summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/ntp.py6
-rwxr-xr-xsrc/conf_mode/ssh.py4
-rwxr-xr-xsrc/conf_mode/tftp_server.py162
-rwxr-xr-xsrc/conf_mode/wireguard.py38
-rwxr-xr-xsrc/helpers/validate-value.py2
-rwxr-xr-xsrc/op_mode/dynamic_dns.py (renamed from src/op_mode/dynamic_dns_status.py)29
-rwxr-xr-xsrc/op_mode/powerctrl.py4
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()