From 8cb56942e141f19af71f97d1093395326c99dbe5 Mon Sep 17 00:00:00 2001 From: hagbard Date: Fri, 17 Aug 2018 16:56:52 +0000 Subject: remove endpoint check, which is optional. server mode find the endpoint from an authenticated package. --- src/conf_mode/wireguard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index 7d52cfe94..3426acbe3 100755 --- a/src/conf_mode/wireguard.py +++ b/src/conf_mode/wireguard.py @@ -135,8 +135,8 @@ 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) +# 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 -- cgit v1.2.3 From 85a80fe59443a91b66185a06e192f99bec30af68 Mon Sep 17 00:00:00 2001 From: hagbard Date: Fri, 17 Aug 2018 18:25:25 +0000 Subject: T427: endpoint is only required for client mode, it's now an optional parameter --- src/conf_mode/wireguard.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index 3426acbe3..dda5c4d8a 100755 --- a/src/conf_mode/wireguard.py +++ b/src/conf_mode/wireguard.py @@ -135,8 +135,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 @@ -205,14 +203,19 @@ 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'] + sl.syslog(sl.LOG_NOTICE, "sudo " + cmd) subprocess.call([ 'sudo ' + cmd], shell=True) -- cgit v1.2.3 From f184700bdb0c070be7f3bf9d9b2712581c29e798 Mon Sep 17 00:00:00 2001 From: hagbard Date: Fri, 17 Aug 2018 19:32:47 +0000 Subject: T783: conf mode persistent-keepalive implementation --- interface-definitions/wireguard.xml | 9 +++++++++ src/conf_mode/wireguard.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'src') diff --git a/interface-definitions/wireguard.xml b/interface-definitions/wireguard.xml index 008f82a0b..eec7a404b 100644 --- a/interface-definitions/wireguard.xml +++ b/interface-definitions/wireguard.xml @@ -68,6 +68,15 @@ Remote endpoint + + + how often send keep alives in seconds + + ^(1|[1-9][0-9]{0,5})$ + + keepliave timer has to be between 1 and 99999 seconds + + diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index dda5c4d8a..94378a6ef 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 @@ -190,6 +194,14 @@ def apply(c): for addr in addr_add: add_addr(intf, addr) + ### persistent-keepalive + for p in c_eff.list_nodes(intf + ' peer'): + pklv_eff = c_eff.return_effective_value(intf + ' peer ' + p + ' persistent-keepalive') + pklv = c_eff.return_value(intf + ' peer ' + p + ' persistent-keepalive') + if pklv_eff == pklv: + del c['interfaces'][intf]['peer'][p]['persistent-keepalive'] + + ## wg command call configure_interface(c,intf) ### ifalias for snmp from description @@ -216,6 +228,9 @@ def configure_interface(c, intf): if c['interfaces'][intf]['peer'][p]['endpoint']: cmd += " endpoint " + c['interfaces'][intf]['peer'][p]['endpoint'] + if c['interfaces'][intf]['peer'][p]['persistent-keepalive']: + cmd += " persistent-keepalive " + str( c['interfaces'][intf]['peer'][p]['persistent-keepalive']) + sl.syslog(sl.LOG_NOTICE, "sudo " + cmd) subprocess.call([ 'sudo ' + cmd], shell=True) -- cgit v1.2.3 From 7a27726e0e1e1de47f8abfb64e9c28eadb34c55b Mon Sep 17 00:00:00 2001 From: Dmytro Aleksandrov Date: Sat, 18 Aug 2018 00:43:12 +0300 Subject: T784: Added update dns dynamic operation --- Makefile | 1 - op-mode-definitions/dns-forwarding.xml | 3 ++ op-mode-definitions/dynamic-dns.xml | 25 ++++++++- src/op_mode/dynamic_dns.py | 92 ++++++++++++++++++++++++++++++++++ src/op_mode/dynamic_dns_status.py | 67 ------------------------- 5 files changed, 119 insertions(+), 69 deletions(-) create mode 100755 src/op_mode/dynamic_dns.py delete mode 100755 src/op_mode/dynamic_dns_status.py (limited to 'src') diff --git a/Makefile b/Makefile index 823637e84..70101181d 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,6 @@ op_mode_definitions: # 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 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 @@ + + Show DNS information + 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 @@ + + Show DNS information + @@ -14,7 +17,7 @@ Show Dynamic DNS status - sudo ${vyos_op_scripts_dir}/dynamic_dns_status.py + sudo ${vyos_op_scripts_dir}/dynamic_dns.py --status @@ -22,4 +25,24 @@ + + + Update data for a service + + + + + Update DNS information + + + + + Update Dynamic DNS information + + sudo ${vyos_op_scripts_dir}/dynamic_dns.py --update + + + + + diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py new file mode 100755 index 000000000..7ac3dfe9f --- /dev/null +++ b/src/op_mode/dynamic_dns.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +import os +import argparse +import jinja2 +import sys +import time + +from vyos.config import Config + +cache_file = r'/var/cache/ddclient/ddclient.cache' + +OUT_TMPL_SRC = """ +{%- for entry in hosts -%} +ip address : {{ entry.ip }} +host-name : {{ entry.host }} +last update : {{ entry.time }} +update-status: {{ entry.status }} + +{% endfor -%} +""" + + +def show_status(): + # Do nothing if service is not configured + c = Config() + if not c.exists_effective('service dns dynamic'): + print("Dynamic DNS not configured") + sys.exit(0) + + data = { + 'hosts': [] + } + + with open(cache_file, 'r') as f: + for line in f: + if line.startswith('#'): + continue + + outp = { + 'host': '', + 'ip': '', + 'time': '' + } + + if 'host=' in line: + host = line.split('host=')[1] + if host: + outp['host'] = host.split(',')[0] + + if 'ip=' in line: + ip = line.split('ip=')[1] + if ip: + outp['ip'] = ip.split(',')[0] + + if 'atime=' in line: + atime = line.split('atime=')[1] + if atime: + tmp = atime.split(',')[0] + outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(tmp, base=10))) + + if 'status=' in line: + status = line.split('status=')[1] + if status: + outp['status'] = status.split(',')[0] + + data['hosts'].append(outp) + + 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/dynamic_dns_status.py b/src/op_mode/dynamic_dns_status.py deleted file mode 100755 index bbff01f49..000000000 --- a/src/op_mode/dynamic_dns_status.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python3 - -import jinja2 -import sys -import time - -from vyos.config import Config - -cache_file = r'/var/cache/ddclient/ddclient.cache' - -OUT_TMPL_SRC = """ -{%- for entry in hosts -%} -ip address : {{ entry.ip }} -host-name : {{ entry.host }} -last update : {{ entry.time }} -update-status: {{ entry.status }} - -{% endfor -%} -""" - -if __name__ == '__main__': - # Do nothing if service is not configured - c = Config() - if not c.exists_effective('service dns dynamic'): - print("Dynamic DNS not configured") - sys.exit(0) - - data = { - 'hosts': [] - } - - with open(cache_file, 'r') as f: - for line in f: - if line.startswith('#'): - continue - - outp = { - 'host': '', - 'ip': '', - 'time': '' - } - - if 'host=' in line: - host = line.split('host=')[1] - if host: - outp['host'] = host.split(',')[0] - - if 'ip=' in line: - ip = line.split('ip=')[1] - if ip: - outp['ip'] = ip.split(',')[0] - - if 'atime=' in line: - atime = line.split('atime=')[1] - if atime: - tmp = atime.split(',')[0] - outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(tmp, base=10))) - - if 'status=' in line: - status = line.split('status=')[1] - if status: - outp['status'] = status.split(',')[0] - - data['hosts'].append(outp) - - tmpl = jinja2.Template(OUT_TMPL_SRC) - print(tmpl.render(data)) -- cgit v1.2.3 From 14f37d3ecbab133b0259de540ae16bd065494dd7 Mon Sep 17 00:00:00 2001 From: hagbard Date: Fri, 17 Aug 2018 22:38:06 +0000 Subject: T783: to disable keepalive is has to be set to 0. --- src/conf_mode/wireguard.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index 94378a6ef..e1c076e2a 100755 --- a/src/conf_mode/wireguard.py +++ b/src/conf_mode/wireguard.py @@ -196,11 +196,27 @@ def apply(c): ### persistent-keepalive for p in c_eff.list_nodes(intf + ' peer'): - pklv_eff = c_eff.return_effective_value(intf + ' peer ' + p + ' persistent-keepalive') - pklv = c_eff.return_value(intf + ' peer ' + p + ' persistent-keepalive') - if pklv_eff == pklv: + 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 ne keepalive value + if not val_eff and val: + c['interfaces'][intf]['peer'][p]['persistent-keepalive'] = val + + ## config == effective config, no change + if val_eff == val: del c['interfaces'][intf]['peer'][p]['persistent-keepalive'] - + ## wg command call configure_interface(c,intf) @@ -228,7 +244,7 @@ def configure_interface(c, intf): if c['interfaces'][intf]['peer'][p]['endpoint']: cmd += " endpoint " + c['interfaces'][intf]['peer'][p]['endpoint'] - if c['interfaces'][intf]['peer'][p]['persistent-keepalive']: + 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) -- cgit v1.2.3 From 55ee5d903817e3a80fb6272d790dcce1044f8a9b Mon Sep 17 00:00:00 2001 From: Runar Borge Date: Sun, 19 Aug 2018 22:25:34 +0200 Subject: T689: Reboot/Poweroff now not working after last changes --- op-mode-definitions/poweroff.xml | 4 ++-- op-mode-definitions/reboot.xml | 4 ++-- src/op_mode/powerctrl.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/op-mode-definitions/poweroff.xml b/op-mode-definitions/poweroff.xml index ff27f4f4d..e2483fefc 100644 --- a/op-mode-definitions/poweroff.xml +++ b/op-mode-definitions/poweroff.xml @@ -4,14 +4,14 @@ Poweroff the system - sudo ${vyos_op_scripts_dir}/powerctrl.py --poweroff now + sudo ${vyos_op_scripts_dir}/powerctrl.py --poweroff Poweroff the system without confirmation - sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --poweroff now + sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --poweroff diff --git a/op-mode-definitions/reboot.xml b/op-mode-definitions/reboot.xml index 340c8ca82..affdffd98 100644 --- a/op-mode-definitions/reboot.xml +++ b/op-mode-definitions/reboot.xml @@ -4,14 +4,14 @@ Reboot the system - sudo ${vyos_op_scripts_dir}/powerctrl.py --reboot now + sudo ${vyos_op_scripts_dir}/powerctrl.py --reboot Reboot the system without confirmation - sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --reboot now + sudo ${vyos_op_scripts_dir}/powerctrl.py --yes --reboot 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() -- cgit v1.2.3 From d3bb77e6bb031270e37ceb83354a1cad9b000317 Mon Sep 17 00:00:00 2001 From: hagbard Date: Mon, 20 Aug 2018 16:38:25 +0000 Subject: bugfix: if config and effective value are equal, there is no change required, deleting it from the dict will result in a keyerror if not aset at all --- src/conf_mode/wireguard.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/conf_mode/wireguard.py b/src/conf_mode/wireguard.py index e1c076e2a..a4f876397 100755 --- a/src/conf_mode/wireguard.py +++ b/src/conf_mode/wireguard.py @@ -209,13 +209,9 @@ def apply(c): if val_eff and not val: c['interfaces'][intf]['peer'][p]['persistent-keepalive'] = 0 - ### set ne keepalive value + ### set new keepalive value if not val_eff and val: c['interfaces'][intf]['peer'][p]['persistent-keepalive'] = val - - ## config == effective config, no change - if val_eff == val: - del c['interfaces'][intf]['peer'][p]['persistent-keepalive'] ## wg command call configure_interface(c,intf) -- cgit v1.2.3 From 8b334a05e4fbab73e7e060b45c9fb33e68ec8b95 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 25 Aug 2018 15:40:50 +0200 Subject: ntp.py: fix typo in comment --- src/conf_mode/ntp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 2a6088575..b618cbd89 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -156,7 +156,7 @@ def apply(ntp): if ntp is not None: os.system('sudo /usr/sbin/invoke-rc.d ntp force-reload') else: - # NTP suuport is removed in the commit + # NTP support is removed in the commit os.system('sudo /usr/sbin/invoke-rc.d ntp stop') os.unlink(config_file) -- cgit v1.2.3 From bbc698be2fcafad4e803fc01ec89f44a3aa20782 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 17 Aug 2018 20:39:11 +0200 Subject: validate-value.py: remove tailing whitespaces --- src/helpers/validate-value.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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: -- cgit v1.2.3 From 211b762f9bdc5704e07638ac8f948277ef4f4319 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:18:18 +0200 Subject: ntp.py: start/stop service via systemctl --- src/conf_mode/ntp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index b618cbd89..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 support is removed in the commit - os.system('sudo /usr/sbin/invoke-rc.d ntp stop') + os.system('sudo systemctl stop ntp.service') os.unlink(config_file) return None -- cgit v1.2.3 From bc8b7305111d890e2933f06d72c60c0ab9258f0f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:18:31 +0200 Subject: ssh.py: start/stop service via systemctl --- src/conf_mode/ssh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') 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 -- cgit v1.2.3 From 4d222bc14c23ba010b6e245ff35ddb766401b20d Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:19:14 +0200 Subject: T792: add TFTP server functionality --- debian/control | 1 + interface-definitions/tftp-server.xml | 57 ++++++++++++ src/conf_mode/tftp_server.py | 159 ++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 interface-definitions/tftp-server.xml create mode 100755 src/conf_mode/tftp_server.py (limited to 'src') diff --git a/debian/control b/debian/control index 70bf7a61c..04b228737 100644 --- a/debian/control +++ b/debian/control @@ -38,6 +38,7 @@ Depends: python3, beep, keepalived (>=2.0.5), wireguard, + tftpd-hpa, ${shlibs:Depends}, ${misc:Depends} Description: VyOS configuration scripts and data diff --git a/interface-definitions/tftp-server.xml b/interface-definitions/tftp-server.xml new file mode 100644 index 000000000..2874b034c --- /dev/null +++ b/interface-definitions/tftp-server.xml @@ -0,0 +1,57 @@ + + + + + + + + Trivial File Transfer Protocol (TFTP) server + 990 + + + + + Folder containing files served by TFTP [REQUIRED] + + + + + Allow TFTP file uploads + + + + + + Port for TFTP service + + 1-65535 + Numeric IP port (default: 69) + + + + + + + + + Addresses for TFTP server to listen [REQUIRED] + + ipv4 + TFTP IPv4 listen address + + + ipv6 + TFTP IPv6 listen address + + + + + + + + + + + + + diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py new file mode 100755 index 000000000..8133ed215 --- /dev/null +++ b/src/conf_mode/tftp_server.py @@ -0,0 +1,159 @@ +#!/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 . +# +# + +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 interface in netifaces.interfaces(): + # Retrieve IP address of network interfaces + if ipversion in netifaces.ifaddresses(interface).keys(): + for addr in netifaces.ifaddresses(interface)[ipversion]: + 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 uid for user 'snmp' + 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) -- cgit v1.2.3 From 5150b2890ec6a38dbeae2e105fce6855ce0f589e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 16:55:49 +0200 Subject: tftp_server.py: fix indention and add more verbose comments --- src/conf_mode/tftp_server.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py index 8133ed215..8665f2964 100755 --- a/src/conf_mode/tftp_server.py +++ b/src/conf_mode/tftp_server.py @@ -59,12 +59,15 @@ default_config_data = { # 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(): - # Retrieve IP address of network interfaces - if ipversion in netifaces.ifaddresses(interface).keys(): - for addr in netifaces.ifaddresses(interface)[ipversion]: - if addr['addr'] == ipaddr: - return True + # 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 -- cgit v1.2.3 From 23022977a6bf94e6be7d37de04c97ab0b5d1ea35 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 16:56:37 +0200 Subject: tftp_server.py: fix copy-paste comment --- src/conf_mode/tftp_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py index 8665f2964..9cf4489af 100755 --- a/src/conf_mode/tftp_server.py +++ b/src/conf_mode/tftp_server.py @@ -139,7 +139,7 @@ def apply(tftpd): 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 uid for user 'snmp' + # get UNIX uid for user 'tftp' tftp_uid = pwd.getpwnam('tftp').pw_uid os.chown(tftp_root, tftp_uid, -1) -- cgit v1.2.3