From 195cc7a2619613bbb357e9988f99e45ff46df480 Mon Sep 17 00:00:00 2001 From: jack9603301 Date: Fri, 16 Oct 2020 00:34:12 +0800 Subject: [PATCH] tinc-vpn:T766:Initial support for tinc VPN --- data/configd-include.json | 3 +- data/templates/tinc/hosts_config.tmpl | 8 + data/templates/tinc/tinc-down.tmpl | 2 + data/templates/tinc/tinc-up.tmpl | 5 + data/templates/tinc/tinc.conf.tmpl | 60 ++ debian/control | 3 +- interface-definitions/interfaces-tinc.xml.in | 653 ++++++++++++++++++ op-mode-definitions/show-interfaces-tinc.xml | 41 ++ op-mode-definitions/show_tinc.xml | 41 ++ python/vyos/ifconfig/__init__.py | 1 + python/vyos/ifconfig/vtinc.py | 42 ++ smoketest/scripts/cli/test_interfaces_tinc.py | 48 ++ src/conf_mode/interfaces-tinc.py | 225 ++++++ 13 files changed, 1130 insertions(+), 2 deletions(-) create mode 100644 data/templates/tinc/hosts_config.tmpl create mode 100644 data/templates/tinc/tinc-down.tmpl create mode 100644 data/templates/tinc/tinc-up.tmpl create mode 100644 data/templates/tinc/tinc.conf.tmpl create mode 100644 interface-definitions/interfaces-tinc.xml.in create mode 100644 op-mode-definitions/show-interfaces-tinc.xml create mode 100644 op-mode-definitions/show_tinc.xml create mode 100755 python/vyos/ifconfig/vtinc.py create mode 100755 smoketest/scripts/cli/test_interfaces_tinc.py create mode 100755 src/conf_mode/interfaces-tinc.py diff --git a/data/configd-include.json b/data/configd-include.json index 2711a29b82b..0f46e9ddae3 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -26,6 +26,7 @@ "interfaces-wireguard.py", "interfaces-wireless.py", "interfaces-wirelessmodem.py", +"interfaces-tinc.py", "ipsec-settings.py", "lldp.py", "nat.py", @@ -60,4 +61,4 @@ "vrf.py", "vrrp.py", "vyos_cert.py" -] \ No newline at end of file +] diff --git a/data/templates/tinc/hosts_config.tmpl b/data/templates/tinc/hosts_config.tmpl new file mode 100644 index 00000000000..b103300f6e4 --- /dev/null +++ b/data/templates/tinc/hosts_config.tmpl @@ -0,0 +1,8 @@ +{% for prefix in subnets %} +Subnet = {{ prefix }} +{% endfor %} +{% for addr in local_address %} +Address = {{ addr }} +{% endfor %} +Port = {{ port }} + diff --git a/data/templates/tinc/tinc-down.tmpl b/data/templates/tinc/tinc-down.tmpl new file mode 100644 index 00000000000..b2598e6d606 --- /dev/null +++ b/data/templates/tinc/tinc-down.tmpl @@ -0,0 +1,2 @@ +#!/bin/sh +ip link set {{ ifname }} down diff --git a/data/templates/tinc/tinc-up.tmpl b/data/templates/tinc/tinc-up.tmpl new file mode 100644 index 00000000000..3f56c61cc91 --- /dev/null +++ b/data/templates/tinc/tinc-up.tmpl @@ -0,0 +1,5 @@ +#!/bin/sh +{% for addr in address %} +ip addr add dev {{ ifname }} local {{ addr }} +{% endfor %} +ip link set {{ ifname }} up diff --git a/data/templates/tinc/tinc.conf.tmpl b/data/templates/tinc/tinc.conf.tmpl new file mode 100644 index 00000000000..349a08f34f4 --- /dev/null +++ b/data/templates/tinc/tinc.conf.tmpl @@ -0,0 +1,60 @@ +Name = {{ node_name }} +Interface = {{ ifname }} +Mode = {{ device.mode }} +Compression = {{ compression_level }} +Cipher = {{ encryption.cipher }} +Digest = {{ encryption.digset }} +Hostnames = {{ resolve_hostname }} +PrivateKeyFile = {{ private_keyfile }} +Broadcast = {{ broadcast_type }} +DecrementTTL = {{ decrement_ttl }} +DirectOnly = {{ direct_only }} +Forwarding = {{ forwarding_option }} +IffOneQueue = {{ iff_One_Queue }} +KeyExpire = {{ key_expire }} +LocalDiscovery = {{ local_discovery }} +MACExpire = {{ mac_expire}} +MaxTimeout = {{ max_timeout }} +PingInterval = {{ ping_interval }} +PingTimeout = {{ ping_timeout }} +PriorityInheritance = {{ priority_inheritance }} +ProcessPriority = {{ priority }} +ReplayWindow = {{ replay_window }} +StrictSubnets = {{ strict_subnets }} +TunnelServer = {{ tunnel_server }} +ClampMSS = {{ clamp_mss }} +IndirectData = {{ indirect_data }} +MACLength = {{ mac_length }} +PMTU = {{ mtu }} +PMTUDiscovery = {{ PMTU_Discovery }} +TCPonly = {{ TCP_Only }} +DeviceType = {{ device.type }} +{% if udp_rcv_buf %} +UDPRcvBuf = {{ udp_rcv_buf }} +{% endif %} +{% if udp_snd_buf %} +UDPSndBuf = {{ udp_snd_buf }} +{% endif %} +{% if proxy and proxy.type %} +{% if proxy.type == 'socks5' %} +Proxy = {{ proxy.type }} {{ proxy.address }} {{ proxy.port }} {{ proxy.username }} { proxy.password }} +{% elif proxy.type == 'socks4' %} +Proxy = {{ proxy.type }} {{ proxy.address }} {{ proxy.port }}{{ proxy.username }} +{% elif proxy.type == 'http' %} +Proxy = {{ proxy.type }} {{ proxy.address }} {{ proxy.port }} +{% elif proxy.type == 'exec' %} +Proxy = {{ proxy.type }} {{ proxy.exec }} +{% endif %} +{% endif %} +{% if connect %} +ConnectTo = {{ connect }} +{% endif %} +{% if bind_address %} +BindToAddress = {{ bind_address }} +{% endif %} +{% if bind_interface %} +BindToInterface = {{ bind_interface }} +{% endif %} +{% if graph_dump_file %} +GraphDumpFile = {{ graph_dump_file }} +{% endif %} diff --git a/debian/control b/debian/control index ebcfc6c43ca..9e6076eeadb 100644 --- a/debian/control +++ b/debian/control @@ -112,7 +112,8 @@ Depends: wireguard-tools, wireguard-modules, wireless-regdb, - wpasupplicant (>= 0.6.7) + wpasupplicant (>= 0.6.7), + tinc Description: VyOS configuration scripts and data VyOS configuration scripts, interface definitions, and everything diff --git a/interface-definitions/interfaces-tinc.xml.in b/interface-definitions/interfaces-tinc.xml.in new file mode 100644 index 00000000000..e93934345db --- /dev/null +++ b/interface-definitions/interfaces-tinc.xml.in @@ -0,0 +1,653 @@ + + + + + + + Tinc VPN Tunnel Interface + 460 + + ^vtinc[0-9]+$ + + Tinc VPN tunnel interface must be named vtincN + + vtincN + Tinc VPN interface name + + + + + + Network Name options(require) + + + + + Local Node Name options(require) + + + + + Declare network segment + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + + + + + + + + + Bind To Address + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + + + + + + + + + IP address + + ipv4 + IPv4 address + + + ipv6 + IPv6 address + + + host + Host + + + + + + + + + + Port Option + + + + + 655 + + + + Bind To Interface + + + + + + + + Connect To Peer Node Name + + + #include + #include + + + Data Encryption settings + + + + + Standard Data Encryption Algorithm(default:aes-256-cbc) + + aes-256-cbc + + + + UDP Digest settings(default:sha256) + + sha256 + + + + + + Virtual Device settings + + + + + Tinc VPN interface device-type + + dummy raw_socket multicast tun tap + + + dummy + Use a dummy interface. No packets are ever read or written to a virtual network device. Useful for testing, or when setting up a node that only forwards packets for other nodes. + + + raw_socket + Open a raw socket, and bind it to a pre-existing Interface (eth0 by default). All packets are read from this interface. Packets received for the local node are written to the raw socket. However, at least on Linux, the operating system does not process IP packets destined for the local host + + + multicast + Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using Device. Packets are read from and written to this multicast socket. This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address. Do NOT connect multiple tinc daemons to the same multicast address, this will very likely cause routing loops. Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured + + + tun + Set type to tun. Depending on the platform, this can either be with or without an address family header (see below) + + + tap + Set type to tap. Tinc will expect packets read from the virtual network device to start with an Ethernet header(default) + + + (dummy|raw_socket|multicast|tun|tap) + + + tap + + + + Tinc VPN interface device-mode + + router switch hub + + + router + router device(default) + + + switch + switch device + + + hub + hub device + + + (router|switch|hub) + + + router + + + + #include + + + This option selects the way broadcast packets are sent to other daemons. NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form + + no mst direct + + + no + Broadcast packets are never sent to other nodes. + + + mst + Broadcast packets are sent and forwarded via the VPN’s Minimum Spanning Tree. This ensures broadcast packets reach all nodes + + + direct + Broadcast packets are sent directly to all nodes that can be reached directly. Broadcast packets received from other nodes are never forwarded. If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to(default) + + + (no|mst|direct) + + + direct + + + + Decrement TTL Option + + yes no + + + yes + When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets, before forwarding a received packet to the virtual network device or to another node, and will drop packets that have a TTL value of zero, in which case it will send an ICMP Time Exceeded packet back(default) + + + no + Do not enable Decrement TTL Option + + + (yes|no) + + + yes + + + + Only carry out peer-to-peer direct communication, discard data packets that need to be forwarded + + yes no + + + yes + When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets, before forwarding a received packet to the virtual network device or to another node, and will drop packets that have a TTL value of zero, in which case it will send an ICMP Time Exceeded packet back + + + no + Do not enable Decrement TTL Option(default) + + + (yes|no) + + + no + + + + This option selects the way indirect packets are forwarded + + off internal kernel + + + off + Incoming packets that are not meant for the local node, but which should be forwarded to another node, are dropped + + + internal + Incoming packets that are meant for another node are forwarded by tinc internally(default) + + + kernel + Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node. This is less efficient, but allows the kernel to apply its routing and firewall rules on them, and can also help debugging + + + (off|internal|kernel) + + + internal + + + + Dump network graph files, which can be read with graphviz + + + + + This option selects whether IP addresses (both real and on the VPN) should be resolved. Since DNS lookups are blocking, it might affect tinc’s efficiency, even stopping the daemon for a few seconds every time it does a lookup if your DNS server is not responding + + yes no + + + yes + Resolve domain name + + + no + Do not resolve domain names(default) + + + (yes|no) + + + no + + + + Set IFF_ONE_QUEUE flag on TUN/TAP devices. + + yes no + + + yes + Set IFF_ONE_QUEUE flag on TUN/TAP devices + + + no + Do not Set IFF_ONE_QUEUE flag on TUN/TAP devices(default) + + + (yes|no) + + + no + + + + Key expiration time(seconds,default:3600) + + 3600 + + + + Local Discovery Option + + yes no + + + yes + When enabled, tinc will try to detect peers that are on the same local network. This will allow direct communication using LAN addresses, even if both peers are behind a NAT and they only ConnectTo a third node outside the NAT, which normally would prevent the peers from learning each other’s LAN address + + + no + Do not Set Local Discovery Option(default) + + + (yes|no) + + + no + + + + MAC expiration time(seconds,default:600) + + 600 + + + + Max Timeout(seconds,default:900) + + 900 + + + + Ping Interval(seconds,default:60) + + 60 + + + + Ping Timeout(seconds,default:5) + + 5 + + + + Priority Inheritance Option + + yes no + + + yes + When this option is enabled the value of the TOS field of tunneled IPv4 packets will be inherited by the UDP packets that are sent out + + + no + Do not Set Priority Inheritance Option(default) + + + (yes|no) + + + no + + + + Private Key File,This is the full path name of the RSA private key file that was generated by ‘tincd --generate-keys’. It must be a full path, not a relative directory(require) + + + + + The directory where the network interface stores host certificates(require) + + + + + Priority Option + + low normal high + + + low + Low Priority + + + normal + normal Priority(default) + + + high + high Priority + + + (low|normal|high) + + + normal + + + + Proxy settings + + + + + Proxy Type + + socks4 socks5 http exec + + + socks4 + socks4 Proxy + + + socks5 + socks4 Proxy + + + http + http Proxy + + + exec + Executes the given command which should set up the outgoing connection. The environment variables NAME, NODE, REMOTEADDRES and REMOTEPORT are available + + + (socks4|socks5|http|exec) + + + + + + Proxy Type + + + + + + + + Proxy Port + + + + + + + + Proxy Username + + + + + Proxy Password + + + + + Executes the given command which should set up the outgoing connection. The environment variables NAME, NODE, REMOTEADDRES and REMOTEPORT are available + + + + + + + ReplayWindow(Bytes,default:16) + + 16 + + + + Strict Subnets Option + + yes no + + + yes + When this option is enabled tinc will only use Subnet statements which are present in the host config files in the local /etc/tinc/netname/hosts/ directory. Subnets learned via connections to other nodes and which are not present in the local host config files are ignored + + + no + Do not Set Strict Subnets Option(default) + + + (yes|no) + + + no + + + + Tunnel Server Option + + yes no + + + yes + When this option is enabled tinc will no longer forward information between other tinc daemons, and will only allow connections with nodes for which host config files are present in the local /etc/tinc/netname/hosts/ directory, Setting this options also implicitly sets StrictSubnets + + + no + Do not Set Tunnel Server Option(default) + + + (yes|no) + + + no + + + + Sets the socket receive buffer size for the UDP socket, in bytes. If unset, the default buffer size will be used by the operating system(Bytes) + + + + + Sets the socket send buffer size for the UDP socket, in bytes. If unset, the default buffer size will be used by the operating system(Bytes) + + + + + Clamp MSS Option + + yes no + + + yes + This option specifies whether tinc should clamp the maximum segment size (MSS) of TCP packets to the path MTU. This helps in situations where ICMP Fragmentation Needed or Packet too Big messages are dropped by firewalls + + + no + Do not Set Clamp MSS Option(default) + + + (yes|no) + + + no + + + + This option specifies whether other tinc daemons besides the one you specified with ConnectTo can make a direct connection to you + + yes no + + + yes + The tinc daemons other than those specified by ConnectTo can directly establish a connection with you + + + no + Do not Set Indirect Data Option(default) + + + (yes|no) + + + no + + + + PMTU Discovery Option + + yes no + + + yes + When this option is enabled, tinc will try to discover the path MTU to this node. After the path MTU has been discovered, it will be enforced on the VPN(default) + + + no + Do not Set PMTU Discovery Option + + + (yes|no) + + + yes + + + + TCP Only Option + + yes no + + + yes + Only use TCP communication + + + no + Do not Set TCP Only Option(default) + + + (yes|no) + + + no + + + + Compression Level Option(default:9) + + 9 + + + + MAC Length(Bytes,default:4)) + + 4 + + + + MTU(Bytes,default:1514) + + 1514 + + + + + + diff --git a/op-mode-definitions/show-interfaces-tinc.xml b/op-mode-definitions/show-interfaces-tinc.xml new file mode 100644 index 00000000000..1e643f143ef --- /dev/null +++ b/op-mode-definitions/show-interfaces-tinc.xml @@ -0,0 +1,41 @@ + + + + + + + + + Show OpenVPN interface information + + + + + Show detailed OpenVPN interface information + + ${vyos_op_scripts_dir}/show_interfaces.py --intf-type=tinc --action=show + + + + + + Show OpenVPN interface information + + + + + ${vyos_op_scripts_dir}/show_interfaces.py --intf=$4 + + + + Show summary of specified OpenVPN interface information + + ${vyos_op_scripts_dir}/show_interfaces.py --intf="$4" --action=show-brief + + + + + + + + diff --git a/op-mode-definitions/show_tinc.xml b/op-mode-definitions/show_tinc.xml new file mode 100644 index 00000000000..6750239a358 --- /dev/null +++ b/op-mode-definitions/show_tinc.xml @@ -0,0 +1,41 @@ + + + + + + + + + Show OpenVPN interface information + + + + + Show detailed OpenVPN interface information + + ${vyos_op_scripts_dir}/show_interfaces.py --intf-type=vtinc --action=show + + + + + + Show OpenVPN interface information + + + + + ${vyos_op_scripts_dir}/show_interfaces.py --intf=$4 + + + + Show summary of specified OpenVPN interface information + + ${vyos_op_scripts_dir}/show_interfaces.py --intf="$4" --action=show-brief + + + + + + + + diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index 9cd8d44c16d..518f36aa563 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -29,6 +29,7 @@ from vyos.ifconfig.vxlan import VXLANIf from vyos.ifconfig.wireguard import WireGuardIf from vyos.ifconfig.vtun import VTunIf +from vyos.ifconfig.vtinc import VTincIf from vyos.ifconfig.vti import VTIIf from vyos.ifconfig.pppoe import PPPoEIf from vyos.ifconfig.tunnel import GREIf diff --git a/python/vyos/ifconfig/vtinc.py b/python/vyos/ifconfig/vtinc.py new file mode 100755 index 00000000000..4570882a41b --- /dev/null +++ b/python/vyos/ifconfig/vtinc.py @@ -0,0 +1,42 @@ +# Copyright 2020 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +from vyos.ifconfig.interface import Interface + +@Interface.register +class VTincIf(Interface): + default = { + 'type': 'vinc', + } + definition = { + **Interface.definition, + **{ + 'section': 'tinc', + 'prefixes': ['vtinc', ], + 'bridgeable': True, + }, + } + + # stub this interface is created in the configure script + + def _create(self): + # we can not create this interface as it is managed outside + # it requires configuring OpenVPN + pass + + def _delete(self): + # we can not create this interface as it is managed outside + # it requires configuring OpenVPN + pass diff --git a/smoketest/scripts/cli/test_interfaces_tinc.py b/smoketest/scripts/cli/test_interfaces_tinc.py new file mode 100755 index 00000000000..376dba36776 --- /dev/null +++ b/smoketest/scripts/cli/test_interfaces_tinc.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import unittest + +from base_interfaces_test import BasicInterfaceTest +from vyos.ifconfig import Section + +base_path = ['interfaces','tinc'] + +class TaskNdpProxy(unittest.TestCase): + def setUp(self): + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + self.session = ConfigSession(os.getpid()) + self.session.delete(base_path) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + def test_ndp_proxy(self): + self.session.set(base_path + ['network'],'test') + self.session.set(base_path + ['node-name'],'test1') + self.session.set(base_path + ['hosts-dir'],'/tmp/test/hosts') + self.session.set(base_path + ['private-keyfile'],'/tmp/test/test.key') + self.session.set(base_path + ['address'],'192.168.20.1/24') + self.session.set(base_path + ['subnets'],'192.168.20.0/24') + # check validate() - outbound-interface must be defined + with self.assertRaises(ConfigSessionError): + self.session.commit() + self.assertEqual(True) + +if __name__ == '__main__': + unittest.main() diff --git a/src/conf_mode/interfaces-tinc.py b/src/conf_mode/interfaces-tinc.py new file mode 100755 index 00000000000..c77cfedb712 --- /dev/null +++ b/src/conf_mode/interfaces-tinc.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os, sys + +from sys import exit +from copy import deepcopy + +from netifaces import interfaces +from vyos.configdict import get_interface_dict,leaf_node_changed +from vyos.config import Config +from netifaces import interfaces +from time import sleep +from vyos.ifconfig import VTincIf +from vyos import ConfigError +from vyos.util import call +from vyos.xml import defaults +from vyos.configdict import dict_merge +from vyos.template import render +from netaddr import * + +from vyos import airbag + +airbag.enable() + +def find_network(ifname,network,copy_node): + conf = Config() + + base = ['interfaces', 'tinc'] + + if not conf.exists(base): + return False + else: + conf.set_level(base) + + tincs = conf.get_config_dict([], key_mangling=('-', '_'), get_first_key=True) + + findCurrentNode = False + findOtherNode = False + + for vtinc in tincs: + if vtinc == ifname: + if findOtherNode: + return True + else: + findCurrentNode = True + continue + if findCurrentNode: + if 'network' in tincs[vtinc]: + if tincs[vtinc]['network'] == network: + copy_node=vtinc + return True + else: + if 'network' in tincs[vtinc]: + if tincs[vtinc]['network'] == network: + copy_node=vtinc + findOtherNode = True + continue + + return False + + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + + base = ['interfaces', 'tinc'] + + tinc = get_interface_dict(conf, base) + + return tinc + +def verify(tinc): + #bail out early - looks like removal from running config + if tinc is None: + return None + if 'deleted' in tinc: + return None + if 'address' not in tinc: + raise ConfigError('address must be set') + if 'private_keyfile' not in tinc: + raise ConfigError('private-keyfile must be set') + if 'hosts_dir' not in tinc: + raise ConfigError('private-keyfile must be set') + if 'network' not in tinc: + raise ConfigError('network must be set') + if 'node_name' not in tinc: + raise ConfigError('node_name must be set') + if 'connect' in tinc: + node_name=tinc['node_name'] + connect_peer_node_name=tinc['connect'] + if node_name == connect_peer_node_name: + raise ConfigError('The local node name("{local_node}") and the remote target connection node name("{remote_node}") cannot match'.format(local_node=node_name,remote_node=connect_peer_node_name)) + + if 'proxy' in tinc: + if 'address' not in tinc['proxy']: + raise ConfigError('proxy.address must be set') + if 'port' not in tinc['proxy']: + raise ConfigError('proxy.port must be set') + if 'type' not in tinc['proxy']: + raise ConfigError('proxy.type must be set') + if tinc['proxy']['type'] == 'socks5': + if 'password' not in tinc['proxy']: + raise ConfigError('proxy.password must be set') + if tinc['proxy']['type'] == 'socks4' or tinc['proxy']['type'] == 'socks5': + if 'username' not in tinc['proxy']: + raise ConfigError('proxy.username must be set') + if tinc['proxy']['type'] == 'exec': + if 'exec' not in tinc: + raise ConfigError('proxy.exec must be set') + + copy_node = None + + other = find_network(tinc['ifname'],tinc['network'],copy_node) + + if other: + raise ConfigError('Two tinc interfaces are not allowed to use the same network name,The network name {network} of the {one} and {two} interfaces is the same'.format(network=tinc['network'],one=tinc['ifname'],two=copy_node)) + + return None + +def generate(tinc): + if tinc is None: + return None + if 'deleted' in tinc: + return None + interface = tinc['ifname'] + network = tinc['network'] + node_name=tinc['node_name'] + private_keyfile = tinc['private_keyfile'] + public_keyfile = f'/tmp/tinc_{network}_{node_name}.key' + config_root_dir='/config/tinc' + config_network_dir=f'/config/tinc/{interface}' + config_hosts_dir=tinc['hosts_dir'] + system_hosts_dir=f'/etc/tinc/{network}/hosts' + tinc_root_dir=f'/etc/tinc' + tinc_network_dir=f'/etc/tinc/{network}' + tinc_main_config=f'{tinc_network_dir}/tinc.conf' + tinc_up=f'{tinc_network_dir}/tinc-up' + tinc_down=f'{tinc_network_dir}/tinc-down' + tinc_host_local_peer_config=f'{config_hosts_dir}/{node_name}' + if tinc: + if not os.path.exists(tinc_network_dir): + os.makedirs(tinc_network_dir, 0o644 ) + if not os.path.exists(system_hosts_dir): + if os.path.exists(config_hosts_dir): + os.symlink(config_hosts_dir,system_hosts_dir) + else: + os.makedirs(config_hosts_dir, 0o644 ) + os.symlink(config_hosts_dir,system_hosts_dir) + elif not os.path.islink(system_hosts_dir): + os.remove(system_hosts_dir) + os.makedirs(config_hosts_dir,0o644) + os.symlink(config_hosts_dir,system_hosts_dir) + os.chdir(tinc_network_dir) + call(f'openssl genrsa -out {private_keyfile} 4096') + call(f'openssl rsa -in {private_keyfile} -pubout -out {public_keyfile}') + render(tinc_main_config, 'tinc/tinc.conf.tmpl', tinc) + render(tinc_up, 'tinc/tinc-up.tmpl', tinc) + render(tinc_down, 'tinc/tinc-down.tmpl', tinc) + print(tinc) + render(tinc_host_local_peer_config, 'tinc/hosts_config.tmpl', tinc) + call(f'cat {public_keyfile} >> {tinc_host_local_peer_config} ') + call(f'chmod a+x {tinc_up}') + call(f'chmod a+x {tinc_down}') + + return None + +def apply(tinc): + if tinc is None: + return None + interface = tinc['ifname'] + if 'deleted' in tinc: + conf = Config() + base = ['interfaces', 'tinc',tinc['ifname'],'network'] + diff = leaf_node_changed(conf,base) + network = diff[0] + call(f'systemctl stop tinc@{network}') + else: + network = tinc['network'] + call(f'systemctl restart tinc@{network}') + cnt = 0 + + while interface not in interfaces(): + # If VPN tunnel can't be established because the peer isn't + # (temporarily) available, the vtun interface never becomes registered + # with the kernel, and the commit would hang if there is no bail out + # condition + cnt += 1 + if cnt == 50: + break + + # sleep 250ms + sleep(0.250) + try: + o = VTunIf(interface) + #update interface description used e.g. within SNMP + o.set_alias(tinc['description']) + except: + pass + + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1)