Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119064406
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/debian/changelog b/debian/changelog
index e8519e87a..a7c428cda 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,52 +1,58 @@
+vyos-1x (1.2.0-2) unstable; urgency=medium
+
+ * T773: adding wireguard support
+
+ -- hagbard <vyosdev@derith.de> Sat, 11 Aug 2018 15:51:34 -0700
+
vyos-1x (1.2.0-1) unstable; urgency=medium
* T666, T616: new implementation of the VRRP CLI.
-- Daniil Baturin <daniil@baturin.org> Fri, 27 Jul 2018 10:25:52 +0200
vyos-1x (1.0.6) unstable; urgency=medium
* T736: Rewrite remote logging (syslog) to XML/Python
-- hagbard <vyosdev@derith.de> Tue, 24 Jul 2018 10:59:25 -0700
vyos-1x (1.0.5) unstable; urgency=medium
* T606: Error in DNS Forwarder listen-on
* T608: Cannot configure broadcast-relay service
-- Christian Poessinger <christian@poessinger.com> Thu, 19 Apr 2018 21:16:28 +0200
vyos-1x (1.0.4) unstable; urgency=medium
* T560: dns-forwarding: replace dnsmasq with pdns-recursor
* T588: Rewrite 'service dns forwarding' in new XML style format
-- Christian Poessinger <christian@poessinger.com> Sun, 15 Apr 2018 16:13:32 +0200
vyos-1x (1.0.3) unstable; urgency=medium
* T379: Add UDP broadcast relay support
* mdns repeater scripts - remove python subprocess
* Support setting optional 'type' node in command templates
-- Christian Poessinger <christian@poessinger.com> Sat, 06 Jan 2018 13:18:30 +0100
vyos-1x (1.0.2) unstable; urgency=low
* Added mdns-repeater configuration nodes
-- Christian Poessinger <christian@poessinger.com> Sat, 09 Dec 2017 10:39:35 +0100
vyos-1x (1.0.1) unstable; urgency=low
* Added the Python library for reading VyOS configs
-- Daniil Baturin <daniil@baturin.org> Thu, 17 Aug 2017 22:22:17 -0400
vyos-1x (1.0.0) unstable; urgency=low
* Created the package
-- Daniil Baturin <daniil@baturin.org> Thu, 17 Aug 2017 20:17:04 -0400
diff --git a/debian/control b/debian/control
index c87e7452c..ce9d925d3 100644
--- a/debian/control
+++ b/debian/control
@@ -1,42 +1,43 @@
Source: vyos-1x
Section: contrib/net
Priority: extra
Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
Build-Depends: debhelper (>= 9),
quilt,
python3,
python3-setuptools,
quilt,
python3-lxml,
python3-nose,
python3-coverage
Standards-Version: 3.9.6
Package: vyos-1x
Architecture: all
Depends: python3,
${python3:Depends},
python3-netifaces,
python3-jinja2,
python3-pystache,
python3-psutil,
python3-tabulate,
ipaddrcheck,
tcpdump,
bmon,
hvinfo,
file,
lsscsi,
pciutils,
usbutils,
snmp, snmpd,
openssh-server,
ntp,
iputils-arping,
libvyosconfig0,
beep,
keepalived (>=2.0.5),
+ wireguard,
${shlibs:Depends},
${misc:Depends}
Description: VyOS configuration scripts and data
VyOS configuration scripts, interface definitions, and everything
diff --git a/interface-definitions/wireguard.xml b/interface-definitions/wireguard.xml
new file mode 100644
index 000000000..008f82a0b
--- /dev/null
+++ b/interface-definitions/wireguard.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="interfaces">
+ <children>
+ <tagNode name="wireguard" owner="${vyos_conf_scripts_dir}/wireguard.py">
+ <properties>
+ <help>WireGuard interface name</help>
+ <priority>459</priority> <!-- subsequent ones may be removed, just make sure ethernet ifs are present -->
+ <constraint>
+ <regex>^wg[0-9]{1,4}</regex>
+ </constraint>
+ <constraintErrorMessage>illegal interface name</constraintErrorMessage>
+ <valueHelp>
+ <format>wgN</format>
+ <description>WireGuard interface name</description>
+ </valueHelp>
+ </properties>
+ <children>
+ <leafNode name="address">
+ <properties>
+ <help>IP address</help>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <multi/>
+ <constraint>
+ <validator name="interface-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="description">
+ <properties>
+ <help>description</help>
+ <constraint>
+ <regex>.[^ ]{1,100}$</regex>
+ </constraint>
+ <constraintErrorMessage>interface description is too long (limit 100 characters)</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="listen-port">
+ <properties>
+ <help>Local port number to accept connections</help>
+ </properties>
+ </leafNode>
+ <tagNode name="peer">
+ <properties>
+ <help>Base64 encoded public key</help>
+ <constraint>
+ <regex>^[0-9a-zA-Z\+/]{43}=$</regex>
+ </constraint>
+ <constraintErrorMessage>Key is not valid 44-character (32-bytes) base64</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="allowed-ips">
+ <properties>
+ <help>IP addresses allowed to traverse the peer</help>
+ <multi/>
+ </properties>
+ </leafNode>
+ <!-- check format IP:port -->
+ <leafNode name="endpoint">
+ <properties>
+ <help>Remote endpoint</help>
+ </properties>
+ </leafNode>
+
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/wireguard-keys.xml b/op-mode-definitions/wireguard-keys.xml
new file mode 100644
index 000000000..29fce33b6
--- /dev/null
+++ b/op-mode-definitions/wireguard-keys.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!-- wireguard key management -->
+<interfaceDefinition>
+ <node name="generate">
+ <children>
+ <node name="wireguard">
+ <properties>
+ <help>wireguard key generation utility</help>
+ </properties>
+ <children>
+ <leafNode name="keypair">
+ <properties>
+ <help>generate a wireguard keypair</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/wireguard_key.py --genkey</command>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="show">
+ <children>
+ <node name="wireguard">
+ <children>
+ <leafNode name="pubkey">
+ <properties>
+ <help>show wireguard public key</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/wireguard_key.py --showpub</command>
+ </leafNode>
+ <leafNode name="privkey">
+ <properties>
+ <help>show wireguard private key</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/wireguard_key.py --showpriv</command>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
+
diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py
new file mode 100755
index 000000000..7d52cfe94
--- /dev/null
+++ b/src/conf_mode/wireguard.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+#
+#
+
+import sys
+import os
+import re
+import syslog as sl
+import subprocess
+
+from vyos.config import Config
+from vyos import ConfigError
+
+dir = r'/config/auth/wireguard'
+pk = dir + '/private.key'
+pub = dir + '/public.key'
+
+### check_kmod may be removed in the future,
+### just want to have everything smoothly running after reboot
+def check_kmod():
+ if not os.path.exists('/sys/module/wireguard'):
+ sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
+ if os.system('sudo modprobe wireguard') != 0:
+ sl.syslog(sl.LOG_NOTICE, "modprobe wireguard failed")
+ raise ConfigError("modprobe wireguard failed")
+
+def get_config():
+ config_data = {
+ 'interfaces' : {}
+ }
+
+ c = Config()
+ if not c.exists('interfaces wireguard'):
+ return None
+
+ c.set_level('interfaces')
+ intfcs = c.list_nodes('wireguard')
+ intfcs_eff = c.list_effective_nodes('wireguard')
+ new_lst = list( set(intfcs) - set(intfcs_eff) )
+ del_lst = list( set(intfcs_eff) - set(intfcs) )
+
+ ### setting deafult and determine status of the config
+ for intfc in intfcs:
+ cnf = 'wireguard ' + intfc
+ # default data struct
+ config_data['interfaces'].update (
+ {
+ intfc : {
+ 'addr' : '',
+ 'descr' : intfc, ## snmp ifAlias
+ 'lport' : '',
+ 'status' : 'exists',
+ 'state' : 'enabled',
+ 'mtu' : 1420,
+ 'peer' : {}
+ }
+ }
+ )
+
+ for i in new_lst:
+ config_data['interfaces'][i]['status'] = 'create'
+
+ for i in del_lst:
+ config_data['interfaces'].update (
+ {
+ i : {
+ 'status': 'delete'
+ }
+ }
+ )
+
+ ### based on the status, set real values
+ for intfc in intfcs:
+ cnf = 'wireguard ' + intfc
+ if config_data['interfaces'][intfc]['status'] != 'delete':
+ #### addresses
+ if c.exists(cnf + ' address'):
+ config_data['interfaces'][intfc]['addr'] = c.return_values(cnf + ' address')
+ ### listen port
+ if c.exists(cnf + ' listen-port'):
+ config_data['interfaces'][intfc]['lport'] = c.return_value(cnf + ' listen-port')
+ ### description
+ if c.exists(cnf + ' description'):
+ config_data['interfaces'][intfc]['descr'] = c.return_value(cnf + ' description')
+ ### mtu
+ if c.exists(cnf + ' mtu'):
+ config_data['interfaces'][intfc]['mtu'] = c.return_value(cnf + ' mtu')
+
+ ### peers
+ if c.exists(cnf + ' peer'):
+ for p in c.list_nodes(cnf + ' peer'):
+ config_data['interfaces'][intfc]['peer'].update (
+ {
+ p : {
+ 'allowed-ips' : [],
+ 'endpoint' : ''
+ }
+ }
+ )
+ if c.exists(cnf + ' peer ' + p + ' allowed-ips'):
+ config_data['interfaces'][intfc]['peer'][p]['allowed-ips'] = c.return_values(cnf + ' peer ' + p + ' allowed-ips')
+ if c.exists(cnf + ' peer ' + p + ' endpoint'):
+ config_data['interfaces'][intfc]['peer'][p]['endpoint'] = c.return_value(cnf + ' peer ' + p + ' endpoint')
+
+ #print (config_data)
+ return config_data
+
+def verify(c):
+ if not c:
+ return None
+
+ for i in c['interfaces']:
+ if c['interfaces'][i]['status'] != 'delete':
+ if not c['interfaces'][i]['addr']:
+ raise ConfigError("address required for interface " + i)
+ if not c['interfaces'][i]['lport']:
+ raise ConfigError("listen-port required for interface " + i)
+ if not c['interfaces'][i]['peer']:
+ raise ConfigError("peer required on interface " + i)
+ else:
+ for p in c['interfaces'][i]['peer']:
+ if not c['interfaces'][i]['peer'][p]['allowed-ips']:
+ raise ConfigError("allowed-ips required on interface " + i + " for peer " + p)
+ if not c['interfaces'][i]['peer'][p]['endpoint']:
+ raise ConfigError("endpoint required on interface " + i + " for peer " + p)
+
+ ### eventually check allowed-ips (if it's an ip and valid CIDR or so)
+ ### endpoint needs to be IP:port
+
+def apply(c):
+ ### no wg config left, delete all wireguard devices on the os
+ if not c:
+ net_devs = os.listdir('/sys/class/net/')
+ for dev in net_devs:
+ buf = open('/sys/class/net/' + dev + '/uevent','r').read()
+ if re.search("DEVTYPE=wireguard", buf, re.I|re.M):
+ wg_intf = re.sub("INTERFACE=","", re.search("INTERFACE=.*", buf, re.I|re.M).group(0) )
+ sl.syslog(sl.LOG_NOTICE, "removing interface " + wg_intf)
+ subprocess.call(['ip l d dev ' + wg_intf + ' >/dev/null'], shell=True)
+ return None
+
+ ###
+ ## to find the diffs between old config an new config
+ ## so we only configure/delete what was not previously configured
+ ###
+ c_eff = Config()
+ c_eff.set_level('interfaces wireguard')
+
+ ### deletion of specific interface
+ for intf in c['interfaces']:
+ if c['interfaces'][intf]['status'] == 'delete':
+ sl.syslog(sl.LOG_NOTICE, "removing interface " + intf)
+ subprocess.call(['ip l d dev ' + intf + ' &>/dev/null'], shell=True)
+
+ ### new config
+ if c['interfaces'][intf]['status'] == 'create':
+ if not os.path.exists(pk):
+ raise ConfigError("No keys found, generate them by executing: \'run generate wireguard keypair\'")
+
+ subprocess.call(['ip l a dev ' + intf + ' type wireguard 2>/dev/null'], shell=True)
+ for addr in c['interfaces'][intf]['addr']:
+ add_addr(intf, addr)
+ configure_interface(c,intf)
+ subprocess.call(['ip l set up dev ' + intf + ' &>/dev/null'], shell=True)
+
+ ### config updates
+ if c['interfaces'][intf]['status'] == 'exists':
+ ### IP address change
+ addr_eff = re.sub("\'", "", c_eff.return_effective_values(intf + ' address')).split()
+ addr_rem = list( set(addr_eff) - set(c['interfaces'][intf]['addr']) )
+ addr_add = list( set(c['interfaces'][intf]['addr']) - set(addr_eff) )
+
+ if len(addr_rem) !=0:
+ for addr in addr_rem:
+ del_addr(intf, addr)
+
+ if len(addr_add) !=0:
+ for addr in addr_add:
+ add_addr(intf, addr)
+
+ configure_interface(c,intf)
+
+ ### ifalias for snmp from description
+ descr_eff = c_eff.return_effective_value(intf + ' description')
+ cnf_descr = c['interfaces'][intf]['descr']
+ if descr_eff != cnf_descr:
+ open('/sys/class/net/' + str(intf) + '/ifalias','w').write(str(cnf_descr))
+
+def configure_interface(c, intf):
+ for p in c['interfaces'][intf]['peer']:
+ cmd = "wg set " + intf + \
+ " listen-port " + c['interfaces'][intf]['lport'] + \
+ " private-key " + pk + \
+ " peer " + p + \
+ " endpoint " + c['interfaces'][intf]['peer'][p]['endpoint']
+ cmd += " allowed-ips "
+ for ap in c['interfaces'][intf]['peer'][p]['allowed-ips']:
+ if ap != c['interfaces'][intf]['peer'][p]['allowed-ips'][-1]:
+ cmd += ap + ","
+ else:
+ cmd += ap
+ sl.syslog(sl.LOG_NOTICE, "sudo " + cmd)
+ subprocess.call([ 'sudo ' + cmd], shell=True)
+
+def add_addr(intf, addr):
+ ret = subprocess.call(['ip a a dev ' + intf + ' ' + addr + ' &>/dev/null'], shell=True)
+ if ret != 0:
+ raise ConfigError('Can\'t set IP ' + addr + ' on ' + intf )
+ else:
+ sl.syslog(sl.LOG_NOTICE, "ip a a dev " + intf + " " + addr)
+
+def del_addr(intf, addr):
+ ret = subprocess.call(['ip a d dev ' + intf + ' ' + addr + ' &>/dev/null'], shell=True)
+ if ret != 0:
+ raise ConfigError('Can\'t delete IP ' + addr + ' on ' + intf )
+ else:
+ sl.syslog(sl.LOG_NOTICE, "ip a d dev " + intf + " " + addr)
+
+if __name__ == '__main__':
+ try:
+ check_kmod()
+ c = get_config()
+ verify(c)
+ #generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ sys.exit(1)
+
diff --git a/src/op_mode/wireguard_key.py b/src/op_mode/wireguard_key.py
new file mode 100755
index 000000000..811cff1ca
--- /dev/null
+++ b/src/op_mode/wireguard_key.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
+#
+#
+
+import argparse
+import os
+import sys
+import syslog as sl
+import subprocess
+
+from vyos import ConfigError
+
+dir = r'/config/auth/wireguard'
+pk = dir + '/private.key'
+pub = dir + '/public.key'
+
+### check_kmod may be removed in the future,
+### once it's loaded automatically
+def check_kmod():
+ if not os.path.exists('/sys/module/wireguard'):
+ sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
+ if os.system('sudo modprobe wireguard') != 0:
+ sl.syslog(sl.LOG_ERR, "modprobe wireguard failed")
+ raise ConfigError("modprobe wireguard failed")
+
+def generate_keypair():
+ ret = subprocess.call(['wg genkey | tee ' + pk + '|wg pubkey > ' + pub], shell=True)
+ if ret != 0:
+ raise ConfigError("wireguard key-pair generation failed")
+ else:
+ sl.syslog(sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir)
+
+def genkey():
+ ### if umask 077 makes trouble, 027 will work
+ old_umask = os.umask(0o077)
+ if os.path.exists(pk) and os.path.exists(pub):
+ choice = input("You have a wireguard key-pair already, do you want to re-generate? [y/n] ")
+ if choice == 'y' or choice == 'Y':
+ generate_keypair()
+ else:
+ os.mkdir(dir)
+ generate_keypair()
+ os.umask(old_umask)
+
+def showkey(key):
+ if key == "pub":
+ if os.path.exists(pub):
+ print ( open(pub).read().strip() )
+ else:
+ print("no public key found")
+
+ if key == "pk":
+ if os.path.exists(pk):
+ print ( open(pk).read().strip() )
+ else:
+ print("no private key found")
+
+if __name__ == '__main__':
+ check_kmod()
+
+ parser = argparse.ArgumentParser(description='wireguard key management')
+ parser.add_argument('--genkey', action="store_true", help='generate key-pair')
+ parser.add_argument('--showpub', action="store_true", help='shows public key')
+ parser.add_argument('--showpriv', action="store_true", help='shows private key')
+ args = parser.parse_args()
+
+ try:
+ if args.genkey:
+ genkey()
+ if args.showpub:
+ showkey("pub")
+ if args.showpriv:
+ showkey("pk")
+
+ except ConfigError as e:
+ print(e)
+ sys.exit(1)
+
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:59 AM (35 m, 33 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4654116
Default Alt Text
(18 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment