Page MenuHomeVyOS Platform

interface-wireguard.py
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

interface-wireguard.py

#!/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
from vyos.ifconfig import WireGuardIf
ifname = str(os.environ['VYOS_TAGNODE_VALUE'])
intfc = WireGuardIf(ifname)
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():
c = Config()
if not c.exists('interfaces wireguard'):
return None
config_data = {
ifname: {
'addr': '',
'descr': ifname,
'lport': None,
'status': 'exists',
'state': 'enabled',
'fwmark': 0x00,
'mtu': 1420,
'peer': {},
'pk' : '/config/auth/wireguard/private.key'
}
}
c.set_level('interfaces wireguard')
if not c.exists_effective(ifname):
config_data[ifname]['status'] = 'create'
if not c.exists(ifname) and c.exists_effective(ifname):
config_data[ifname]['status'] = 'delete'
if config_data[ifname]['status'] != 'delete':
if c.exists(ifname + ' address'):
config_data[ifname]['addr'] = c.return_values(ifname + ' address')
if c.exists(ifname + ' disable'):
config_data[ifname]['state'] = 'disable'
if c.exists(ifname + ' port'):
config_data[ifname]['lport'] = c.return_value(ifname + ' port')
if c.exists(ifname + ' fwmark'):
config_data[ifname]['fwmark'] = c.return_value(ifname + ' fwmark')
if c.exists(ifname + ' description'):
config_data[ifname]['descr'] = c.return_value(
ifname + ' description')
if c.exists(ifname + ' mtu'):
config_data[ifname]['mtu'] = c.return_value(ifname + ' mtu')
if c.exists(ifname + ' peer'):
for p in c.list_nodes(ifname + ' peer'):
if not c.exists(ifname + ' peer ' + p + ' disable'):
config_data[ifname]['peer'].update(
{
p: {
'allowed-ips': [],
'endpoint': '',
'pubkey': ''
}
}
)
if c.exists(ifname + ' peer ' + p + ' pubkey'):
config_data[ifname]['peer'][p]['pubkey'] = c.return_value(
ifname + ' peer ' + p + ' pubkey')
if c.exists(ifname + ' peer ' + p + ' allowed-ips'):
config_data[ifname]['peer'][p]['allowed-ips'] = c.return_values(
ifname + ' peer ' + p + ' allowed-ips')
if c.exists(ifname + ' peer ' + p + ' endpoint'):
config_data[ifname]['peer'][p]['endpoint'] = c.return_value(
ifname + ' peer ' + p + ' endpoint')
if c.exists(ifname + ' peer ' + p + ' persistent-keepalive'):
config_data[ifname]['peer'][p]['persistent-keepalive'] = c.return_value(
ifname + ' peer ' + p + ' persistent-keepalive')
if c.exists(ifname + ' peer ' + p + ' preshared-key'):
config_data[ifname]['peer'][p]['psk'] = c.return_value(
ifname + ' peer ' + p + ' preshared-key')
return config_data
def verify(c):
if not c:
return None
if not os.path.exists(c[ifname]['pk']):
raise ConfigError(
"No keys found, generate them by executing: \'run generate wireguard keypair\'")
if c[ifname]['status'] != 'delete':
if not c[ifname]['addr']:
raise ConfigError("ERROR: IP address required")
if not c[ifname]['peer']:
raise ConfigError("ERROR: peer required")
for p in c[ifname]['peer']:
if not c[ifname]['peer'][p]['allowed-ips']:
raise ConfigError("ERROR: allowed-ips required for peer " + p)
if not c[ifname]['peer'][p]['pubkey']:
raise ConfigError("peer pubkey required for peer " + p)
def apply(c):
# no wg config left, delete all wireguard devices, if any
if not c:
net_devs = os.listdir('/sys/class/net/')
for dev in net_devs:
if os.path.isdir('/sys/class/net/' + dev):
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
# interface removal
if c[ifname]['status'] == 'delete':
sl.syslog(sl.LOG_NOTICE, "removing interface " + ifname)
intfc.remove()
return None
c_eff = Config()
c_eff.set_level('interfaces wireguard')
# interface state
if c[ifname]['state'] == 'disable':
sl.syslog(sl.LOG_NOTICE, "disable interface " + ifname)
intfc.state = 'down'
else:
if not intfc.state == 'up':
sl.syslog(sl.LOG_NOTICE, "enable interface " + ifname)
intfc.state = 'up'
# IP address
if not c_eff.exists_effective(ifname + ' address'):
for ip in c[ifname]['addr']:
intfc.add_addr(ip)
else:
addr_eff = c_eff.return_effective_values(ifname + ' address')
addr_rem = list(set(addr_eff) - set(c[ifname]['addr']))
addr_add = list(set(c[ifname]['addr']) - set(addr_eff))
if len(addr_rem) != 0:
for ip in addr_rem:
sl.syslog(
sl.LOG_NOTICE, "remove IP address {0} from {1}".format(ip, ifname))
intfc.del_addr(ip)
if len(addr_add) != 0:
for ip in addr_add:
sl.syslog(
sl.LOG_NOTICE, "add IP address {0} to {1}".format(ip, ifname))
intfc.add_addr(ip)
# interface MTU
if c[ifname]['mtu'] != 1420:
intfc.mtu = int(c[ifname]['mtu'])
else:
# default is set to 1420 in config_data
intfc.mtu = int(c[ifname]['mtu'])
# ifalias for snmp from description
descr_eff = c_eff.return_effective_value(ifname + ' description')
if descr_eff != c[ifname]['descr']:
intfc.ifalias = str(c[ifname]['descr'])
# peer deletion
peer_eff = c_eff.list_effective_nodes(ifname + ' peer')
peer_cnf = []
try:
for p in c[ifname]['peer']:
peer_cnf.append(p)
except KeyError:
pass
peer_rem = list(set(peer_eff) - set(peer_cnf))
for p in peer_rem:
pkey = c_eff.return_effective_value(ifname + ' peer ' + p + ' pubkey')
intfc.remove_peer(pkey)
# peer key update
for p in peer_eff:
if p in peer_cnf:
ekey = c_eff.return_effective_value(
ifname + ' peer ' + p + ' pubkey')
nkey = c[ifname]['peer'][p]['pubkey']
if nkey != ekey:
sl.syslog(
sl.LOG_NOTICE, "peer {0} pubkey changed from {1} to {2} on interface {3}".format(p, ekey, nkey, ifname))
intfc.remove_peer(ekey)
intfc.config['private-key'] = c[ifname]['pk']
for p in c[ifname]['peer']:
intfc.config['pubkey'] = str(c[ifname]['peer'][p]['pubkey'])
intfc.config['allowed-ips'] = (c[ifname]['peer'][p]['allowed-ips'])
# listen-port
if c[ifname]['lport']:
intfc.config['port'] = c[ifname]['lport']
# fwmark
if c[ifname]['fwmark']:
intfc.config['fwmark'] = c[ifname]['fwmark']
# endpoint
if c[ifname]['peer'][p]['endpoint']:
intfc.config['endpoint'] = c[ifname]['peer'][p]['endpoint']
# persistent-keepalive
if 'persistent-keepalive' in c[ifname]['peer'][p]:
intfc.config['keepalive'] = c[ifname][
'peer'][p]['persistent-keepalive']
# preshared-key - needs to be read from a file
if 'psk' in c[ifname]['peer'][p]:
psk_file = '/config/auth/wireguard/psk'
old_umask = os.umask(0o077)
open(psk_file, 'w').write(str(c[ifname]['peer'][p]['psk']))
os.umask(old_umask)
intfc.config['psk'] = psk_file
intfc.update()
if __name__ == '__main__':
try:
check_kmod()
c = get_config()
verify(c)
apply(c)
except ConfigError as e:
print(e)
sys.exit(1)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:46 AM (11 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4348008
Default Alt Text
interface-wireguard.py (9 KB)

Event Timeline