From 415e572dfba776a981e2ec1e4331c30cd5cb59f3 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Wed, 11 Aug 2021 04:06:19 -0500 Subject: openvpn: T3736: openvpn-option keeps and adds double dashes (--) --- data/templates/openvpn/server.conf.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index d9f01310e..0968a18ba 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -225,7 +225,7 @@ auth-retry nointeract {% for option in openvpn_option %} {% for argument in option.split('--') %} {% if argument is defined and argument != '' %} ---{{ argument }} +{{ argument }} {% endif %} {% endfor %} {% endfor %} -- cgit v1.2.3 From 6748dbe0100cfedf1b2f00884899e71729bfa9f3 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Tue, 17 Aug 2021 07:04:34 -0500 Subject: add part 2fa --- data/templates/openvpn/server.conf.tmpl | 11 ++++++ interface-definitions/interfaces-openvpn.xml.in | 47 +++++++++++++++++++++++++ src/conf_mode/interfaces-openvpn.py | 25 +++++++++++-- 3 files changed, 80 insertions(+), 3 deletions(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 0968a18ba..91f8d7515 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -127,6 +127,14 @@ push "dhcp-option DNS6 {{ nameserver }}" {% if server.domain_name is defined and server.domain_name is not none %} push "dhcp-option DOMAIN {{ server.domain_name }}" {% endif %} +{% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} +plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/otp-secrets otp_slop= +{{- server['2fa']['totp']['slop']|default(180) }} totp_t0= +{{- server['2fa']['totp']['t0']|default(0) }} totp_step= +{{- server['2fa']['totp']['step']|default(30) }} totp_digits= +{{- server['2fa']['totp']['digits']|default(6)}} password_is_cr= +{%-if server['2fa']['totp']['challenge']|default('enabled') == 'enabled' %}1{% else %}0{% endif %}" +{% endif %} {% endif %} {% else %} # @@ -218,6 +226,9 @@ auth-user-pass {{ auth_user_pass_file }} auth-retry nointeract {% endif %} + +{% if openvpn_option is defined and openvpn_option is not none %} + {% if openvpn_option is defined and openvpn_option is not none %} # # Custom options added by user (not validated) diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in index 7ff08ac86..1a07e7d91 100644 --- a/interface-definitions/interfaces-openvpn.xml.in +++ b/interface-definitions/interfaces-openvpn.xml.in @@ -635,6 +635,53 @@ net30 + + + 2-factor authentication + + + + + Time-based One-Time Passwords + + + + + Maximum allowed clock slop in seconds (default: 180) + + 180 + + + + time drift in seconds (default: 0) + + 0 + + + + Step value for TOTP in seconds (default: 30) + + 30 + + + + Number of digits to use from TOTP hash (default: 6) + + 6 + + + + expect password as result of a challenge response protocol (default: enabled) + + ^(enable|disable)$ + + + enable + + + + + diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 74e29ed82..f19804910 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -25,7 +25,9 @@ from ipaddress import IPv4Network from ipaddress import IPv6Address from ipaddress import IPv6Network from ipaddress import summarize_address_range +from pathlib import Path from netifaces import interfaces +from secrets import SystemRandom from shutil import rmtree from vyos.config import Config @@ -309,9 +311,9 @@ def verify(openvpn): raise ConfigError('Must specify "server subnet" or add interface to bridge in server mode') - for client in (dict_search('client', openvpn) or []): - if len(client['ip']) > 1 or len(client['ipv6_ip']) > 1: - raise ConfigError(f'Server client "{client["name"]}": cannot specify more than 1 IPv4 and 1 IPv6 IP') + for client_k, client_v in (dict_search('server.client', openvpn).items() or []): + if (client_v.get('ip') and len(client_v['ip']) > 1) or (client_v.get('ipv6_ip') and len(client_v['ipv6_ip']) > 1): + raise ConfigError(f'Server client "{client_k}": cannot specify more than 1 IPv4 and 1 IPv6 IP') if dict_search('server.client_ip_pool', openvpn): if not (dict_search('server.client_ip_pool.start', openvpn) and dict_search('server.client_ip_pool.stop', openvpn)): @@ -359,6 +361,23 @@ def verify(openvpn): if IPv6Address(client['ipv6_ip'][0]) in v6PoolNet: print(f'Warning: Client "{client["name"]}" IP {client["ipv6_ip"][0]} is in server IP pool, it is not reserved for this client.') + if dict_search('server.2fa.totp', openvpn): + if not Path(otp_file).is_file(): + Path(otp_file).touch() + for client in (dict_search('server.client', openvpn) or []): + with open(otp_file, "r+") as f: + users = f.readlines() + exists = None + for user in users: + if re.search('^' + client + ' ', user): + exists = 'true' + + if not exists: + random = SystemRandom() + totp_secret = ''.join(random.choice(secret_chars) for _ in range(16)) + f.write("{0} otp totp:sha1:base32:{1}::xxx *\n".format(client, totp_secret)) + + else: # checks for both client and site-to-site go here if dict_search('server.reject_unconfigured_clients', openvpn): -- cgit v1.2.3 From 87ee779a977e6b643d4131eb5d89b1264c3bdf55 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Thu, 2 Sep 2021 06:02:43 -0500 Subject: add 2fa op files and update template --- data/templates/openvpn/server.conf.tmpl | 3 -- src/completion/list_openvpn_users.py | 48 +++++++++++++++++++++++++ src/op_mode/show_openvpn_2fa.py | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100755 src/completion/list_openvpn_users.py create mode 100755 src/op_mode/show_openvpn_2fa.py (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 91f8d7515..4c5dbc2c5 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -226,9 +226,6 @@ auth-user-pass {{ auth_user_pass_file }} auth-retry nointeract {% endif %} - -{% if openvpn_option is defined and openvpn_option is not none %} - {% if openvpn_option is defined and openvpn_option is not none %} # # Custom options added by user (not validated) diff --git a/src/completion/list_openvpn_users.py b/src/completion/list_openvpn_users.py new file mode 100755 index 000000000..c472dbeab --- /dev/null +++ b/src/completion/list_openvpn_users.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019-2021 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 os +import sys +import argparse + +from vyos.config import Config +from vyos.util import dict_search + +def get_user_from_interface(interface): + config = Config() + base = ['interfaces', 'openvpn', interface] + openvpn = config.get_config_dict(base, effective=True, key_mangling=('-', '_')) + users = [] + + try: + for user in (dict_search('server.client', openvpn[interface]) or []): + users.append(user.split(',')[0]) + except: + pass + + return users + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--interface", type=str, help="List users per interface") + args = parser.parse_args() + + users = [] + + users = get_user_from_interface(args.interface) + + print(" ".join(users)) + diff --git a/src/op_mode/show_openvpn_2fa.py b/src/op_mode/show_openvpn_2fa.py new file mode 100755 index 000000000..8600f755d --- /dev/null +++ b/src/op_mode/show_openvpn_2fa.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Copyright 2017, 2021 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +import re +import socket +import urllib.parse +import argparse + +from vyos.util import popen + +otp_file = '/config/auth/openvpn/{interface}-otp-secrets' + +def get_2fa_secret(interface, client): + try: + with open(otp_file.format(interface=interface), "r") as f: + users = f.readlines() + for user in users: + if re.search('^' + client + ' ', user): + return user.split(':')[3] + except: + pass + +def get_2fa_uri(client, secret): + hostname = socket.gethostname() + fqdn = socket.getfqdn() + uri = 'otpauth://totp/{hostname}:{client}@{fqdn}?secret={secret}' + + return urllib.parse.quote(uri.format(hostname=hostname, client=client, fqdn=fqdn, secret=secret), safe='/:@?=') + +if __name__ == '__main__': + parser = argparse.ArgumentParser(add_help=False, description='Show 2fa information') + parser.add_argument('--intf', action="store", type=str, default='', help='only show the specified interface') + parser.add_argument('--user', action="store", type=str, default='', help='only show the specified users') + parser.add_argument('--action', action="store", type=str, default='show', help='action to perform') + + args = parser.parse_args() + secret = get_2fa_secret(args.intf, args.user) + + if args.action == "secret" and secret: + print(secret) + + if args.action == "uri" and secret: + uri = get_2fa_uri(args.user, secret) + print(uri) + + if args.action == "qrcode" and secret: + uri = get_2fa_uri(args.user, secret) + qrcode,err = popen('qrencode -t ansiutf8', input=uri) + print(qrcode) + -- cgit v1.2.3 From 65b55f35f836185ffbf589c5ea5a6ee89568957e Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 3 Sep 2021 03:23:28 -0500 Subject: fix file location and use correct variable --- data/templates/openvpn/server.conf.tmpl | 2 +- src/conf_mode/interfaces-openvpn.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 4c5dbc2c5..e6dd9fcbc 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -133,7 +133,7 @@ plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/ {{- server['2fa']['totp']['t0']|default(0) }} totp_step= {{- server['2fa']['totp']['step']|default(30) }} totp_digits= {{- server['2fa']['totp']['digits']|default(6)}} password_is_cr= -{%-if server['2fa']['totp']['challenge']|default('enabled') == 'enabled' %}1{% else %}0{% endif %}" +{%-if server['2fa']['totp']['challenge']|default('enable') == 'enable' %}1{% else %}0{% endif %}" {% endif %} {% endif %} {% else %} diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 194126a34..365d0982e 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -381,7 +381,7 @@ def verify(openvpn): for client in (dict_search('server.client', openvpn) or []): exists = None for ovpn_user in ovpn_users: - if re.search('^' + client + ' ', user): + if re.search('^' + client + ' ', ovpn_user): fp.write(ovpn_user) exists = 'true' -- cgit v1.2.3 From 2a27f35ea595a86a37fce093574c015dd7add2d9 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 3 Sep 2021 04:20:56 -0500 Subject: change secret file location in template --- data/templates/openvpn/server.conf.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index e6dd9fcbc..1348912b3 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -128,7 +128,7 @@ push "dhcp-option DNS6 {{ nameserver }}" push "dhcp-option DOMAIN {{ server.domain_name }}" {% endif %} {% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} -plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/otp-secrets otp_slop= +plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= {{- server['2fa']['totp']['slop']|default(180) }} totp_t0= {{- server['2fa']['totp']['t0']|default(0) }} totp_step= {{- server['2fa']['totp']['step']|default(30) }} totp_digits= -- cgit v1.2.3 From cfebb0b01c37e92503aeb88bca42fa18f6927814 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 3 Sep 2021 04:31:36 -0500 Subject: fix configure error if 2fa is defined but no option is defined --- data/templates/openvpn/server.conf.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 1348912b3..679c25dd8 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -127,13 +127,15 @@ push "dhcp-option DNS6 {{ nameserver }}" {% if server.domain_name is defined and server.domain_name is not none %} push "dhcp-option DOMAIN {{ server.domain_name }}" {% endif %} -{% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} +{% if server['2fa'] is defined and server['2fa'] is not none %} +{% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= {{- server['2fa']['totp']['slop']|default(180) }} totp_t0= {{- server['2fa']['totp']['t0']|default(0) }} totp_step= {{- server['2fa']['totp']['step']|default(30) }} totp_digits= {{- server['2fa']['totp']['digits']|default(6)}} password_is_cr= {%-if server['2fa']['totp']['challenge']|default('enable') == 'enable' %}1{% else %}0{% endif %}" +{% endif %} {% endif %} {% endif %} {% else %} -- cgit v1.2.3 From 5366f9c9ce9850cdf3fddbf0c2947994a0c7eef6 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 3 Sep 2021 06:00:07 -0500 Subject: do not use capitals in opmode rename t0 to drift add subnemu for 2fa to make it more readable --- data/templates/openvpn/server.conf.tmpl | 2 +- interface-definitions/interfaces-openvpn.xml.in | 2 +- op-mode-definitions/openvpn.xml.in | 39 +++++++++++++++---------- 3 files changed, 25 insertions(+), 18 deletions(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 679c25dd8..d97ff7717 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -131,7 +131,7 @@ push "dhcp-option DOMAIN {{ server.domain_name }}" {% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= {{- server['2fa']['totp']['slop']|default(180) }} totp_t0= -{{- server['2fa']['totp']['t0']|default(0) }} totp_step= +{{- server['2fa']['totp']['drift']|default(0) }} totp_step= {{- server['2fa']['totp']['step']|default(30) }} totp_digits= {{- server['2fa']['totp']['digits']|default(6)}} password_is_cr= {%-if server['2fa']['totp']['challenge']|default('enable') == 'enable' %}1{% else %}0{% endif %}" diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in index 0395f7d65..62fac9be0 100644 --- a/interface-definitions/interfaces-openvpn.xml.in +++ b/interface-definitions/interfaces-openvpn.xml.in @@ -657,7 +657,7 @@ - + time drift in seconds (default: 0) diff --git a/op-mode-definitions/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in index 6549976c5..068d5d8fb 100644 --- a/op-mode-definitions/openvpn.xml.in +++ b/op-mode-definitions/openvpn.xml.in @@ -63,24 +63,31 @@ - + - Show 2fa authentication secret + Show 2fa information - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=secret - - - - Show 2fa otpauth uri - - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=uri - - - - Show 2fa QR code - - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=qrcode - + + + + Show 2fa authentication secret + + ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=secret + + + + Show 2fa otpauth uri + + ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=uri + + + + Show 2fa QR code + + ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=qrcode + + + -- cgit v1.2.3 From 024839cb1588964da46f198976053b7d78b8e9a0 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 17 Sep 2021 05:16:07 -0500 Subject: update the location of the openvpn-otp.so plugin --- data/templates/openvpn/server.conf.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index d97ff7717..b53361710 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -129,7 +129,7 @@ push "dhcp-option DOMAIN {{ server.domain_name }}" {% endif %} {% if server['2fa'] is defined and server['2fa'] is not none %} {% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} -plugin "/usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= +plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= {{- server['2fa']['totp']['slop']|default(180) }} totp_t0= {{- server['2fa']['totp']['drift']|default(0) }} totp_step= {{- server['2fa']['totp']['step']|default(30) }} totp_digits= -- cgit v1.2.3 From eb7f8904076e749e18c10b6374bf363dfa009c19 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Fri, 17 Sep 2021 05:18:53 -0500 Subject: Revert "openvpn: T3736: openvpn-option keeps and adds double dashes (--)" This reverts commit 415e572dfba776a981e2ec1e4331c30cd5cb59f3. --- data/templates/openvpn/server.conf.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index b53361710..644eb805f 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -235,7 +235,7 @@ auth-retry nointeract {% for option in openvpn_option %} {% for argument in option.split('--') %} {% if argument is defined and argument != '' %} -{{ argument }} +--{{ argument }} {% endif %} {% endfor %} {% endfor %} -- cgit v1.2.3 From 74a8c4b42b5ad31cdf34ddea07f83f7bff86be87 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 4 Oct 2021 22:25:19 +0200 Subject: bgp: T3741: "parameter default no-ipv4-unicast" is now a default option --- data/templates/frr/bgpd.frr.tmpl | 2 - .../include/bgp/protocol-common-config.xml.i | 6 -- smoketest/configs/bgp-small-ipv4-unicast | 77 ++++++++++++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 3 - src/migration-scripts/bgp/1-to-2 | 77 ++++++++++++++++++++++ 5 files changed, 154 insertions(+), 11 deletions(-) create mode 100644 smoketest/configs/bgp-small-ipv4-unicast create mode 100755 src/migration-scripts/bgp/1-to-2 (limited to 'data/templates') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 27a2b98a5..a35930c93 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -230,10 +230,8 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% else %} no bgp ebgp-requires-policy {% endif %} -{% if parameters is defined and parameters.default is defined and parameters.default.no_ipv4_unicast is defined %} {# Option must be set before any neighbor - see https://phabricator.vyos.net/T3463 #} no bgp default ipv4-unicast -{% endif %} {# Workaround for T2100 until we have decided about a migration script #} no bgp network import-check {% if address_family is defined and address_family is not none %} diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 30033bc50..2dfae517e 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -1253,12 +1253,6 @@ - - - Deactivate IPv4 unicast for a peer by default - - - diff --git a/smoketest/configs/bgp-small-ipv4-unicast b/smoketest/configs/bgp-small-ipv4-unicast new file mode 100644 index 000000000..a4dcd6218 --- /dev/null +++ b/smoketest/configs/bgp-small-ipv4-unicast @@ -0,0 +1,77 @@ +interfaces { + ethernet eth0 { + address 192.0.2.1 + address 2001:db8::1/64 + } + loopback lo { + } +} +protocols { + bgp 65001 { + address-family { + ipv4-unicast { + network 10.0.150.0/23 { + } + } + ipv6-unicast { + network 2001:db8:200::/40 { + } + } + } + neighbor 192.0.2.10 { + remote-as 65010 + } + neighbor 192.0.2.11 { + remote-as 65011 + } + neighbor 2001:db8::10 { + remote-as 65010 + } + neighbor 2001:db8::11 { + remote-as 65011 + } + parameters { + log-neighbor-changes + } + } +} +service { + ssh { + disable-host-validation + port 22 + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + domain-name vyos.net + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + syslog { + global { + facility all { + level notice + } + facility protocols { + level debug + } + } + } +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@9:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.5 */ diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 29b5aa9d1..16284ed01 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -221,8 +221,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): # Default local preference (higher = more preferred, default value is 100) self.cli_set(base_path + ['parameters', 'default', 'local-pref', local_pref]) - # Deactivate IPv4 unicast for a peer by default - self.cli_set(base_path + ['parameters', 'default', 'no-ipv4-unicast']) self.cli_set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time]) self.cli_set(base_path + ['parameters', 'graceful-shutdown']) self.cli_set(base_path + ['parameters', 'ebgp-requires-policy']) @@ -246,7 +244,6 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' bgp router-id {router_id}', frrconfig) self.assertIn(f' bgp log-neighbor-changes', frrconfig) self.assertIn(f' bgp default local-preference {local_pref}', frrconfig) - self.assertIn(f' no bgp default ipv4-unicast', frrconfig) self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig) self.assertIn(f' bgp graceful-shutdown', frrconfig) self.assertIn(f' bgp bestpath as-path multipath-relax', frrconfig) diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2 new file mode 100755 index 000000000..4c6d5ceb8 --- /dev/null +++ b/src/migration-scripts/bgp/1-to-2 @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 . + +# T3741: no-ipv4-unicast is now enabled by default + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.template import is_ipv4 + +if (len(argv) < 1): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'bgp'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +# This is now a default option - simply delete it. +# As it was configured explicitly - we can also bail out early as we need to +# do nothing! +if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']): + config.delete(base + ['parameters', 'default', 'no-ipv4-unicast']) + + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters', 'default'])) == 0: + config.delete(base + ['parameters', 'default']) + + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters'])) == 0: + config.delete(base + ['parameters']) + + exit(0) + +# As we now install a new default option into BGP we need to migrate all +# existing BGP neighbors and restore the old behavior +if config.exists(base + ['neighbor']): + for neighbor in config.list_nodes(base + ['neighbor']): + peer_group = base + ['neighbor', neighbor, 'peer-group'] + if config.exists(peer_group): + peer_group_name = config.return_value(peer_group) + # peer group enables old behavior for neighbor - bail out + if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']): + continue + + afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast'] + if not config.exists(afi_ipv4): + config.set(afi_ipv4) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + exit(1) -- cgit v1.2.3 From ba8630da96396f09c638fccdc9cfe6a3ee70fd58 Mon Sep 17 00:00:00 2001 From: Kim Hagen Date: Thu, 7 Oct 2021 08:44:00 -0500 Subject: pull request fixes --- data/templates/openvpn/server.conf.tmpl | 12 ++--- interface-definitions/interfaces-openvpn.xml.in | 23 +++++---- op-mode-definitions/openvpn.xml.in | 16 +++---- src/conf_mode/interfaces-openvpn.py | 18 ++++++- src/op_mode/show_openvpn_2fa.py | 64 ------------------------- src/op_mode/show_openvpn_mfa.py | 64 +++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 91 deletions(-) delete mode 100755 src/op_mode/show_openvpn_2fa.py create mode 100755 src/op_mode/show_openvpn_mfa.py (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 644eb805f..3104203ad 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -127,14 +127,10 @@ push "dhcp-option DNS6 {{ nameserver }}" {% if server.domain_name is defined and server.domain_name is not none %} push "dhcp-option DOMAIN {{ server.domain_name }}" {% endif %} -{% if server['2fa'] is defined and server['2fa'] is not none %} -{% if server['2fa']['totp'] is defined and server['2fa']['totp'] is not none %} -plugin "/usr/lib/openvpn/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets otp_slop= -{{- server['2fa']['totp']['slop']|default(180) }} totp_t0= -{{- server['2fa']['totp']['drift']|default(0) }} totp_step= -{{- server['2fa']['totp']['step']|default(30) }} totp_digits= -{{- server['2fa']['totp']['digits']|default(6)}} password_is_cr= -{%-if server['2fa']['totp']['challenge']|default('enable') == 'enable' %}1{% else %}0{% endif %}" +{% if server.mfa is defined and server.mfa is not none %} +{% if server.mfa.totp is defined and server.mfa.totp is not none %} +{% set totp_config = server.mfa.totp %} +plugin "{{ plugin_dir}}/openvpn-otp.so" "otp_secrets=/config/auth/openvpn/{{ ifname }}-otp-secrets {{ 'otp_slop=' ~ totp_config.slop }} {{ 'totp_t0=' ~ totp_config.drift }} {{ 'totp_step=' ~ totp_config.step }} {{ 'totp_digits=' ~ totp_config.digits }} password_is_cr={{ '1' if totp_config.challenge == 'enable' else '0' }}" {% endif %} {% endif %} {% endif %} diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in index 62fac9be0..023f9f55d 100644 --- a/interface-definitions/interfaces-openvpn.xml.in +++ b/interface-definitions/interfaces-openvpn.xml.in @@ -635,14 +635,14 @@ net30 - + - 2-factor authentication + multi-factor authentication - Time-based One-Time Passwords + Time-based one-time passwords @@ -656,10 +656,11 @@ + 180 - time drift in seconds (default: 0) + Time drift in seconds (default: 0) 1-65535 Seconds @@ -668,10 +669,11 @@ + 0 - Step value for TOTP in seconds (default: 30) + Step value for totp in seconds (default: 30) 1-65535 Seconds @@ -680,10 +682,11 @@ + 30 - Number of digits to use from TOTP hash (default: 6) + Number of digits to use for totp hash (default: 6) 1-65535 Seconds @@ -692,25 +695,27 @@ + 6 - expect password as result of a challenge response protocol (default: enabled) + Expect password as result of a challenge response protocol (default: enabled) disable enable disable - Disable challenge response (default) + Disable challenge-response enable - Enable chalenge response (default) + Enable chalenge-response (default) ^(disable|enable)$ + enable diff --git a/op-mode-definitions/openvpn.xml.in b/op-mode-definitions/openvpn.xml.in index 068d5d8fb..7243d69fd 100644 --- a/op-mode-definitions/openvpn.xml.in +++ b/op-mode-definitions/openvpn.xml.in @@ -63,28 +63,28 @@ - + - Show 2fa information + Show multi-factor authentication information - Show 2fa authentication secret + Show multi-factor authentication secret - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=secret + ${vyos_op_scripts_dir}/show_openvpn_mfa.py --user="$6" --intf="$4" --action=secret - Show 2fa otpauth uri + Show multi-factor authentication otpauth uri - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=uri + ${vyos_op_scripts_dir}/show_openvpn_mfa.py --user="$6" --intf="$4" --action=uri - Show 2fa QR code + Show multi-factor authentication QR code - ${vyos_op_scripts_dir}/show_openvpn_2fa.py --user="$6" --intf="$4" --action=qrcode + ${vyos_op_scripts_dir}/show_openvpn_mfa.py --user="$6" --intf="$4" --action=qrcode diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 365d0982e..220c4f157 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -80,6 +80,11 @@ def get_config(config=None): tmp_pki = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) + # We have to get the dict using 'get_config_dict' instead of 'get_interface_dict' + # as 'get_interface_dict' merges the defaults in, so we can not check for defaults in there. + tmp_openvpn = conf.get_config_dict(base + [os.environ['VYOS_TAGNODE_VALUE']], key_mangling=('-', '_'), + get_first_key=True, no_tag_node_value_mangle=True) + openvpn = get_interface_dict(conf, base) if 'deleted' not in openvpn: @@ -89,6 +94,14 @@ def get_config(config=None): openvpn['daemon_user'] = user openvpn['daemon_group'] = group + # We have to cleanup the config dict, as default values could enable features + # which are not explicitly enabled on the CLI. Example: server mfa totp + # originate comes with defaults, which will enable the + # totp plugin, even when not set via CLI so we + # need to check this first and drop those keys + if 'totp' not in tmp_openvpn['server']: + del openvpn['server']['mfa']['totp'] + return openvpn def is_ec_private_key(pki, cert_name): @@ -369,8 +382,8 @@ def verify(openvpn): if IPv6Address(client['ipv6_ip'][0]) in v6PoolNet: print(f'Warning: Client "{client["name"]}" IP {client["ipv6_ip"][0]} is in server IP pool, it is not reserved for this client.') - # add 2fa users to the file the 2fa plugin uses - if dict_search('server.2fa.totp', openvpn): + # add mfa users to the file the mfa plugin uses + if dict_search('server.mfa.totp', openvpn): if not Path(otp_file.format(**openvpn)).is_file(): Path(otp_path).mkdir(parents=True, exist_ok=True) Path(otp_file.format(**openvpn)).touch() @@ -590,6 +603,7 @@ def generate_pki_files(openvpn): def generate(openvpn): interface = openvpn['ifname'] directory = os.path.dirname(cfg_file.format(**openvpn)) + plugin_dir = '/usr/lib/openvpn' # we can't know in advance which clients have been removed, # thus all client configs will be removed and re-added on demand diff --git a/src/op_mode/show_openvpn_2fa.py b/src/op_mode/show_openvpn_2fa.py deleted file mode 100755 index 8600f755d..000000000 --- a/src/op_mode/show_openvpn_2fa.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2017, 2021 VyOS maintainers and contributors -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see . - -import re -import socket -import urllib.parse -import argparse - -from vyos.util import popen - -otp_file = '/config/auth/openvpn/{interface}-otp-secrets' - -def get_2fa_secret(interface, client): - try: - with open(otp_file.format(interface=interface), "r") as f: - users = f.readlines() - for user in users: - if re.search('^' + client + ' ', user): - return user.split(':')[3] - except: - pass - -def get_2fa_uri(client, secret): - hostname = socket.gethostname() - fqdn = socket.getfqdn() - uri = 'otpauth://totp/{hostname}:{client}@{fqdn}?secret={secret}' - - return urllib.parse.quote(uri.format(hostname=hostname, client=client, fqdn=fqdn, secret=secret), safe='/:@?=') - -if __name__ == '__main__': - parser = argparse.ArgumentParser(add_help=False, description='Show 2fa information') - parser.add_argument('--intf', action="store", type=str, default='', help='only show the specified interface') - parser.add_argument('--user', action="store", type=str, default='', help='only show the specified users') - parser.add_argument('--action', action="store", type=str, default='show', help='action to perform') - - args = parser.parse_args() - secret = get_2fa_secret(args.intf, args.user) - - if args.action == "secret" and secret: - print(secret) - - if args.action == "uri" and secret: - uri = get_2fa_uri(args.user, secret) - print(uri) - - if args.action == "qrcode" and secret: - uri = get_2fa_uri(args.user, secret) - qrcode,err = popen('qrencode -t ansiutf8', input=uri) - print(qrcode) - diff --git a/src/op_mode/show_openvpn_mfa.py b/src/op_mode/show_openvpn_mfa.py new file mode 100755 index 000000000..1ab54600c --- /dev/null +++ b/src/op_mode/show_openvpn_mfa.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# Copyright 2017, 2021 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +import re +import socket +import urllib.parse +import argparse + +from vyos.util import popen + +otp_file = '/config/auth/openvpn/{interface}-otp-secrets' + +def get_mfa_secret(interface, client): + try: + with open(otp_file.format(interface=interface), "r") as f: + users = f.readlines() + for user in users: + if re.search('^' + client + ' ', user): + return user.split(':')[3] + except: + pass + +def get_mfa_uri(client, secret): + hostname = socket.gethostname() + fqdn = socket.getfqdn() + uri = 'otpauth://totp/{hostname}:{client}@{fqdn}?secret={secret}' + + return urllib.parse.quote(uri.format(hostname=hostname, client=client, fqdn=fqdn, secret=secret), safe='/:@?=') + +if __name__ == '__main__': + parser = argparse.ArgumentParser(add_help=False, description='Show two-factor authentication information') + parser.add_argument('--intf', action="store", type=str, default='', help='only show the specified interface') + parser.add_argument('--user', action="store", type=str, default='', help='only show the specified users') + parser.add_argument('--action', action="store", type=str, default='show', help='action to perform') + + args = parser.parse_args() + secret = get_mfa_secret(args.intf, args.user) + + if args.action == "secret" and secret: + print(secret) + + if args.action == "uri" and secret: + uri = get_mfa_uri(args.user, secret) + print(uri) + + if args.action == "qrcode" and secret: + uri = get_mfa_uri(args.user, secret) + qrcode,err = popen('qrencode -t ansiutf8', input=uri) + print(qrcode) + -- cgit v1.2.3 From 699d4533c543f2578c68f1d3ca9f2a2b8d5c4692 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 8 Sep 2021 14:35:20 +0200 Subject: openvpn: T3805: drop privileges using systemd - required for rtnetlink --- data/templates/openvpn/server.conf.tmpl | 2 -- src/conf_mode/interfaces-openvpn.py | 2 -- src/etc/systemd/system/openvpn@.service.d/override.conf | 4 ++++ 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'data/templates') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 3104203ad..5c78d998e 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -7,8 +7,6 @@ # verb 3 -user {{ daemon_user }} -group {{ daemon_group }} dev-type {{ device_type }} dev {{ ifname }} persist-key diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 94fb14246..d57ccb354 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -92,8 +92,6 @@ def get_config(config=None): openvpn['pki'] = tmp_pki openvpn['auth_user_pass_file'] = '/run/openvpn/{ifname}.pw'.format(**openvpn) - openvpn['daemon_user'] = user - openvpn['daemon_group'] = group # We have to cleanup the config dict, as default values could enable features # which are not explicitly enabled on the CLI. Example: server mfa totp diff --git a/src/etc/systemd/system/openvpn@.service.d/override.conf b/src/etc/systemd/system/openvpn@.service.d/override.conf index 7946484a3..03fe6b587 100644 --- a/src/etc/systemd/system/openvpn@.service.d/override.conf +++ b/src/etc/systemd/system/openvpn@.service.d/override.conf @@ -7,3 +7,7 @@ WorkingDirectory= WorkingDirectory=/run/openvpn ExecStart= ExecStart=/usr/sbin/openvpn --daemon openvpn-%i --config %i.conf --status %i.status 30 --writepid %i.pid +User=openvpn +Group=openvpn +AmbientCapabilities=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_AUDIT_WRITE +CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_AUDIT_WRITE -- cgit v1.2.3 From 4218a5bcb1093108e25d4e07fa07050b4f79d3d5 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 10 Oct 2021 18:53:02 +0200 Subject: lcd: T2564: add support for hd44780 displays --- data/templates/lcd/LCDd.conf.tmpl | 7 +++++++ debian/control | 1 + interface-definitions/system-lcd.xml.in | 8 ++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'data/templates') diff --git a/data/templates/lcd/LCDd.conf.tmpl b/data/templates/lcd/LCDd.conf.tmpl index 6cf6a440f..2c7ad920f 100644 --- a/data/templates/lcd/LCDd.conf.tmpl +++ b/data/templates/lcd/LCDd.conf.tmpl @@ -53,6 +53,8 @@ DriverPath=/usr/lib/x86_64-linux-gnu/lcdproc/ Driver=CFontzPacket {% elif model == 'sdec' %} Driver=sdeclcd +{% elif model == 'hd44780' %} +Driver=hd44780 {% endif %} {% endif %} @@ -128,5 +130,10 @@ USB=yes ## SDEC driver for Lanner, Watchguard, Sophos sppliances ## [sdeclcd] # No options +{% elif model == 'hd44780' %} +[hd44780] +ConnectionType=ezio +Device={{ device }} +Size=16x2 {% endif %} {% endif %} diff --git a/debian/control b/debian/control index f3a26e73e..6c0f2f886 100644 --- a/debian/control +++ b/debian/control @@ -72,6 +72,7 @@ Depends: iw, keepalived (>=2.0.5), lcdproc, + lcdproc-extra-drivers, libatomic1, libcharon-extra-plugins (>=5.9), libcharon-extauth-plugins (>=5.9), diff --git a/interface-definitions/system-lcd.xml.in b/interface-definitions/system-lcd.xml.in index 36116ae1b..4c9d5c92e 100644 --- a/interface-definitions/system-lcd.xml.in +++ b/interface-definitions/system-lcd.xml.in @@ -12,7 +12,7 @@ Model of the display attached to this system [REQUIRED] - cfa-533 cfa-631 cfa-633 cfa-635 sdec + cfa-533 cfa-631 cfa-633 cfa-635 hd44780 sdec cfa-533 @@ -30,12 +30,16 @@ cfa-635 Crystalfontz CFA-635 + + hd44780 + Hitachi HD44780, Caswell Appliances + sdec Lanner, Watchguard, Nexcom NSA, Sophos UTM appliances - ^(cfa-533|cfa-631|cfa-633|cfa-635|sdec)$ + ^(cfa-533|cfa-631|cfa-633|cfa-635|hd44780|sdec)$ -- cgit v1.2.3 From d4c5e78fc94a375487a968083f88d96323b67301 Mon Sep 17 00:00:00 2001 From: Georgiy Tugai Date: Wed, 13 Oct 2021 13:28:11 +0200 Subject: ntp: T3904: Fix NTP pool associations As of NTP 4.2.7, 'nopeer' also blocks pool associations. See https://bugs.ntp.org/show_bug.cgi?id=2657 See also https://github.com/geerlingguy/ansible-role-ntp/pull/84 (cherry picked from commit 854c68d43d8f1cf20417edd12284ea20f9e7ec9a) --- data/templates/ntp/ntpd.conf.tmpl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'data/templates') diff --git a/data/templates/ntp/ntpd.conf.tmpl b/data/templates/ntp/ntpd.conf.tmpl index 2b56b53c3..38e68f24f 100644 --- a/data/templates/ntp/ntpd.conf.tmpl +++ b/data/templates/ntp/ntpd.conf.tmpl @@ -6,6 +6,8 @@ driftfile /var/lib/ntp/ntp.drift # By default, only allow ntpd to query time sources, ignore any incoming requests restrict default noquery nopeer notrap nomodify +# Allow pool associations +restrict source nomodify notrap noquery # Local users have unrestricted access, allowing reconfiguration via ntpdc restrict 127.0.0.1 restrict -6 ::1 -- cgit v1.2.3 From 70836c5adb4e51bf46f79700b57b9a1437776793 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Thu, 14 Oct 2021 12:35:17 +0000 Subject: dhclient: T3832: Add hexadecimal format for client-id The hedadecimal option dhcp-cliend-identifier format is required to set values without quotes, separated by colons. --- data/templates/dhcp-client/ipv4.tmpl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'data/templates') diff --git a/data/templates/dhcp-client/ipv4.tmpl b/data/templates/dhcp-client/ipv4.tmpl index c934b7cdb..11e961166 100644 --- a/data/templates/dhcp-client/ipv4.tmpl +++ b/data/templates/dhcp-client/ipv4.tmpl @@ -7,7 +7,12 @@ retry 300; interface "{{ ifname }}" { send host-name "{{ dhcp_options.host_name }}"; {% if dhcp_options.client_id is defined and dhcp_options.client_id is not none %} - send dhcp-client-identifier "{{ dhcp_options.client_id }}"; +{% set client_id = dhcp_options.client_id %} +{# Use HEX representation of client-id as it is send in MAC-address style using hex characters. If not HEX, use double quotes ASCII format #} +{% if not dhcp_options.client_id.split(':') | length >= 5 %} +{% set client_id = '"' + dhcp_options.client_id + '"' %} +{% endif %} + send dhcp-client-identifier {{ client_id }}; {% endif %} {% if dhcp_options.vendor_class_id is defined and dhcp_options.vendor_class_id is not none %} send vendor-class-identifier "{{ dhcp_options.vendor_class_id }}"; -- cgit v1.2.3 From 3d00140453b3967370c77ddd9dac4af223a7ddce Mon Sep 17 00:00:00 2001 From: Marek Isalski Date: Fri, 6 Aug 2021 14:44:48 +0100 Subject: l2tp: T3724: allow setting accel-ppp l2tp host-name --- data/templates/accel-ppp/l2tp.config.tmpl | 3 +++ interface-definitions/vpn_l2tp.xml.in | 5 +++++ src/conf_mode/vpn_l2tp.py | 2 ++ 3 files changed, 10 insertions(+) (limited to 'data/templates') diff --git a/data/templates/accel-ppp/l2tp.config.tmpl b/data/templates/accel-ppp/l2tp.config.tmpl index 44c96b935..9fcda76d4 100644 --- a/data/templates/accel-ppp/l2tp.config.tmpl +++ b/data/templates/accel-ppp/l2tp.config.tmpl @@ -57,6 +57,9 @@ bind={{ outside_addr }} {% if lns_shared_secret %} secret={{ lns_shared_secret }} {% endif %} +{% if lns_host_name %} +host-name={{ lns_host_name }} +{% endif %} [client-ip-range] 0.0.0.0/0 diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in index cbd5e38e7..6cb0d4544 100644 --- a/interface-definitions/vpn_l2tp.xml.in +++ b/interface-definitions/vpn_l2tp.xml.in @@ -34,6 +34,11 @@ Tunnel password used to authenticate the client (LAC) + + + Sent to the client (LAC) in the Host-Name attribute + + diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py index 9c52f77ca..818e8fa0b 100755 --- a/src/conf_mode/vpn_l2tp.py +++ b/src/conf_mode/vpn_l2tp.py @@ -290,6 +290,8 @@ def get_config(config=None): # LNS secret if conf.exists(['lns', 'shared-secret']): l2tp['lns_shared_secret'] = conf.return_value(['lns', 'shared-secret']) + if conf.exists(['lns', 'host-name']): + l2tp['lns_host_name'] = conf.return_value(['lns', 'host-name']) if conf.exists(['ccp-disable']): l2tp['ccp_disable'] = True -- cgit v1.2.3 From 35aeea69c62a1755595d34b856d03f58cdd2da4c Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Mon, 11 Oct 2021 06:32:07 +0000 Subject: ddclient: T3897: Add option for IPv6 Dynamic DNS --- data/templates/dynamic-dns/ddclient.conf.tmpl | 2 +- interface-definitions/dns-dynamic.xml.in | 6 ++++ smoketest/scripts/cli/test_service_dns_dynamic.py | 38 +++++++++++++++++++++++ src/conf_mode/dynamic_dns.py | 2 +- 4 files changed, 46 insertions(+), 2 deletions(-) (limited to 'data/templates') diff --git a/data/templates/dynamic-dns/ddclient.conf.tmpl b/data/templates/dynamic-dns/ddclient.conf.tmpl index 9d379de00..517e4bad4 100644 --- a/data/templates/dynamic-dns/ddclient.conf.tmpl +++ b/data/templates/dynamic-dns/ddclient.conf.tmpl @@ -9,7 +9,7 @@ ssl=yes {% set web_skip = ", web-skip='" + interface[iface].use_web.skip + "'" if interface[iface].use_web.skip is defined else '' %} use=web, web='{{ interface[iface].use_web.url }}'{{ web_skip }} {% else %} -use=if, if={{ iface }} +{{ 'usev6=if' if interface[iface].ipv6_enable is defined else 'use=if' }}, if={{ iface }} {% endif %} {% if interface[iface].rfc2136 is defined and interface[iface].rfc2136 is not none %} diff --git a/interface-definitions/dns-dynamic.xml.in b/interface-definitions/dns-dynamic.xml.in index 250642691..64826516e 100644 --- a/interface-definitions/dns-dynamic.xml.in +++ b/interface-definitions/dns-dynamic.xml.in @@ -274,6 +274,12 @@ + + + Allow explicit IPv6 addresses for Dynamic DNS for this interface + + + diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py index d8a87ffd4..03fccf2c7 100755 --- a/smoketest/scripts/cli/test_service_dns_dynamic.py +++ b/smoketest/scripts/cli/test_service_dns_dynamic.py @@ -24,6 +24,7 @@ from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError from vyos.util import cmd from vyos.util import process_named_running +from vyos.util import read_file PROCESS_NAME = 'ddclient' DDCLIENT_CONF = '/run/ddclient/ddclient.conf' @@ -122,5 +123,42 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) + def test_dyndns_ipv6(self): + ddns = ['interface', 'eth0', 'service', 'dynv6'] + hostname = 'test.ddns.vyos.io' + proto = 'dyndns2' + user = 'none' + password = 'paSS_4ord' + servr = 'ddns.vyos.io' + + self.cli_set(base_path + ['interface', 'eth0', 'ipv6-enable']) + self.cli_set(base_path + ddns + ['host-name', hostname]) + self.cli_set(base_path + ddns + ['login', user]) + self.cli_set(base_path + ddns + ['password', password]) + self.cli_set(base_path + ddns + ['protocol', proto]) + self.cli_set(base_path + ddns + ['server', servr]) + + # commit changes + self.cli_commit() + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + config = read_file(DDCLIENT_CONF) + + protocol = get_config_value('protocol') + login = get_config_value('login') + pwd = get_config_value('password') + server = get_config_value('server') + + # Check some generating config parameters + self.assertTrue(protocol == proto) + self.assertTrue(login == user) + self.assertTrue(pwd == "'" + password + "'") + self.assertTrue(server == servr) + + self.assertIn('usev6=if', config) + self.assertIn(hostname, config) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/dynamic_dns.py b/src/conf_mode/dynamic_dns.py index c979feca7..646de6324 100755 --- a/src/conf_mode/dynamic_dns.py +++ b/src/conf_mode/dynamic_dns.py @@ -132,7 +132,7 @@ def generate(dyndns): return None render(config_file, 'dynamic-dns/ddclient.conf.tmpl', dyndns, - permission=0o600) + permission=0o644) return None -- cgit v1.2.3 From 16ae2933ff976737e52113105228a5f7f75686a3 Mon Sep 17 00:00:00 2001 From: sarthurdev <965089+sarthurdev@users.noreply.github.com> Date: Sat, 16 Oct 2021 20:54:34 +0200 Subject: mdns: T3917: Change to avahi-daemon for IPv4 + IPv6 mDNS repeater --- data/templates/mdns-repeater/avahi-daemon.tmpl | 18 ++++++++++++++++++ data/templates/mdns-repeater/mdns-repeater.tmpl | 2 -- debian/control | 2 +- smoketest/scripts/cli/test_service_mdns-repeater.py | 2 +- src/conf_mode/service_mdns-repeater.py | 10 +++++----- 5 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 data/templates/mdns-repeater/avahi-daemon.tmpl delete mode 100644 data/templates/mdns-repeater/mdns-repeater.tmpl (limited to 'data/templates') diff --git a/data/templates/mdns-repeater/avahi-daemon.tmpl b/data/templates/mdns-repeater/avahi-daemon.tmpl new file mode 100644 index 000000000..65bb5a306 --- /dev/null +++ b/data/templates/mdns-repeater/avahi-daemon.tmpl @@ -0,0 +1,18 @@ +[server] +use-ipv4=yes +use-ipv6=yes +allow-interfaces={{ interface | join(', ') }} +disallow-other-stacks=no + +[wide-area] +enable-wide-area=yes + +[publish] +disable-publishing=yes +disable-user-service-publishing=yes +publish-addresses=no +publish-hinfo=no +publish-workstation=no + +[reflector] +enable-reflector=yes diff --git a/data/templates/mdns-repeater/mdns-repeater.tmpl b/data/templates/mdns-repeater/mdns-repeater.tmpl deleted file mode 100644 index 80f4ab047..000000000 --- a/data/templates/mdns-repeater/mdns-repeater.tmpl +++ /dev/null @@ -1,2 +0,0 @@ -### Autogenerated by mdns_repeater.py ### -DAEMON_ARGS="{{ interface | join(' ') }}" diff --git a/debian/control b/debian/control index 6c0f2f886..0843b9025 100644 --- a/debian/control +++ b/debian/control @@ -33,6 +33,7 @@ Architecture: amd64 arm64 Depends: ${python3:Depends}, accel-ppp, + avahi-daemon, beep, bmon, bsdmainutils, @@ -87,7 +88,6 @@ Depends: lldpd, lm-sensors, lsscsi, - mdns-repeater, minisign, modemmanager, mtr-tiny, diff --git a/smoketest/scripts/cli/test_service_mdns-repeater.py b/smoketest/scripts/cli/test_service_mdns-repeater.py index b1092c3e5..8941f065c 100755 --- a/smoketest/scripts/cli/test_service_mdns-repeater.py +++ b/smoketest/scripts/cli/test_service_mdns-repeater.py @@ -42,7 +42,7 @@ class TestServiceMDNSrepeater(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Check for running process - self.assertTrue(process_named_running('mdns-repeater')) + self.assertTrue(process_named_running('avahi-daemon')) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/service_mdns-repeater.py b/src/conf_mode/service_mdns-repeater.py index c920920ed..55b568e48 100755 --- a/src/conf_mode/service_mdns-repeater.py +++ b/src/conf_mode/service_mdns-repeater.py @@ -28,7 +28,7 @@ from vyos import ConfigError from vyos import airbag airbag.enable() -config_file = r'/etc/default/mdns-repeater' +config_file = '/etc/avahi/avahi-daemon.conf' vrrp_running_file = '/run/mdns_vrrp_active' def get_config(config=None): @@ -92,12 +92,12 @@ def generate(mdns): if len(mdns['interface']) < 2: return None - render(config_file, 'mdns-repeater/mdns-repeater.tmpl', mdns) + render(config_file, 'mdns-repeater/avahi-daemon.tmpl', mdns) return None def apply(mdns): if not mdns or 'disable' in mdns: - call('systemctl stop mdns-repeater.service') + call('systemctl stop avahi-daemon.service') if os.path.exists(config_file): os.unlink(config_file) @@ -112,10 +112,10 @@ def apply(mdns): os.mknod(vrrp_running_file) # vrrp script looks for this file to update mdns repeater if len(mdns['interface']) < 2: - call('systemctl stop mdns-repeater.service') + call('systemctl stop avahi-daemon.service') return None - call('systemctl restart mdns-repeater.service') + call('systemctl restart avahi-daemon.service') return None -- cgit v1.2.3 From b1db3de80b8b5f4e2dcbc6d687d342986345c4b2 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Fri, 22 Oct 2021 11:55:17 +0000 Subject: hosts: T2683: Allow multiple entries for static-host-mapping --- data/templates/vyos-hostsd/hosts.tmpl | 5 +++-- interface-definitions/dns-domain-name.xml.in | 2 +- src/conf_mode/host_name.py | 2 +- src/services/vyos-hostsd | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'data/templates') diff --git a/data/templates/vyos-hostsd/hosts.tmpl b/data/templates/vyos-hostsd/hosts.tmpl index 8b73c6e51..03662d562 100644 --- a/data/templates/vyos-hostsd/hosts.tmpl +++ b/data/templates/vyos-hostsd/hosts.tmpl @@ -17,8 +17,9 @@ ff02::2 ip6-allrouters {% for tag, taghosts in hosts.items() %} # {{ tag }} {% for host, hostprops in taghosts.items() if hostprops.address is defined %} -{{ "%-15s" | format(hostprops.address) }} {{ host }} {{ hostprops.aliases|join(' ') if hostprops.aliases is defined }} +{% for addr in hostprops.address %} +{{ "%-15s" | format(addr) }} {{ host }} {{ hostprops.aliases|join(' ') if hostprops.aliases is defined }} +{% endfor %} {% endfor %} {% endfor %} {% endif %} - diff --git a/interface-definitions/dns-domain-name.xml.in b/interface-definitions/dns-domain-name.xml.in index 2b1644609..005a55ab3 100644 --- a/interface-definitions/dns-domain-name.xml.in +++ b/interface-definitions/dns-domain-name.xml.in @@ -102,11 +102,11 @@ + - diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py index a7135911d..87bad0dc6 100755 --- a/src/conf_mode/host_name.py +++ b/src/conf_mode/host_name.py @@ -79,7 +79,7 @@ def get_config(config=None): # system static-host-mapping for hn in conf.list_nodes(['system', 'static-host-mapping', 'host-name']): hosts['static_host_mapping'][hn] = {} - hosts['static_host_mapping'][hn]['address'] = conf.return_value(['system', 'static-host-mapping', 'host-name', hn, 'inet']) + hosts['static_host_mapping'][hn]['address'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'inet']) hosts['static_host_mapping'][hn]['aliases'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'alias']) return hosts diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd index 4c4bb036e..f4b1d0fc2 100755 --- a/src/services/vyos-hostsd +++ b/src/services/vyos-hostsd @@ -317,7 +317,7 @@ hosts_add_schema = op_type_schema.extend({ 'data': { str: { str: { - 'address': str, + 'address': [str], 'aliases': [str] } } -- cgit v1.2.3 From 45f815928976519ffba2ecadf197f725e7640852 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Mon, 25 Oct 2021 18:07:06 +0000 Subject: snmp: T2763: Add protocol TCP for service snmp --- data/templates/snmp/etc.snmpd.conf.tmpl | 2 +- interface-definitions/snmp.xml.in | 20 ++++++++++++++++++++ src/conf_mode/snmp.py | 9 +++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'data/templates') diff --git a/data/templates/snmp/etc.snmpd.conf.tmpl b/data/templates/snmp/etc.snmpd.conf.tmpl index db2114fa1..30806ce8a 100644 --- a/data/templates/snmp/etc.snmpd.conf.tmpl +++ b/data/templates/snmp/etc.snmpd.conf.tmpl @@ -39,7 +39,7 @@ SysDescr {{ description }} {% endif %} # Listen -agentaddress unix:/run/snmpd.socket{% if listen_on %}{% for li in listen_on %},{{ li }}{% endfor %}{% else %},udp:161{% if ipv6_enabled %},udp6:161{% endif %}{% endif %} +agentaddress unix:/run/snmpd.socket{% if listen_on %}{% for li in listen_on %},{{ li }}{% endfor %}{% else %},{{protocol}}:161{% if ipv6_enabled %},{{protocol}}6:161{% endif %}{% endif %} # SNMP communities {% for c in communities %} diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index b0b7768d2..949536fe7 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -149,6 +149,26 @@ Oid must be 'route-table' + + + Listen protocol for SNMP + + udp tcp + + + udp + Listen protocol UDP (default) + + + tcp + Listen protocol TCP + + + ^(udp|tcp)$ + + + udp + Register a subtree for SMUX-based processing diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py index 23e45a5b7..2a420b193 100755 --- a/src/conf_mode/snmp.py +++ b/src/conf_mode/snmp.py @@ -52,6 +52,7 @@ default_config_data = { 'communities': [], 'smux_peers': [], 'location' : '', + 'protocol' : 'udp', 'description' : '', 'contact' : '', 'route_table': 'False', @@ -151,6 +152,9 @@ def get_config(): if conf.exists('location'): snmp['location'] = conf.return_value('location') + if conf.exists('protocol'): + snmp['protocol'] = conf.return_value('protocol') + if conf.exists('smux-peer'): snmp['smux_peers'] = conf.return_values('smux-peer') @@ -404,13 +408,14 @@ def verify(snmp): for listen in snmp['listen_address']: addr = listen[0] port = listen[1] + protocol = snmp['protocol'] if is_ipv4(addr): # example: udp:127.0.0.1:161 - listen = 'udp:' + addr + ':' + port + listen = f'{protocol}:{addr}:{port}' elif snmp['ipv6_enabled']: # example: udp6:[::1]:161 - listen = 'udp6:' + '[' + addr + ']' + ':' + port + listen = f'{protocol}6:[{addr}]:{port}' # We only wan't to configure addresses that exist on the system. # Hint the user if they don't exist -- cgit v1.2.3 From 2c89e1fc4f1aa8a84b3c610b791873bf66c2fec8 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Tue, 26 Oct 2021 16:13:06 +0000 Subject: bgp: T3945: Add route-map for aggregate-address --- data/templates/frr/bgpd.frr.tmpl | 3 +++ interface-definitions/include/bgp/afi-aggregate-address.xml.i | 1 + 2 files changed, 4 insertions(+) (limited to 'data/templates') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index a35930c93..2d01ed6a6 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -266,6 +266,9 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} {% for ip in afi_config.aggregate_address %} aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} +{% if afi_config.aggregate_address[ip].route_map is defined and afi_config.aggregate_address[ip].route_map is not none %} + aggregate-address {{ ip }} route-map {{ afi_config.aggregate_address[ip].route_map }} +{% endif %} {% endfor %} {% endif %} {% if afi_config.maximum_paths is defined and afi_config.maximum_paths.ebgp is defined and afi_config.maximum_paths.ebgp is not none %} diff --git a/interface-definitions/include/bgp/afi-aggregate-address.xml.i b/interface-definitions/include/bgp/afi-aggregate-address.xml.i index 646751c32..c1b7958da 100644 --- a/interface-definitions/include/bgp/afi-aggregate-address.xml.i +++ b/interface-definitions/include/bgp/afi-aggregate-address.xml.i @@ -5,6 +5,7 @@ +#include Announce the aggregate summary network only -- cgit v1.2.3 From a522971938611eb2c630257449369ecf03156d47 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 26 Oct 2021 19:45:12 +0200 Subject: bgp: T3945: relax Jinja2 for loop for aggregate-address --- data/templates/frr/bgpd.frr.tmpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'data/templates') diff --git a/data/templates/frr/bgpd.frr.tmpl b/data/templates/frr/bgpd.frr.tmpl index 2d01ed6a6..61936bb56 100644 --- a/data/templates/frr/bgpd.frr.tmpl +++ b/data/templates/frr/bgpd.frr.tmpl @@ -264,10 +264,10 @@ router bgp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is defined and vrf is not none {% endif %} {% endif %} {% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} -{% for ip in afi_config.aggregate_address %} - aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} -{% if afi_config.aggregate_address[ip].route_map is defined and afi_config.aggregate_address[ip].route_map is not none %} - aggregate-address {{ ip }} route-map {{ afi_config.aggregate_address[ip].route_map }} +{% for aggregate, aggregate_config in afi_config.aggregate_address.items() %} + aggregate-address {{ aggregate }}{{ ' as-set' if aggregate_config.as_set is defined }}{{ ' summary-only' if aggregate_config.summary_only is defined }} +{% if aggregate_config.route_map is defined and aggregate_config.route_map is not none %} + aggregate-address {{ aggregate }} route-map {{ aggregate_config.route_map }} {% endif %} {% endfor %} {% endif %} -- cgit v1.2.3