diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/ntp.py | 6 | ||||
-rwxr-xr-x | src/conf_mode/ssh.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/tftp_server.py | 162 | ||||
-rwxr-xr-x | src/conf_mode/wireguard.py | 38 | ||||
-rwxr-xr-x | src/helpers/validate-value.py | 2 | ||||
-rwxr-xr-x | src/op_mode/dynamic_dns.py (renamed from src/op_mode/dynamic_dns_status.py) | 29 | ||||
-rwxr-xr-x | src/op_mode/powerctrl.py | 4 |
7 files changed, 231 insertions, 14 deletions
diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 2a6088575..8533411cc 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -154,10 +154,10 @@ def generate(ntp): def apply(ntp): if ntp is not None: - os.system('sudo /usr/sbin/invoke-rc.d ntp force-reload') + os.system('sudo systemctl restart ntp.service') else: - # NTP suuport is removed in the commit - os.system('sudo /usr/sbin/invoke-rc.d ntp stop') + # NTP support is removed in the commit + os.system('sudo systemctl stop ntp.service') os.unlink(config_file) return None diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py index f1ac19473..beca7bb9a 100755 --- a/src/conf_mode/ssh.py +++ b/src/conf_mode/ssh.py @@ -236,10 +236,10 @@ def generate(ssh): def apply(ssh): if ssh is not None and 'port' in ssh.keys(): - os.system("sudo systemctl restart ssh") + os.system("sudo systemctl restart ssh.service") else: # SSH access is removed in the commit - os.system("sudo systemctl stop ssh") + os.system("sudo systemctl stop ssh.service") os.unlink(config_file) return None diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py new file mode 100755 index 000000000..9cf4489af --- /dev/null +++ b/src/conf_mode/tftp_server.py @@ -0,0 +1,162 @@ +#!/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 stat +import pwd + +import jinja2 +import ipaddress +import netifaces + +from vyos.config import Config +from vyos import ConfigError + +config_file = r'/etc/default/tftpd-hpa' + +# Please be careful if you edit the template. +config_tmpl = """ +### Autogenerated by tftp_server.py ### + +# See manual at https://linux.die.net/man/8/tftpd + +TFTP_USERNAME="tftp" +TFTP_DIRECTORY="{{ directory }}" +{% if listen_ipv4 and listen_ipv6 -%} +TFTP_ADDRESS="{% for a in listen_ipv4 -%}{{ a }}:{{ port }}{{- " --address " if not loop.last -}}{% endfor -%} {% for a in listen_ipv6 %} --address [{{ a }}]:{{ port }}{% endfor -%}" +{% elif listen_ipv4 -%} +TFTP_ADDRESS="{% for a in listen_ipv4 -%}{{ a }}:{{ port }}{{- " --address " if not loop.last -}}{% endfor %} -4" +{% elif listen_ipv6 -%} +TFTP_ADDRESS="{% for a in listen_ipv6 -%}[{{ a }}]:{{ port }}{{- " --address " if not loop.last -}}{% endfor %} -6" +{%- endif %} + +TFTP_OPTIONS="--secure {% if allow_upload %}--create --umask 002{% endif %}" +""" + +default_config_data = { + 'directory': '', + 'allow_upload': False, + 'port': '69', + 'listen_ipv4': [], + 'listen_ipv6': [] +} + +# Verify if an IP address is assigned to any interface, IPv4 and IPv6 +def addrok(ipaddr, ipversion): + # For every available interface on this system + for interface in netifaces.interfaces(): + # If it has any IPv4 or IPv6 address (depending on ipversion) configured + if ipversion in netifaces.ifaddresses(interface).keys(): + # For every configured IP address + for addr in netifaces.ifaddresses(interface)[ipversion]: + # Check if it matches to the address requested + if addr['addr'] == ipaddr: + return True + + return False + +def get_config(): + tftpd = default_config_data + conf = Config() + if not conf.exists('service tftp-server'): + return None + else: + conf.set_level('service tftp-server') + + if conf.exists('directory'): + tftpd['directory'] = conf.return_value('directory') + + if conf.exists('allow-upload'): + tftpd['allow_upload'] = True + + if conf.exists('port'): + tftpd['port'] = conf.return_value('port') + + if conf.exists('listen-address'): + for addr in conf.return_values('listen-address'): + if (ipaddress.ip_address(addr).version == 4): + tftpd['listen_ipv4'].append(addr) + + if (ipaddress.ip_address(addr).version == 6): + tftpd['listen_ipv6'].append(addr) + + return tftpd + +def verify(tftpd): + # bail out early - looks like removal from running config + if tftpd is None: + return None + + # Configuring allowed clients without a server makes no sense + if not tftpd['directory']: + raise ConfigError('TFTP root directory must be configured!') + + if not (tftpd['listen_ipv4'] or tftpd['listen_ipv6']): + raise ConfigError('TFTP server listen address must be configured!') + + for address in tftpd['listen_ipv4']: + if not addrok(address, netifaces.AF_INET): + raise ConfigError('TFTP server listen address "{0}" not configured on this system.'.format(address)) + + for address in tftpd['listen_ipv6']: + if not addrok(address, netifaces.AF_INET6): + raise ConfigError('TFTP server listen address "{0}" not configured on this system.'.format(address)) + + return None + +def generate(tftpd): + # bail out early - looks like removal from running config + if tftpd is None: + return None + + tmpl = jinja2.Template(config_tmpl) + config_text = tmpl.render(tftpd) + with open(config_file, 'w') as f: + f.write(config_text) + + return None + +def apply(tftpd): + if tftpd is not None: + + tftp_root = tftpd['directory'] + if not os.path.exists(tftp_root): + os.makedirs(tftp_root) + os.chmod(tftp_root, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH) + # get UNIX uid for user 'tftp' + tftp_uid = pwd.getpwnam('tftp').pw_uid + os.chown(tftp_root, tftp_uid, -1) + + os.system('sudo systemctl restart tftpd-hpa.service') + else: + # TFTP server support is removed in the commit + os.system('sudo systemctl stop tftpd-hpa.service') + os.unlink(config_file) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + sys.exit(1) diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index 7d52cfe94..a4f876397 100755 --- a/src/conf_mode/wireguard.py +++ b/src/conf_mode/wireguard.py @@ -116,6 +116,10 @@ def get_config(): 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 @@ -135,8 +139,6 @@ def verify(c): 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 @@ -192,6 +194,26 @@ def apply(c): 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 @@ -205,14 +227,22 @@ def configure_interface(c, intf): cmd = "wg set " + intf + \ " listen-port " + c['interfaces'][intf]['lport'] + \ " private-key " + pk + \ - " peer " + p + \ - " endpoint " + c['interfaces'][intf]['peer'][p]['endpoint'] + " 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) diff --git a/src/helpers/validate-value.py b/src/helpers/validate-value.py index d702739b5..36f996d38 100755 --- a/src/helpers/validate-value.py +++ b/src/helpers/validate-value.py @@ -23,7 +23,7 @@ try: except Exception as exn: if debug: print(exn) - else: + else: pass try: 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/powerctrl.py b/src/op_mode/powerctrl.py index f73d6c005..8a66b3afd 100755 --- a/src/op_mode/powerctrl.py +++ b/src/op_mode/powerctrl.py @@ -126,9 +126,9 @@ def main(): args = parser.parse_args() try: - if args.reboot: + if args.reboot is not None: execute_shutdown(args.reboot, reboot=True, ask=args.yes) - if args.poweroff: + if args.poweroff is not None: execute_shutdown(args.poweroff, reboot=False,ask=args.yes) if args.cancel: cancel_shutdown() |