summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile6
-rw-r--r--data/interface-types.json1
-rw-r--r--debian/changelog6
-rw-r--r--debian/control2
-rw-r--r--interface-definitions/ssh.xml22
-rw-r--r--interface-definitions/wireguard.xml87
-rw-r--r--op-mode-definitions/date.xml64
-rw-r--r--op-mode-definitions/dns-forwarding.xml3
-rw-r--r--op-mode-definitions/dynamic-dns.xml25
-rw-r--r--op-mode-definitions/show-date.xml30
-rw-r--r--op-mode-definitions/show-ntp.xml22
-rw-r--r--op-mode-definitions/wireguard.xml42
-rwxr-xr-xsrc/completion/list_ntp_servers.sh4
-rwxr-xr-xsrc/conf_mode/wireguard.py273
-rwxr-xr-xsrc/op_mode/dynamic_dns.py (renamed from src/op_mode/dynamic_dns_status.py)29
-rwxr-xr-xsrc/op_mode/wireguard_key.py92
17 files changed, 668 insertions, 43 deletions
diff --git a/.gitignore b/.gitignore
index 5d0af4bae..af15969c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,12 +21,15 @@ parts/
sdist/
var/
wheels/
+Pipfile
+Pipfile.lock
*.egg-info/
.installed.cfg
*.egg
.idea/
.idea
.idea/*
+*.iml
# PyInstaller
# Usually these files are written by a python script from a template
diff --git a/Makefile b/Makefile
index addb83a5f..70101181d 100644
--- a/Makefile
+++ b/Makefile
@@ -9,9 +9,10 @@ interface_definitions:
find $(CURDIR)/interface-definitions/ -type f -name "*.xml" | xargs -I {} $(CURDIR)/scripts/build-command-templates {} $(CURDIR)/schema/interface_definition.rng $(TMPL_DIR) || exit 1
# XXX: delete top level node.def's that now live in other packages
+ rm -f $(TMPL_DIR)/interfaces/node.def
+ rm -f $(TMPL_DIR)/protocols/node.def
rm -f $(TMPL_DIR)/system/node.def
rm -f $(TMPL_DIR)/system/options/node.def
- rm -f $(TMPL_DIR)/protocols/node.def
rm -f $(TMPL_DIR)/vpn/node.def
rm -f $(TMPL_DIR)/vpn/ipsec/node.def
@@ -23,11 +24,12 @@ op_mode_definitions:
find $(CURDIR)/op-mode-definitions/ -type f -name "*.xml" | xargs -I {} $(CURDIR)/scripts/build-command-op-templates {} $(CURDIR)/schema/op-mode-definition.rng $(OP_TMPL_DIR) || exit 1
# XXX: delete top level op mode node.def's that now live in other packages
+ rm -f $(OP_TMPL_DIR)/set/node.def
rm -f $(OP_TMPL_DIR)/show/node.def
- rm -f $(OP_TMPL_DIR)/show/dns/node.def
rm -f $(OP_TMPL_DIR)/reset/node.def
rm -f $(OP_TMPL_DIR)/restart/node.def
rm -f $(OP_TMPL_DIR)/monitor/node.def
+ rm -f $(OP_TMPL_DIR)/generate/node.def
.PHONY: all
all: clean interface_definitions op_mode_definitions
diff --git a/data/interface-types.json b/data/interface-types.json
index c452122af..f5820f403 100644
--- a/data/interface-types.json
+++ b/data/interface-types.json
@@ -10,6 +10,7 @@
"vti": "vti",
"l2tpv3": "l2tpeth",
"vxlan": "vxlan",
+ "wireguard": "wg",
"wireless": "wireless",
"wirelessmodem": "wlm",
"input": "ifb",
diff --git a/debian/changelog b/debian/changelog
index e8519e87a..a7c428cda 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+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.
diff --git a/debian/control b/debian/control
index c87e7452c..70bf7a61c 100644
--- a/debian/control
+++ b/debian/control
@@ -32,10 +32,12 @@ Depends: python3,
snmp, snmpd,
openssh-server,
ntp,
+ ntpdate,
iputils-arping,
libvyosconfig0,
beep,
keepalived (>=2.0.5),
+ wireguard,
${shlibs:Depends},
${misc:Depends}
Description: VyOS configuration scripts and data
diff --git a/interface-definitions/ssh.xml b/interface-definitions/ssh.xml
index e8786d202..35fe79214 100644
--- a/interface-definitions/ssh.xml
+++ b/interface-definitions/ssh.xml
@@ -1,7 +1,5 @@
<?xml version="1.0"?>
-
<!--SSH configuration -->
-
<interfaceDefinition>
<node name="service">
<children>
@@ -13,18 +11,23 @@
<children>
<node name="access-control">
<properties>
- <help>SSH user/group access controls. Directives are processed in this order: deny-users, allow-users, deny-groups and allow-groups</help>
+ <help>SSH user/group access controls. Directives are processed
+ in the following order: deny-users, allow-users, deny-groups and
+ allow-groups.</help>
</properties>
<children>
<node name="allow">
+ <properties>
+ <help>Allow user/group SSH access</help>
+ </properties>
<children>
<leafNode name="group">
<properties>
<help>Allow members of a group to login</help>
- <constraint>
- <regex>^[a-z_][a-z0-9_-]{1,31}[$]?</regex>
- </constraint>
- <constraintErrorMessage>illegal characters or more than 32 characters</constraintErrorMessage>
+ <constraint>
+ <regex>^[a-z_][a-z0-9_-]{1,31}[$]?</regex>
+ </constraint>
+ <constraintErrorMessage>illegal characters or more than 32 characters</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
@@ -41,6 +44,9 @@
</children>
</node>
<node name="deny">
+ <properties>
+ <help>Deny user/group SSH access</help>
+ </properties>
<children>
<leafNode name="group">
<properties>
@@ -147,7 +153,7 @@
</leafNode>
<leafNode name="mac">
<properties>
- <help>Allowed message authentication code (MAC) algorithms</help>
+ <help>Allowed message authentication code (MAC) algorithms</help>
<completionHelp>
<script>ssh -Q mac | tr '\n' ' '</script>
</completionHelp>
diff --git a/interface-definitions/wireguard.xml b/interface-definitions/wireguard.xml
new file mode 100644
index 000000000..1437e9f0c
--- /dev/null
+++ b/interface-definitions/wireguard.xml
@@ -0,0 +1,87 @@
+<?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>
+ <leafNode name="persistent-keepalive">
+ <properties>
+ <help>how often send keep alives in seconds</help>
+ <constraint>
+ <regex>^(1|[1-9][0-9]{1,5})$</regex>
+ </constraint>
+ <constraintErrorMessage>keepliave timer has to be between 1 and 99999 seconds</constraintErrorMessage>
+ </properties>
+ </leafNode>
+
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/date.xml b/op-mode-definitions/date.xml
new file mode 100644
index 000000000..15a69dbd9
--- /dev/null
+++ b/op-mode-definitions/date.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="show">
+ <children>
+ <node name="date">
+ <properties>
+ <help>Show system time and date</help>
+ </properties>
+ <command>/bin/date</command>
+ <children>
+ <node name="utc">
+ <properties>
+ <help>Show system date and time as Coordinated Universal Time</help>
+ </properties>
+ <command>/bin/date -u</command>
+ <children>
+ <leafNode name="maya">
+ <properties>
+ <help>Show UTC date in Maya calendar format</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/maya_date.py $(date +%s)</command>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="set">
+ <children>
+ <tagNode name="date">
+ <properties>
+ <help>Set system date and time</help>
+ <completionHelp>
+ <list>&lt;MMDDhhmm&gt; &lt;MMDDhhmmYY&gt; &lt;MMDDhhmmCCYY&gt; &lt;MMDDhhmmCCYY.ss&gt;</list>
+ </completionHelp>
+ </properties>
+ <command>/bin/date "$3"</command>
+ </tagNode>
+ <node name="date">
+ <properties>
+ <help>Set system date and time</help>
+ </properties>
+ <children>
+ <node name="ntp">
+ <properties>
+ <help>Set system date and time from NTP server (default: 0.pool.ntp.org)</help>
+ </properties>
+ <command>/usr/sbin/ntpdate -u 0.pool.ntp.org</command>
+ </node>
+ <tagNode name="ntp">
+ <properties>
+ <help>Set system date and time from NTP server</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_ntp_servers.sh</script>
+ </completionHelp>
+ </properties>
+ <command>/usr/sbin/ntpdate -u "$4"</command>
+ </tagNode>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/dns-forwarding.xml b/op-mode-definitions/dns-forwarding.xml
index e789f4aee..be71302cd 100644
--- a/op-mode-definitions/dns-forwarding.xml
+++ b/op-mode-definitions/dns-forwarding.xml
@@ -4,6 +4,9 @@
<node name="show">
<children>
<node name="dns">
+ <properties>
+ <help>Show DNS information</help>
+ </properties>
<children>
<node name="forwarding">
<properties>
diff --git a/op-mode-definitions/dynamic-dns.xml b/op-mode-definitions/dynamic-dns.xml
index c67769a83..76c473fd7 100644
--- a/op-mode-definitions/dynamic-dns.xml
+++ b/op-mode-definitions/dynamic-dns.xml
@@ -4,6 +4,9 @@
<node name="show">
<children>
<node name="dns">
+ <properties>
+ <help>Show DNS information</help>
+ </properties>
<children>
<node name="dynamic">
<properties>
@@ -14,7 +17,7 @@
<properties>
<help>Show Dynamic DNS status</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/dynamic_dns_status.py</command>
+ <command>sudo ${vyos_op_scripts_dir}/dynamic_dns.py --status</command>
</leafNode>
</children>
</node>
@@ -22,4 +25,24 @@
</node>
</children>
</node>
+ <node name="update">
+ <properties>
+ <help>Update data for a service</help>
+ </properties>
+ <children>
+ <node name="dns">
+ <properties>
+ <help>Update DNS information</help>
+ </properties>
+ <children>
+ <node name="dynamic">
+ <properties>
+ <help>Update Dynamic DNS information</help>
+ </properties>
+ <command>sudo ${vyos_op_scripts_dir}/dynamic_dns.py --update</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
</interfaceDefinition>
diff --git a/op-mode-definitions/show-date.xml b/op-mode-definitions/show-date.xml
deleted file mode 100644
index 705172b39..000000000
--- a/op-mode-definitions/show-date.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0"?>
-<interfaceDefinition>
- <node name="show">
- <children>
- <node name="date">
- <properties>
- <help>Show system time and date</help>
- </properties>
- <command>/bin/date</command>
- <children>
- <node name="utc">
- <properties>
- <help>Show system date and time as Coordinated Universal Time</help>
- </properties>
- <command>/bin/date -u</command>
- <children>
- <leafNode name="maya">
- <properties>
- <help>Show UTC date in Maya calendar format</help>
- </properties>
- <command>${vyos_op_scripts_dir}/maya_date.py $(date +%s)</command>
- </leafNode>
- </children>
- </node>
- </children>
- </node>
-
- </children>
- </node>
-</interfaceDefinition>
diff --git a/op-mode-definitions/show-ntp.xml b/op-mode-definitions/show-ntp.xml
new file mode 100644
index 000000000..4f2f2192b
--- /dev/null
+++ b/op-mode-definitions/show-ntp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="show">
+ <children>
+ <node name="ntp">
+ <properties>
+ <help>Show peer status of NTP daemon</help>
+ </properties>
+ <command>if ps -C ntpd &amp;>/dev/null; then ntpdc -n -c peers; else echo NTP daemon disabled; fi</command>
+ </node>
+ <tagNode name="ntp">
+ <properties>
+ <help>Show date and time of specified NTP server</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_ntp_servers.sh</script>
+ </completionHelp>
+ </properties>
+ <command>/usr/sbin/ntpdate -q "$3"</command>
+ </tagNode>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/op-mode-definitions/wireguard.xml b/op-mode-definitions/wireguard.xml
new file mode 100644
index 000000000..29fce33b6
--- /dev/null
+++ b/op-mode-definitions/wireguard.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/completion/list_ntp_servers.sh b/src/completion/list_ntp_servers.sh
new file mode 100755
index 000000000..d0977fbd6
--- /dev/null
+++ b/src/completion/list_ntp_servers.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Completion script used to select specific NTP server
+/bin/cli-shell-api -- listEffectiveNodes system ntp server | sed "s/'//g"
diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py
new file mode 100755
index 000000000..a4f876397
--- /dev/null
+++ b/src/conf_mode/wireguard.py
@@ -0,0 +1,273 @@
+#!/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')
+
+ ### persistent-keepalive
+ if c.exists(cnf + ' peer ' + p + ' persistent-keepalive'):
+ config_data['interfaces'][intfc]['peer'][p]['persistent-keepalive'] = c.return_value(cnf + ' peer ' + p + ' persistent-keepalive')
+
+ #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)
+
+ ### 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)
+
+ ### persistent-keepalive
+ for p in c_eff.list_nodes(intf + ' peer'):
+ val_eff = ""
+ val = ""
+
+ if c_eff.exists_effective(intf + ' peer ' + p + ' persistent-keepalive'):
+ val_eff = c_eff.return_effective_value(intf + ' peer ' + p + ' persistent-keepalive')
+
+ if 'persistent-keepalive' in c['interfaces'][intf]['peer'][p]:
+ val = c['interfaces'][intf]['peer'][p]['persistent-keepalive']
+
+ ### disable keepalive
+ if val_eff and not val:
+ c['interfaces'][intf]['peer'][p]['persistent-keepalive'] = 0
+
+ ### set new keepalive value
+ if not val_eff and val:
+ c['interfaces'][intf]['peer'][p]['persistent-keepalive'] = val
+
+ ## wg command call
+ 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
+ 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
+
+ ## endpoint is only required if wg runs as client
+ if c['interfaces'][intf]['peer'][p]['endpoint']:
+ cmd += " endpoint " + c['interfaces'][intf]['peer'][p]['endpoint']
+
+ if 'persistent-keepalive' in c['interfaces'][intf]['peer'][p]:
+ cmd += " persistent-keepalive " + str( c['interfaces'][intf]['peer'][p]['persistent-keepalive'])
+
+ 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/dynamic_dns_status.py b/src/op_mode/dynamic_dns.py
index bbff01f49..7ac3dfe9f 100755
--- a/src/op_mode/dynamic_dns_status.py
+++ b/src/op_mode/dynamic_dns.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
-
+import os
+import argparse
import jinja2
import sys
import time
@@ -18,7 +19,8 @@ update-status: {{ entry.status }}
{% endfor -%}
"""
-if __name__ == '__main__':
+
+def show_status():
# Do nothing if service is not configured
c = Config()
if not c.exists_effective('service dns dynamic'):
@@ -65,3 +67,26 @@ if __name__ == '__main__':
tmpl = jinja2.Template(OUT_TMPL_SRC)
print(tmpl.render(data))
+
+
+def update_ddns():
+ os.system('systemctl stop ddclient')
+ os.remove(cache_file)
+ os.system('systemctl start ddclient')
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument("--status", help="Show DDNS status", action="store_true")
+ group.add_argument("--update", help="Update DDNS on a given interface", action="store_true")
+ args = parser.parse_args()
+
+ if args.status:
+ show_status()
+ elif args.update:
+ update_ddns()
+
+
+if __name__ == '__main__':
+ main()
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)
+