diff options
-rw-r--r-- | data/templates/dhcp-client/ipv6.tmpl | 42 | ||||
-rw-r--r-- | data/templates/lcd/LCDd.conf.tmpl | 12 | ||||
-rw-r--r-- | data/templates/ocserv/ocserv_config.tmpl | 82 | ||||
-rw-r--r-- | data/templates/ocserv/ocserv_passwd.tmpl | 6 | ||||
-rw-r--r-- | data/templates/ocserv/radius_conf.tmpl | 22 | ||||
-rw-r--r-- | data/templates/ocserv/radius_servers.tmpl | 7 | ||||
-rw-r--r-- | debian/control | 1 | ||||
-rw-r--r-- | interface-definitions/system-lcd.xml.in | 16 | ||||
-rw-r--r-- | interface-definitions/vpn_anyconnect.xml.in | 258 | ||||
-rw-r--r-- | op-mode-definitions/anyconnect.xml | 20 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 5 | ||||
-rwxr-xr-x | src/conf_mode/system_lcd.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/vpn_anyconnect.py | 132 | ||||
-rw-r--r-- | src/etc/systemd/system/ocserv.service.d/override.conf | 14 | ||||
-rwxr-xr-x | src/op_mode/anyconnect-control.py | 67 | ||||
-rw-r--r-- | src/systemd/lcdproc.service | 4 |
16 files changed, 659 insertions, 33 deletions
diff --git a/data/templates/dhcp-client/ipv6.tmpl b/data/templates/dhcp-client/ipv6.tmpl index 5c0cea280..9673f302b 100644 --- a/data/templates/dhcp-client/ipv6.tmpl +++ b/data/templates/dhcp-client/ipv6.tmpl @@ -4,45 +4,41 @@ interface {{ ifname }} { request domain-name-servers; request domain-name; -{% if dhcpv6_options is defined %} -{% if dhcpv6_options.parameters_only is defined %} +{% if dhcpv6_options is defined and dhcpv6_options.parameters_only is defined %} information-only; -{% endif %} -{% if dhcpv6_options.temporary is not defined %} +{% endif %} +{% if dhcpv6_options is not defined or dhcpv6_options.temporary is not defined %} send ia-na 1; # non-temporary address -{% endif %} -{% if dhcpv6_options.prefix_delegation is defined %} +{% endif %} +{% if dhcpv6_options is defined and dhcpv6_options.prefix_delegation is defined %} send ia-pd 2; # prefix delegation -{% endif %} -{% endif %} +{% endif %} }; -{% if dhcpv6_options is defined %} -{% if dhcpv6_options.temporary is not defined %} +{% if dhcpv6_options is not defined or dhcpv6_options.temporary is not defined %} id-assoc na 1 { # Identity association NA }; -{% endif %} +{% endif %} -{% if dhcpv6_options.prefix_delegation is defined %} +{% if dhcpv6_options is defined and dhcpv6_options.prefix_delegation is defined %} id-assoc pd 2 { -{% if dhcpv6_options.prefix_delegation.length is defined %} +{% if dhcpv6_options.prefix_delegation.length is defined %} prefix ::/{{ dhcpv6_options.prefix_delegation.length }} infinity; -{% endif %} -{% for interface in dhcpv6_options.prefix_delegation.interface %} +{% endif %} +{% for interface in dhcpv6_options.prefix_delegation.interface %} prefix-interface {{ interface }} { -{% if dhcpv6_options.prefix_delegation.interface[interface].sla_id is defined %} +{% if dhcpv6_options.prefix_delegation.interface[interface].sla_id is defined %} sla-id {{ dhcpv6_options.prefix_delegation.interface[interface].sla_id }}; -{% endif %} -{% if dhcpv6_options.prefix_delegation.interface[interface].sla_len is defined %} +{% endif %} +{% if dhcpv6_options.prefix_delegation.interface[interface].sla_len is defined %} sla-len {{ dhcpv6_options.prefix_delegation.interface[interface].sla_len }}; -{% endif %} -{% if dhcpv6_options.prefix_delegation.interface[interface].address is defined %} +{% endif %} +{% if dhcpv6_options.prefix_delegation.interface[interface].address is defined %} ifid {{ dhcpv6_options.prefix_delegation.interface[interface].address }}; -{% endif %} +{% endif %} }; -{% endfor %} +{% endfor %} }; -{% endif %} {% endif %} diff --git a/data/templates/lcd/LCDd.conf.tmpl b/data/templates/lcd/LCDd.conf.tmpl index da749d04a..bde177b6a 100644 --- a/data/templates/lcd/LCDd.conf.tmpl +++ b/data/templates/lcd/LCDd.conf.tmpl @@ -48,8 +48,12 @@ DriverPath=/usr/lib/x86_64-linux-gnu/lcdproc/ # sed1520, serialPOS, serialVFD, shuttleVFD, sli, stv5730, svga, t6963, # text, tyan, ula200, vlsys_m428, xosd, yard2LCD -{% if model is defined and model.startswith('CFA-') %} +{% if model is defined %} +{% if model.startswith('cfa-') %} Driver=CFontzPacket +{% elif model == 'sdec' %} +Driver=sdeclcd +{% endif %} {% endif %} # Tells the driver to bind to the given interface. [default: 127.0.0.1] @@ -112,7 +116,7 @@ Heartbeat=off TitleSpeed=10 {% if model is defined and model is not none %} -{% if model.startswith('CFA-') %} +{% if model.startswith('cfa-') %} ## CrystalFontz packet driver (for CFA533, CFA631, CFA633 & CFA635) ## [CFontzPacket] Model={{ model.split('-')[1] }} @@ -122,5 +126,9 @@ Brightness=500 OffBrightness=50 Reboot=yes USB=yes +{% elif model == 'sdec' %} +## SDEC driver for Lanner, Watchguard, Sophos sppliances ## +[sdeclcd] +# No options {% endif %} {% endif %} diff --git a/data/templates/ocserv/ocserv_config.tmpl b/data/templates/ocserv/ocserv_config.tmpl new file mode 100644 index 000000000..6aaeff693 --- /dev/null +++ b/data/templates/ocserv/ocserv_config.tmpl @@ -0,0 +1,82 @@ +### generated by vpn_anyconnect.py ### + +tcp-port = {{ listen_ports.tcp }} +udp-port = {{ listen_ports.udp }} + +run-as-user = nobody +run-as-group = daemon + +{% if "radius" in authentication.mode %} +auth = "radius [config=/run/ocserv/radiusclient.conf]" +{% else %} +auth = "plain[/run/ocserv/ocpasswd]" +{% endif %} + +{% if ssl.cert_file %} +server-cert = {{ ssl.cert_file }} +{% endif %} + +{% if ssl.key_file %} +server-key = {{ ssl.key_file }} +{% endif %} + +{% if ssl.ca_cert_file %} +ca-cert = {{ ssl.ca_cert_file }} +{% endif %} + +socket-file = /run/ocserv/ocserv.socket +occtl-socket-file = /run/ocserv/occtl.socket +use-occtl = true +isolate-workers = true +keepalive = 300 +dpd = 60 +mobile-dpd = 300 +switch-to-tcp-timeout = 30 +tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128" +auth-timeout = 240 +idle-timeout = 1200 +mobile-idle-timeout = 1800 +min-reauth-time = 3 +cookie-timeout = 300 +rekey-method = ssl +try-mtu-discovery = true +cisco-client-compat = true +dtls-legacy = true + + +# The name to use for the tun device +device = sslvpn + +# An alternative way of specifying the network: +{% if network_settings %} +# DNS settings +{% if network_settings.name_server is string %} +dns = {{ network_settings.name_server }} +{% else %} +{% for dns in network_settings.name_server %} +dns = {{ dns }} +{% endfor %} +{% endif %} +# IPv4 network pool +{% if network_settings.client_ip_settings %} +{% if network_settings.client_ip_settings.subnet %} +ipv4-network = {{ network_settings.client_ip_settings.subnet }} +{% endif %} +{% endif %} +# IPv6 network pool +{% if network_settings.client_ipv6_pool %} +{% if network_settings.client_ipv6_pool.prefix %} +ipv6-network = {{ network_settings.client_ipv6_pool.prefix }} +ipv6-subnet-prefix = {{ network_settings.client_ipv6_pool.mask }} +{% endif %} +{% endif %} +{% endif %} + +{% if network_settings.push_route is string %} +route = {{ network_settings.push_route }} +{% else %} +{% for route in network_settings.push_route %} +route = {{ route }} +{% endfor %} +{% endif %} + diff --git a/data/templates/ocserv/ocserv_passwd.tmpl b/data/templates/ocserv/ocserv_passwd.tmpl new file mode 100644 index 000000000..ffadb4860 --- /dev/null +++ b/data/templates/ocserv/ocserv_passwd.tmpl @@ -0,0 +1,6 @@ +#<username>:<group>:<hash> +{% for user in username if username is defined %} +{% if not "disable" in username[user] %} +{{ user }}:*:{{ username[user].hash }} +{% endif %} +{% endfor %}
\ No newline at end of file diff --git a/data/templates/ocserv/radius_conf.tmpl b/data/templates/ocserv/radius_conf.tmpl new file mode 100644 index 000000000..2d19306a0 --- /dev/null +++ b/data/templates/ocserv/radius_conf.tmpl @@ -0,0 +1,22 @@ +### generated by cpn_anyconnect.py ### +nas-identifier VyOS +{% for srv in server %} +{% if not "disable" in server[srv] %} +{% if "port" in server[srv] %} +authserver {{ srv }}:{{server[srv]["port"]}} +{% else %} +authserver {{ srv }} +{% endif %} +{% endif %} +{% endfor %} +radius_timeout {{ timeout }} +{% if source_address %} +bindaddr {{ source_address }} +{% else %} +bindaddr * +{% endif %} +servers /run/ocserv/radius_servers +dictionary /etc/radcli/dictionary +default_realm +radius_retries 3 +#
\ No newline at end of file diff --git a/data/templates/ocserv/radius_servers.tmpl b/data/templates/ocserv/radius_servers.tmpl new file mode 100644 index 000000000..ba21fa074 --- /dev/null +++ b/data/templates/ocserv/radius_servers.tmpl @@ -0,0 +1,7 @@ +### generated by cpn_anyconnect.py ### +# server key +{% for srv in server %} +{% if not "disable" in server[srv] %} +{{ srv }} {{ server[srv].key }} +{% endif %} +{% endfor %} diff --git a/debian/control b/debian/control index 34ba4be8e..520401d57 100644 --- a/debian/control +++ b/debian/control @@ -107,6 +107,7 @@ Depends: python3, libatomic1, fastnetmon, libndp-tools, + ocserv, tcptraceroute Description: VyOS configuration scripts and data VyOS configuration scripts, interface definitions, and everything diff --git a/interface-definitions/system-lcd.xml.in b/interface-definitions/system-lcd.xml.in index ad59acb6b..36116ae1b 100644 --- a/interface-definitions/system-lcd.xml.in +++ b/interface-definitions/system-lcd.xml.in @@ -12,26 +12,30 @@ <properties> <help>Model of the display attached to this system [REQUIRED]</help> <completionHelp> - <list>CFA-533 CFA-631 CFA-633 CFA-635</list> + <list>cfa-533 cfa-631 cfa-633 cfa-635 sdec</list> </completionHelp> <valueHelp> - <format>CFA-533</format> + <format>cfa-533</format> <description>Crystalfontz CFA-533</description> </valueHelp> <valueHelp> - <format>CFA-631</format> + <format>cfa-631</format> <description>Crystalfontz CFA-631</description> </valueHelp> <valueHelp> - <format>CFA-633</format> + <format>cfa-633</format> <description>Crystalfontz CFA-633</description> </valueHelp> <valueHelp> - <format>CFA-635</format> + <format>cfa-635</format> <description>Crystalfontz CFA-635</description> </valueHelp> + <valueHelp> + <format>sdec</format> + <description>Lanner, Watchguard, Nexcom NSA, Sophos UTM appliances</description> + </valueHelp> <constraint> - <regex>^(CFA-533|CFA-631|CFA-633|CFA-635)$</regex> + <regex>^(cfa-533|cfa-631|cfa-633|cfa-635|sdec)$</regex> </constraint> </properties> </leafNode> diff --git a/interface-definitions/vpn_anyconnect.xml.in b/interface-definitions/vpn_anyconnect.xml.in new file mode 100644 index 000000000..e74326986 --- /dev/null +++ b/interface-definitions/vpn_anyconnect.xml.in @@ -0,0 +1,258 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="vpn"> + <children> + <node name="anyconnect" owner="${vyos_conf_scripts_dir}/vpn_anyconnect.py"> + <properties> + <help>SSL VPN AnyConnect</help> + <priority>901</priority> + </properties> + <children> + <node name="authentication"> + <properties> + <help>Authentication for remote access SSL VPN Server</help> + </properties> + <children> + <leafNode name="mode"> + <properties> + <help>Authentication mode used by this server</help> + <valueHelp> + <format>local</format> + <description>Use local username/password configuration</description> + </valueHelp> + <valueHelp> + <format>radius</format> + <description>Use RADIUS server for user autentication</description> + </valueHelp> + <constraint> + <regex>(local|radius)</regex> + </constraint> + <completionHelp> + <list>local radius</list> + </completionHelp> + </properties> + </leafNode> + <node name="local-users"> + <properties> + <help>Local user authentication for SSL VPN server</help> + </properties> + <children> + <tagNode name="username"> + <properties> + <help>User name for authentication</help> + </properties> + <children> + <leafNode name="disable"> + <properties> + <help>Option to disable a SSL VPN Server user</help> + <valueless /> + </properties> + </leafNode> + <leafNode name="password"> + <properties> + <help>Password for authentication</help> + </properties> + </leafNode> + </children> + </tagNode> + </children> + </node> + #include <include/radius-server.xml.i> + <node name="radius"> + <children> + <leafNode name="timeout"> + <properties> + <help>Session timeout</help> + <valueHelp> + <format>1-30</format> + <description>Session timeout in seconds (default: 2)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-30"/> + </constraint> + <constraintErrorMessage>Timeout must be between 1 and 30 seconds</constraintErrorMessage> + </properties> + <defaultValue>2</defaultValue> + </leafNode> + </children> + </node> + </children> + </node> + <node name="listen-ports"> + <properties> + <help>SSL Certificate, SSL Key and CA (/config/auth)</help> + </properties> + <children> + <leafNode name="tcp"> + <properties> + <help>tcp port number to accept connections (default: 443)</help> + <valueHelp> + <format>1-65535</format> + <description>Numeric IP port (default: 443)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>443</defaultValue> + </leafNode> + <leafNode name="udp"> + <properties> + <help>udp port number to accept connections (default: 443)</help> + <valueHelp> + <format>1-65535</format> + <description>Numeric IP port (default: 443)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>443</defaultValue> + </leafNode> + </children> + </node> + <node name="ssl"> + <properties> + <help>SSL Certificate, SSL Key and CA (/config/auth)</help> + </properties> + <children> + <leafNode name="ca-cert-file"> + <properties> + <help>Certificate Authority certificate</help> + <completionHelp> + <script>ls /config/auth</script> + </completionHelp> + <valueHelp> + <format>file</format> + <description>File in /config/auth directory</description> + </valueHelp> + <constraint> + <validator name="file-exists" argument="--directory /config"/> + </constraint> + </properties> + </leafNode> + <leafNode name="cert-file"> + <properties> + <help>Server Certificate</help> + <valueHelp> + <format>file</format> + <description>File in /config/auth directory</description> + </valueHelp> + <constraint> + <validator name="file-exists" argument="--directory /config"/> + </constraint> + </properties> + </leafNode> + <leafNode name="key-file"> + <properties> + <help>Privat Key of the Server Certificate</help> + <valueHelp> + <format>file</format> + <description>File in /config/auth directory</description> + </valueHelp> + <constraint> + <validator name="file-exists" argument="--directory /config"/> + </constraint> + </properties> + </leafNode> + </children> + </node> + <node name="network-settings"> + <properties> + <help>Network settings</help> + </properties> + <children> + <leafNode name="push-route"> + <properties> + <help>Route to be pushed to the client</help> + <valueHelp> + <format>ipv4net</format> + <description>IPv4 network and prefix length</description> + </valueHelp> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 network and prefix length</description> + </valueHelp> + <constraint> + <validator name="ip-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + <node name="client-ip-settings"> + <properties> + <help>Client IP pools settings</help> + </properties> + <children> + <leafNode name="subnet"> + <properties> + <help>Client IP subnet (CIDR notation)</help> + <valueHelp> + <format>ipv4net</format> + <description>IPv4 address and prefix length</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + </constraint> + <constraintErrorMessage>Not a valid CIDR formatted prefix</constraintErrorMessage> + </properties> + </leafNode> + </children> + </node> + <node name="client-ipv6-pool"> + <properties> + <help>Pool of client IPv6 addresses</help> + </properties> + <children> + <leafNode name="prefix"> + <properties> + <help>Pool of addresses used to assign to clients</help> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 address and prefix length</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + </properties> + </leafNode> + <leafNode name="mask"> + <properties> + <help>Prefix length used for individual client</help> + <valueHelp> + <format><48-128></format> + <description>Client prefix length (default: 64)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 48-128"/> + </constraint> + </properties> + <defaultValue>64</defaultValue> + </leafNode> + </children> + </node> + <leafNode name="name-server"> + <properties> + <help>Domain Name Server (DNS) propagated to client</help> + <valueHelp> + <format>ipv4</format> + <description>Domain Name Server (DNS) IPv4 address</description> + </valueHelp> + <valueHelp> + <format>ipv6</format> + <description>Domain Name Server (DNS) IPv6 address</description> + </valueHelp> + <constraint> + <validator name="ipv4-address"/> + <validator name="ipv6-address"/> + </constraint> + <multi/> + </properties> + </leafNode> + </children> + </node> + </children> + </node> + </children> +</node> +</interfaceDefinition> diff --git a/op-mode-definitions/anyconnect.xml b/op-mode-definitions/anyconnect.xml new file mode 100644 index 000000000..7e8cdd35b --- /dev/null +++ b/op-mode-definitions/anyconnect.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="anyconnect-server"> + <properties> + <help>show anyconnect-server information</help> + </properties> + <children> + <leafNode name="sessions"> + <properties> + <help>Show active anyconnect server sessions</help> + </properties> + <command>${vyos_op_scripts_dir}/anyconnect-control.py --action="show_sessions"</command> + </leafNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 36f258301..892495dec 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -901,6 +901,11 @@ class Interface(Control): if isinstance(new_addr, str): new_addr = [new_addr] + # ensure DHCP/DHCPv6 is stopped (when not configured explicitly) + for proto in ['dhcp', 'dhcpv6']: + if proto not in new_addr: + self.del_addr(proto) + # determine IP addresses which are assigned to the interface and build a # list of addresses which are no longer in the dict so they can be removed cur_addr = self.get_addr() diff --git a/src/conf_mode/system_lcd.py b/src/conf_mode/system_lcd.py index 0ad1318f0..31a09252d 100755 --- a/src/conf_mode/system_lcd.py +++ b/src/conf_mode/system_lcd.py @@ -41,6 +41,10 @@ def verify(lcd): if not lcd: return None + if 'model' in lcd and lcd['model'] in ['sdec']: + # This is a fixed LCD display, no device needed - bail out early + return None + if not {'device', 'model'} <= set(lcd): raise ConfigError('Both device and driver must be set!') diff --git a/src/conf_mode/vpn_anyconnect.py b/src/conf_mode/vpn_anyconnect.py new file mode 100755 index 000000000..45c06bffa --- /dev/null +++ b/src/conf_mode/vpn_anyconnect.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018-2020 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 os +from sys import exit + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.xml import defaults +from vyos.template import render +from vyos.util import call +from vyos import ConfigError +from crypt import crypt, mksalt, METHOD_SHA512 + +from vyos import airbag +airbag.enable() + +cfg_dir = '/run/ocserv' +ocserv_conf = cfg_dir + '/ocserv.conf' +ocserv_passwd = cfg_dir + '/ocpasswd' +radius_cfg = cfg_dir + '/radiusclient.conf' +radius_servers = cfg_dir + '/radius_servers' + + +# Generate hash from user cleartext password +def get_hash(password): + return crypt(password, mksalt(METHOD_SHA512)) + + +def get_config(): + conf = Config() + base = ['vpn', 'anyconnect'] + ocserv = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + default_values = defaults(base) + ocserv = dict_merge(default_values, ocserv) + return ocserv + + +def verify(ocserv): + if ocserv is None: + return None + + # Check authentication + if "authentication" in ocserv: + if "mode" in ocserv["authentication"]: + if "local" in ocserv["authentication"]["mode"]: + if not ocserv["authentication"]["local_users"] or not ocserv["authentication"]["local_users"]["username"]: + raise ConfigError('Anyconect mode local required at leat one user') + else: + for user in ocserv["authentication"]["local_users"]["username"]: + if not "password" in ocserv["authentication"]["local_users"]["username"][user]: + raise ConfigError(f'password required for user {user}') + else: + raise ConfigError('anyconnect authentication mode required') + else: + raise ConfigError('anyconnect authentication credentials required') + + # Check ssl + if "ssl" in ocserv: + req_cert = ['ca_cert_file', 'cert_file', 'key_file'] + for cert in req_cert: + if not cert in ocserv["ssl"]: + raise ConfigError('anyconnect ssl {0} required'.format(cert.replace('_', '-'))) + else: + raise ConfigError('anyconnect ssl required') + + # Check network settings + if "network_settings" in ocserv: + if "push_route" in ocserv["network_settings"]: + # Replace default route + if "0.0.0.0/0" in ocserv["network_settings"]["push_route"]: + ocserv["network_settings"]["push_route"].remove("0.0.0.0/0") + ocserv["network_settings"]["push_route"].append("default") + else: + ocserv["network_settings"]["push_route"] = "default" + else: + raise ConfigError('anyconnect network settings required') + + +def generate(ocserv): + if not ocserv: + return None + + if "radius" in ocserv["authentication"]["mode"]: + # Render radius client configuration + render(radius_cfg, 'ocserv/radius_conf.tmpl', ocserv["authentication"]["radius"], trim_blocks=True) + # Render radius servers + render(radius_servers, 'ocserv/radius_servers.tmpl', ocserv["authentication"]["radius"], trim_blocks=True) + else: + if "local_users" in ocserv["authentication"]: + for user in ocserv["authentication"]["local_users"]["username"]: + ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"]) + # Render local users + render(ocserv_passwd, 'ocserv/ocserv_passwd.tmpl', ocserv["authentication"]["local_users"], trim_blocks=True) + + # Render config + render(ocserv_conf, 'ocserv/ocserv_config.tmpl', ocserv, trim_blocks=True) + + + +def apply(ocserv): + if not ocserv: + call('systemctl stop ocserv.service') + for file in [ocserv_conf, ocserv_passwd]: + if os.path.exists(file): + os.unlink(file) + else: + call('systemctl restart ocserv.service') + + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) diff --git a/src/etc/systemd/system/ocserv.service.d/override.conf b/src/etc/systemd/system/ocserv.service.d/override.conf new file mode 100644 index 000000000..89dbb153f --- /dev/null +++ b/src/etc/systemd/system/ocserv.service.d/override.conf @@ -0,0 +1,14 @@ +[Unit] +RequiresMountsFor=/run +ConditionPathExists=/run/ocserv/ocserv.conf +After= +After=vyos-router.service +After=dbus.service + +[Service] +WorkingDirectory=/run/ocserv +PIDFile= +PIDFile=/run/ocserv/ocserv.pid +ExecStart= +ExecStart=/usr/sbin/ocserv --foreground --pid-file /run/ocserv/ocserv.pid --config /run/ocserv/ocserv.conf + diff --git a/src/op_mode/anyconnect-control.py b/src/op_mode/anyconnect-control.py new file mode 100755 index 000000000..6382016b7 --- /dev/null +++ b/src/op_mode/anyconnect-control.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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 argparse +import json + +from vyos.config import Config +from vyos.util import popen, run, DEVNULL +from tabulate import tabulate + +occtl = '/usr/bin/occtl' +occtl_socket = '/run/ocserv/occtl.socket' + +def show_sessions(): + out, code = popen("sudo {0} -j -s {1} show users".format(occtl, occtl_socket),stderr=DEVNULL) + if code: + sys.exit('Cannot get anyconnect users information') + else: + headers = ["interface", "username", "ip", "remote IP", "RX", "TX", "state", "uptime"] + sessions = json.loads(out) + ses_list = [] + for ses in sessions: + ses_list.append([ses["Device"], ses["Username"], ses["IPv4"], ses["Remote IP"], ses["_RX"], ses["_TX"], ses["State"], ses["_Connected at"]]) + if len(ses_list) > 0: + print(tabulate(ses_list, headers)) + else: + print("No active anyconnect sessions") + +def is_ocserv_configured(): + if not Config().exists_effective('vpn anyconnect'): + print("vpn anyconnect server is not configured") + sys.exit(1) + +def main(): + #parese args + parser = argparse.ArgumentParser() + parser.add_argument('--action', help='Control action', required=True) + parser.add_argument('--selector', help='Selector username|ifname|sid', required=False) + parser.add_argument('--target', help='Target must contain username|ifname|sid', required=False) + args = parser.parse_args() + + + # Check is IPoE configured + is_ocserv_configured() + + if args.action == "restart": + run("systemctl restart ocserv") + sys.exit(0) + elif args.action == "show_sessions": + show_sessions() + +if __name__ == '__main__': + main() diff --git a/src/systemd/lcdproc.service b/src/systemd/lcdproc.service index 5aa99ec78..ef717667a 100644 --- a/src/systemd/lcdproc.service +++ b/src/systemd/lcdproc.service @@ -1,8 +1,8 @@ [Unit] Description=LCDproc system status information viewer on %I Documentation=man:lcdproc(8) http://www.lcdproc.org/ -After=vyos-router.service -After=LCDd.service +After=vyos-router.service LCDd.service +Requires=LCDd.service [Service] User=root |