summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/config-mode-dependencies/vyos-1x.json1
-rw-r--r--data/templates/accel-ppp/config_extended_scripts.j29
-rw-r--r--data/templates/accel-ppp/config_limits.j212
-rw-r--r--data/templates/accel-ppp/config_snmp.j24
-rw-r--r--data/templates/accel-ppp/config_wins_server.j26
-rw-r--r--data/templates/accel-ppp/ipoe.config.j218
-rw-r--r--data/templates/accel-ppp/l2tp.config.j241
-rw-r--r--data/templates/accel-ppp/pppoe.config.j276
-rw-r--r--data/templates/accel-ppp/pptp.config.j239
-rw-r--r--data/templates/accel-ppp/sstp.config.j220
-rw-r--r--data/templates/frr/bgpd.frr.j25
-rw-r--r--data/templates/frr/eigrpd.frr.j224
-rw-r--r--interface-definitions/firewall.xml.in4
-rw-r--r--interface-definitions/include/accel-ppp/extended-scripts.xml.i41
-rw-r--r--interface-definitions/include/accel-ppp/limits.xml.i28
-rw-r--r--interface-definitions/include/accel-ppp/snmp.xml.i15
-rw-r--r--interface-definitions/include/bgp/protocol-common-config.xml.i24
-rw-r--r--interface-definitions/include/eigrp/protocol-common-config.xml.i5
-rw-r--r--interface-definitions/include/pki/openssh-key.xml.i14
-rw-r--r--interface-definitions/include/version/l2tp-version.xml.i2
-rw-r--r--interface-definitions/pki.xml.in39
-rw-r--r--interface-definitions/protocols_rpki.xml.in17
-rw-r--r--interface-definitions/service_ipoe-server.xml.in11
-rw-r--r--interface-definitions/service_pppoe-server.xml.in110
-rw-r--r--interface-definitions/vpn_l2tp.xml.in83
-rw-r--r--interface-definitions/vpn_pptp.xml.in23
-rw-r--r--interface-definitions/vpn_sstp.xml.in32
-rw-r--r--op-mode-definitions/dhcp.xml.in54
-rw-r--r--python/vyos/accel_ppp_util.py32
-rw-r--r--python/vyos/kea.py35
-rw-r--r--python/vyos/pki.py31
-rwxr-xr-xsmoketest/bin/vyos-configtest-pki41
-rw-r--r--smoketest/config-tests/rpki-only30
-rw-r--r--smoketest/configs/rpki-only122
-rw-r--r--smoketest/scripts/cli/base_accel_ppp_test.py51
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py5
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py4
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_rpki.py140
-rwxr-xr-xsmoketest/scripts/cli/test_service_ipoe-server.py4
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py6
-rwxr-xr-xsrc/conf_mode/pki.py40
-rwxr-xr-xsrc/conf_mode/protocols_eigrp.py10
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py47
-rwxr-xr-xsrc/conf_mode/service_ipoe-server.py8
-rwxr-xr-xsrc/conf_mode/service_pppoe-server.py10
-rwxr-xr-xsrc/conf_mode/vpn_l2tp.py12
-rwxr-xr-xsrc/conf_mode/vpn_pptp.py12
-rwxr-xr-xsrc/conf_mode/vpn_sstp.py88
-rwxr-xr-xsrc/init/vyos-router4
-rwxr-xr-xsrc/migration-scripts/ipsec/6-to-72
-rwxr-xr-xsrc/migration-scripts/l2tp/8-to-949
-rwxr-xr-xsrc/migration-scripts/rpki/1-to-222
-rwxr-xr-xsrc/op_mode/dhcp.py93
53 files changed, 1224 insertions, 431 deletions
diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json
index b62603e34..b0586e0bb 100644
--- a/data/config-mode-dependencies/vyos-1x.json
+++ b/data/config-mode-dependencies/vyos-1x.json
@@ -27,6 +27,7 @@
"https": ["service_https"],
"ipsec": ["vpn_ipsec"],
"openconnect": ["vpn_openconnect"],
+ "rpki": ["protocols_rpki"],
"sstp": ["vpn_sstp"]
},
"vpn_l2tp": {
diff --git a/data/templates/accel-ppp/config_extended_scripts.j2 b/data/templates/accel-ppp/config_extended_scripts.j2
new file mode 100644
index 000000000..ded0a0a39
--- /dev/null
+++ b/data/templates/accel-ppp/config_extended_scripts.j2
@@ -0,0 +1,9 @@
+{% if extended_scripts is vyos_defined %}
+[pppd-compat]
+verbose=1
+radattr-prefix=/run/accel-pppd/radattr
+{% set script_name = {'on_up': 'ip-up', 'on_down': 'ip-down', 'on_change':'ip-change', 'on_pre_up':'ip-pre-up'} %}
+{% for script in extended_scripts %}
+{{ script_name[script] }}={{ extended_scripts[script] }}
+{% endfor %}
+{% endif %} \ No newline at end of file
diff --git a/data/templates/accel-ppp/config_limits.j2 b/data/templates/accel-ppp/config_limits.j2
new file mode 100644
index 000000000..f10dfccd7
--- /dev/null
+++ b/data/templates/accel-ppp/config_limits.j2
@@ -0,0 +1,12 @@
+{% if limits is vyos_defined %}
+[connlimit]
+{% if limits.connection_limit is vyos_defined %}
+limit={{ limits.connection_limit }}
+{% endif %}
+{% if limits.burst is vyos_defined %}
+burst={{ limits.burst }}
+{% endif %}
+{% if limits.timeout is vyos_defined %}
+timeout={{ limits.timeout }}
+{% endif %}
+{% endif %} \ No newline at end of file
diff --git a/data/templates/accel-ppp/config_snmp.j2 b/data/templates/accel-ppp/config_snmp.j2
new file mode 100644
index 000000000..11526dd81
--- /dev/null
+++ b/data/templates/accel-ppp/config_snmp.j2
@@ -0,0 +1,4 @@
+{% if snmp.master_agent is vyos_defined %}
+[snmp]
+master=1
+{% endif %}
diff --git a/data/templates/accel-ppp/config_wins_server.j2 b/data/templates/accel-ppp/config_wins_server.j2
new file mode 100644
index 000000000..23312f92e
--- /dev/null
+++ b/data/templates/accel-ppp/config_wins_server.j2
@@ -0,0 +1,6 @@
+{% if wins_server is vyos_defined %}
+[wins]
+{% for server in wins_server %}
+wins{{ loop.index }}={{ server }}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/accel-ppp/ipoe.config.j2 b/data/templates/accel-ppp/ipoe.config.j2
index 8b022eaa5..c89812985 100644
--- a/data/templates/accel-ppp/ipoe.config.j2
+++ b/data/templates/accel-ppp/ipoe.config.j2
@@ -6,10 +6,16 @@ ipoe
shaper
{# Common authentication backend definitions #}
{% include 'accel-ppp/config_modules_auth_mode.j2' %}
+ippool
ipv6pool
ipv6_nd
ipv6_dhcp
-ippool
+{% if snmp is vyos_defined %}
+net-snmp
+{% endif %}
+{% if limits is vyos_defined %}
+connlimit
+{% endif %}
[core]
thread-count={{ thread_count }}
@@ -19,6 +25,7 @@ thread-count={{ thread_count }}
max-starting={{ max_concurrent_sessions }}
{% endif %}
+
[log]
syslog=accel-ipoe,daemon
copy=1
@@ -84,5 +91,14 @@ proxy-arp=1
{# Common RADIUS shaper configuration #}
{% include 'accel-ppp/config_shaper_radius.j2' %}
+{# Common Extended scripts configuration #}
+{% include 'accel-ppp/config_extended_scripts.j2' %}
+
+{# Common Limits configuration #}
+{% include 'accel-ppp/config_limits.j2' %}
+
+{# Common SNMP definitions #}
+{% include 'accel-ppp/config_snmp.j2' %}
+
[cli]
tcp=127.0.0.1:2002
diff --git a/data/templates/accel-ppp/l2tp.config.j2 b/data/templates/accel-ppp/l2tp.config.j2
index 203a9772e..4ce9042c2 100644
--- a/data/templates/accel-ppp/l2tp.config.j2
+++ b/data/templates/accel-ppp/l2tp.config.j2
@@ -10,6 +10,12 @@ ippool
{% include 'accel-ppp/config_modules_ipv6.j2' %}
{# Common authentication protocols (pap, chap ...) #}
{% include 'accel-ppp/config_modules_auth_protocols.j2' %}
+{% if snmp is vyos_defined %}
+net-snmp
+{% endif %}
+{% if limits is vyos_defined %}
+connlimit
+{% endif %}
[core]
thread-count={{ thread_count }}
@@ -24,15 +30,8 @@ syslog=accel-l2tp,daemon
copy=1
level=5
-{# Common DNS name-server definition #}
-{% include 'accel-ppp/config_name_server.j2' %}
-
-{% if wins_server is vyos_defined %}
-[wins]
-{% for server in wins_server %}
-wins{{ loop.index }}={{ server }}
-{% endfor %}
-{% endif %}
+[client-ip-range]
+0.0.0.0/0
[l2tp]
verbose=1
@@ -56,24 +55,36 @@ ipv6-pool={{ default_ipv6_pool }}
ipv6-pool-delegate={{ default_ipv6_pool }}
{% endif %}
-[client-ip-range]
-0.0.0.0/0
-
{# Common IP pool definitions #}
{% include 'accel-ppp/config_ip_pool.j2' %}
+{# Common IPv6 pool definitions #}
+{% include 'accel-ppp/config_ipv6_pool.j2' %}
+
+{# Common DNS name-server definition #}
+{% include 'accel-ppp/config_name_server.j2' %}
+
+{# Common wins-server definition #}
+{% include 'accel-ppp/config_wins_server.j2' %}
+
{# Common chap-secrets and RADIUS server/option definitions #}
{% include 'accel-ppp/config_chap_secrets_radius.j2' %}
{# Common ppp-options definitions #}
{% include 'accel-ppp/ppp-options.j2' %}
-{# Common IPv6 pool definitions #}
-{% include 'accel-ppp/config_ipv6_pool.j2' %}
-
{# Common RADIUS shaper configuration #}
{% include 'accel-ppp/config_shaper_radius.j2' %}
+{# Common Extended scripts configuration #}
+{% include 'accel-ppp/config_extended_scripts.j2' %}
+
+{# Common Limits configuration #}
+{% include 'accel-ppp/config_limits.j2' %}
+
+{# Common SNMP definitions #}
+{% include 'accel-ppp/config_snmp.j2' %}
+
[cli]
tcp=127.0.0.1:2004
diff --git a/data/templates/accel-ppp/pppoe.config.j2 b/data/templates/accel-ppp/pppoe.config.j2
index bf7b2eb72..6b01958e5 100644
--- a/data/templates/accel-ppp/pppoe.config.j2
+++ b/data/templates/accel-ppp/pppoe.config.j2
@@ -10,7 +10,6 @@ ippool
{% include 'accel-ppp/config_modules_ipv6.j2' %}
{# Common authentication protocols (pap, chap ...) #}
{% include 'accel-ppp/config_modules_auth_protocols.j2' %}
-
{% if snmp is vyos_defined %}
net-snmp
{% endif %}
@@ -35,32 +34,8 @@ level=5
noauth=1
{% endif %}
-{% if snmp.master_agent is vyos_defined %}
-[snmp]
-master=1
-{% endif %}
-
[client-ip-range]
-disable
-
-{# Common IP pool definitions #}
-{% include 'accel-ppp/config_ip_pool.j2' %}
-
-{# Common IPv6 pool definitions #}
-{% include 'accel-ppp/config_ipv6_pool.j2' %}
-
-{# Common DNS name-server definition #}
-{% include 'accel-ppp/config_name_server.j2' %}
-
-{% if wins_server is vyos_defined %}
-[wins]
-{% for server in wins_server %}
-wins{{ loop.index }}={{ server }}
-{% endfor %}
-{% endif %}
-
-{# Common chap-secrets and RADIUS server/option definitions #}
-{% include 'accel-ppp/config_chap_secrets_radius.j2' %}
+0.0.0.0/0
[common]
{% if session_control is vyos_defined and session_control is not vyos_defined('disable') %}
@@ -70,9 +45,6 @@ single-session={{ session_control }}
max-starting={{ max_concurrent_sessions }}
{% endif %}
-{# Common ppp-options definitions #}
-{% include 'accel-ppp/ppp-options.j2' %}
-
[pppoe]
verbose=1
ac-name={{ access_concentrator }}
@@ -116,31 +88,35 @@ ipv6-pool={{ default_ipv6_pool }}
ipv6-pool-delegate={{ default_ipv6_pool }}
{% endif %}
-{% if limits is vyos_defined %}
-[connlimit]
-{% if limits.connection_limit is vyos_defined %}
-limit={{ limits.connection_limit }}
-{% endif %}
-{% if limits.burst is vyos_defined %}
-burst={{ limits.burst }}
-{% endif %}
-{% if limits.timeout is vyos_defined %}
-timeout={{ limits.timeout }}
-{% endif %}
-{% endif %}
+{# Common IP pool definitions #}
+{% include 'accel-ppp/config_ip_pool.j2' %}
+
+{# Common IPv6 pool definitions #}
+{% include 'accel-ppp/config_ipv6_pool.j2' %}
+
+{# Common DNS name-server definition #}
+{% include 'accel-ppp/config_name_server.j2' %}
+
+{# Common wins-server definition #}
+{% include 'accel-ppp/config_wins_server.j2' %}
+
+{# Common chap-secrets and RADIUS server/option definitions #}
+{% include 'accel-ppp/config_chap_secrets_radius.j2' %}
+
+{# Common ppp-options definitions #}
+{% include 'accel-ppp/ppp-options.j2' %}
{# Common RADIUS shaper configuration #}
{% include 'accel-ppp/config_shaper_radius.j2' %}
-{% if extended_scripts is vyos_defined %}
-[pppd-compat]
-verbose=1
-radattr-prefix=/run/accel-pppd/radattr
-{% set script_name = {'on_up': 'ip-up', 'on_down': 'ip-down', 'on_change':'ip-change', 'on_pre_up':'ip-pre-up'} %}
-{% for script in extended_scripts %}
-{{ script_name[script] }}={{ extended_scripts[script] }}
-{% endfor %}
-{% endif %}
+{# Common Extended scripts configuration #}
+{% include 'accel-ppp/config_extended_scripts.j2' %}
+
+{# Common Limits configuration #}
+{% include 'accel-ppp/config_limits.j2' %}
+
+{# Common SNMP definitions #}
+{% include 'accel-ppp/config_snmp.j2' %}
[cli]
tcp=127.0.0.1:2001
diff --git a/data/templates/accel-ppp/pptp.config.j2 b/data/templates/accel-ppp/pptp.config.j2
index 290e6235d..a04bd40c0 100644
--- a/data/templates/accel-ppp/pptp.config.j2
+++ b/data/templates/accel-ppp/pptp.config.j2
@@ -10,6 +10,12 @@ ippool
{% include 'accel-ppp/config_modules_ipv6.j2' %}
{# Common authentication protocols (pap, chap ...) #}
{% include 'accel-ppp/config_modules_auth_protocols.j2' %}
+{% if snmp is vyos_defined %}
+net-snmp
+{% endif %}
+{% if limits is vyos_defined %}
+connlimit
+{% endif %}
[core]
thread-count={{ thread_count }}
@@ -24,15 +30,8 @@ syslog=accel-pptp,daemon
copy=1
level=5
-{# Common DNS name-server definition #}
-{% include 'accel-ppp/config_name_server.j2' %}
-
-{% if wins_server is vyos_defined %}
-[wins]
-{% for server in wins_server %}
-wins{{ loop.index }}={{ server }}
-{% endfor %}
-{% endif %}
+[client-ip-range]
+0.0.0.0/0
[pptp]
ifname=pptp%d
@@ -52,24 +51,36 @@ ipv6-pool={{ default_ipv6_pool }}
ipv6-pool-delegate={{ default_ipv6_pool }}
{% endif %}
-[client-ip-range]
-0.0.0.0/0
-
{# Common IP pool definitions #}
{% include 'accel-ppp/config_ip_pool.j2' %}
{# Common IPv6 pool definitions #}
{% include 'accel-ppp/config_ipv6_pool.j2' %}
-{# Common ppp-options definitions #}
-{% include 'accel-ppp/ppp-options.j2' %}
+{# Common DNS name-server definition #}
+{% include 'accel-ppp/config_name_server.j2' %}
+
+{# Common wins-server definition #}
+{% include 'accel-ppp/config_wins_server.j2' %}
{# Common chap-secrets and RADIUS server/option definitions #}
{% include 'accel-ppp/config_chap_secrets_radius.j2' %}
+{# Common ppp-options definitions #}
+{% include 'accel-ppp/ppp-options.j2' %}
+
{# Common RADIUS shaper configuration #}
{% include 'accel-ppp/config_shaper_radius.j2' %}
+{# Common Extended scripts configuration #}
+{% include 'accel-ppp/config_extended_scripts.j2' %}
+
+{# Common Limits configuration #}
+{% include 'accel-ppp/config_limits.j2' %}
+
+{# Common SNMP definitions #}
+{% include 'accel-ppp/config_snmp.j2' %}
+
[cli]
tcp=127.0.0.1:2003
diff --git a/data/templates/accel-ppp/sstp.config.j2 b/data/templates/accel-ppp/sstp.config.j2
index c0bc62d9f..b624f83a3 100644
--- a/data/templates/accel-ppp/sstp.config.j2
+++ b/data/templates/accel-ppp/sstp.config.j2
@@ -10,6 +10,12 @@ ippool
{% include 'accel-ppp/config_modules_ipv6.j2' %}
{# Common authentication protocols (pap, chap ...) #}
{% include 'accel-ppp/config_modules_auth_protocols.j2' %}
+{% if snmp is vyos_defined %}
+net-snmp
+{% endif %}
+{% if limits is vyos_defined %}
+connlimit
+{% endif %}
[core]
thread-count={{ thread_count }}
@@ -26,7 +32,7 @@ copy=1
level=5
[client-ip-range]
-disable
+0.0.0.0/0
[sstp]
verbose=1
@@ -53,6 +59,9 @@ ipv6-pool-delegate={{ default_ipv6_pool }}
{# Common DNS name-server definition #}
{% include 'accel-ppp/config_name_server.j2' %}
+{# Common wins-server definition #}
+{% include 'accel-ppp/config_wins_server.j2' %}
+
{# Common chap-secrets and RADIUS server/option definitions #}
{% include 'accel-ppp/config_chap_secrets_radius.j2' %}
@@ -62,5 +71,14 @@ ipv6-pool-delegate={{ default_ipv6_pool }}
{# Common RADIUS shaper configuration #}
{% include 'accel-ppp/config_shaper_radius.j2' %}
+{# Common Extended scripts configuration #}
+{% include 'accel-ppp/config_extended_scripts.j2' %}
+
+{# Common Limits configuration #}
+{% include 'accel-ppp/config_limits.j2' %}
+
+{# Common SNMP definitions #}
+{% include 'accel-ppp/config_snmp.j2' %}
+
[cli]
tcp=127.0.0.1:2005
diff --git a/data/templates/frr/bgpd.frr.j2 b/data/templates/frr/bgpd.frr.j2
index ed55db3f2..e9422b257 100644
--- a/data/templates/frr/bgpd.frr.j2
+++ b/data/templates/frr/bgpd.frr.j2
@@ -390,7 +390,7 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% endif %}
{% if afi_config.ead_es_route_target.export is vyos_defined %}
{% for route_target in afi_config.ead_es_route_target.export %}
- ead-es-route-target export {{ route_target }}
+ ead-es-route-target export {{ route_target }}
{% endfor %}
{% endif %}
{% if afi_config.rt_auto_derive is vyos_defined %}
@@ -402,6 +402,9 @@ router bgp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% if afi_config.flooding.head_end_replication is vyos_defined %}
flooding head-end-replication
{% endif %}
+{% if afi_config.mac_vrf.soo is vyos_defined %}
+ mac-vrf soo {{ afi_config.mac_vrf.soo }}
+{% endif %}
{% if afi_config.nexthop.vpn.export is vyos_defined %}
nexthop vpn export {{ afi_config.nexthop.vpn.export }}
{% endif %}
diff --git a/data/templates/frr/eigrpd.frr.j2 b/data/templates/frr/eigrpd.frr.j2
index 3038a0b1d..d16963a51 100644
--- a/data/templates/frr/eigrpd.frr.j2
+++ b/data/templates/frr/eigrpd.frr.j2
@@ -1,21 +1,31 @@
!
-router eigrp {{ local_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
+router eigrp {{ system_as }} {{ 'vrf ' ~ vrf if vrf is vyos_defined }}
{% if maximum_paths is vyos_defined %}
-maximum-paths {{ maximum_paths }}
+ maximum-paths {{ maximum_paths }}
{% endif %}
{% if metric.weights is vyos_defined %}
-metric weights {{ metric.weights }}
+ metric weights {{ metric.weights }}
{% endif %}
{% if network is vyos_defined %}
{% for net in network %}
-network {{ net }}
+ network {{ net }}
+{% endfor %}
+{% endif %}
+{% if passive_interface is vyos_defined %}
+{% for interface in passive_interface %}
+ passive-interface {{ interface }}
{% endfor %}
{% endif %}
{% if redistribute is vyos_defined %}
{% for protocol in redistribute %}
-redistribute {{ protocol }}
+ redistribute {{ protocol }}
{% endfor %}
{% endif %}
+{% if router_id is vyos_defined %}
+ eigrp router-id {{ router_id }}
+{% endif %}
{% if variance is vyos_defined %}
-variance {{ variance }}
-{% endif %} \ No newline at end of file
+ variance {{ variance }}
+{% endif %}
+exit
+!
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index 662ba24ab..3219471b1 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -2,7 +2,7 @@
<interfaceDefinition>
<node name="firewall" owner="${vyos_conf_scripts_dir}/firewall.py">
<properties>
- <priority>199</priority>
+ <priority>319</priority>
<help>Firewall</help>
</properties>
<children>
@@ -94,7 +94,7 @@
<properties>
<help>Firewall domain-group</help>
<constraint>
- <regex>[a-zA-Z_][a-zA-Z0-9][\w\-\.]*</regex>
+ <regex>[a-zA-Z_][a-zA-Z0-9]?[\w\-\.]*</regex>
</constraint>
<constraintErrorMessage>Name of domain-group can only contain alpha-numeric letters, hyphen, underscores and not start with numeric</constraintErrorMessage>
</properties>
diff --git a/interface-definitions/include/accel-ppp/extended-scripts.xml.i b/interface-definitions/include/accel-ppp/extended-scripts.xml.i
new file mode 100644
index 000000000..4bba76e32
--- /dev/null
+++ b/interface-definitions/include/accel-ppp/extended-scripts.xml.i
@@ -0,0 +1,41 @@
+<!-- include start from accel-ppp/extended-scripts.xml.i -->
+<node name="extended-scripts">
+ <properties>
+ <help>Extended script execution</help>
+ </properties>
+ <children>
+ <leafNode name="on-pre-up">
+ <properties>
+ <help>Script to run before PPPoE session interface comes up</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="on-up">
+ <properties>
+ <help>Script to run when PPPoE session interface is completely configured and started</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="on-down">
+ <properties>
+ <help>Script to run when PPPoE session interface going to terminate</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="on-change">
+ <properties>
+ <help>Script to run when PPPoE session interface changed by RADIUS CoA handling</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/accel-ppp/limits.xml.i b/interface-definitions/include/accel-ppp/limits.xml.i
new file mode 100644
index 000000000..df72b79d4
--- /dev/null
+++ b/interface-definitions/include/accel-ppp/limits.xml.i
@@ -0,0 +1,28 @@
+<!-- include start from accel-ppp/limits.xml.i -->
+<node name="limits">
+ <properties>
+ <help>Limits the connection rate from a single source</help>
+ </properties>
+ <children>
+ <leafNode name="connection-limit">
+ <properties>
+ <help>Acceptable rate of connections (e.g. 1/min, 60/sec)</help>
+ <constraint>
+ <regex>[0-9]+\/(min|sec)</regex>
+ </constraint>
+ <constraintErrorMessage>illegal value</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="burst">
+ <properties>
+ <help>Burst count</help>
+ </properties>
+ </leafNode>
+ <leafNode name="timeout">
+ <properties>
+ <help>Timeout in seconds</help>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/accel-ppp/snmp.xml.i b/interface-definitions/include/accel-ppp/snmp.xml.i
new file mode 100644
index 000000000..373ced16f
--- /dev/null
+++ b/interface-definitions/include/accel-ppp/snmp.xml.i
@@ -0,0 +1,15 @@
+<!-- include start from accel-ppp/snmp.xml.i -->
+<node name="snmp">
+ <properties>
+ <help>Enable SNMP</help>
+ </properties>
+ <children>
+ <leafNode name="master-agent">
+ <properties>
+ <help>Enable SNMP master agent mode</help>
+ <valueless />
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i
index ea6e75bbd..ca67eaf3c 100644
--- a/interface-definitions/include/bgp/protocol-common-config.xml.i
+++ b/interface-definitions/include/bgp/protocol-common-config.xml.i
@@ -894,6 +894,30 @@
</leafNode>
</children>
</node>
+ <node name="mac-vrf">
+ <properties>
+ <help>EVPN MAC-VRF</help>
+ </properties>
+ <children>
+ <leafNode name="soo">
+ <properties>
+ <help>Site-of-Origin extended community</help>
+ <valueHelp>
+ <format>ASN:NN</format>
+ <description>based on autonomous system number in format &lt;0-65535:0-4294967295&gt;</description>
+ </valueHelp>
+ <valueHelp>
+ <format>IP:NN</format>
+ <description>Based on a router-id IP address in format &lt;IP:0-65535&gt;</description>
+ </valueHelp>
+ <constraint>
+ <validator name="bgp-extended-community"/>
+ </constraint>
+ <constraintErrorMessage>Should be in form: ASN:NN or IPADDR:NN where ASN is autonomous system number</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<tagNode name="vni">
<properties>
<help>VXLAN Network Identifier</help>
diff --git a/interface-definitions/include/eigrp/protocol-common-config.xml.i b/interface-definitions/include/eigrp/protocol-common-config.xml.i
index a21d18424..a8290f772 100644
--- a/interface-definitions/include/eigrp/protocol-common-config.xml.i
+++ b/interface-definitions/include/eigrp/protocol-common-config.xml.i
@@ -1,5 +1,5 @@
<!-- include start from eigrp/protocol-common-config.xml.i -->
-<leafNode name="local-as">
+<leafNode name="system-as">
<properties>
<help>Autonomous System Number (ASN)</help>
<valueHelp>
@@ -61,6 +61,7 @@
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
+ <multi/>
</properties>
</leafNode>
<leafNode name="redistribute">
@@ -108,7 +109,7 @@
</properties>
</leafNode>
#include <include/router-id.xml.i>
-<!-- FRR timers not implemented yet -->
+<!-- FRR error: active time not implemented yet -->
<leafNode name="variance">
<properties>
<help>Control load balancing variance</help>
diff --git a/interface-definitions/include/pki/openssh-key.xml.i b/interface-definitions/include/pki/openssh-key.xml.i
new file mode 100644
index 000000000..8f005d077
--- /dev/null
+++ b/interface-definitions/include/pki/openssh-key.xml.i
@@ -0,0 +1,14 @@
+<!-- include start from pki/openssh-key.xml.i -->
+<leafNode name="key">
+ <properties>
+ <help>OpenSSH key in PKI configuration</help>
+ <completionHelp>
+ <path>pki openssh</path>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of OpenSSH key in PKI configuration</description>
+ </valueHelp>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/version/l2tp-version.xml.i b/interface-definitions/include/version/l2tp-version.xml.i
index 01004c5a0..5397407fb 100644
--- a/interface-definitions/include/version/l2tp-version.xml.i
+++ b/interface-definitions/include/version/l2tp-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/l2tp-version.xml.i -->
-<syntaxVersion component='l2tp' version='8'></syntaxVersion>
+<syntaxVersion component='l2tp' version='9'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in
index 617bdd584..7a0b073b4 100644
--- a/interface-definitions/pki.xml.in
+++ b/interface-definitions/pki.xml.in
@@ -168,6 +168,45 @@
</properties>
<children>
#include <include/pki/cli-public-key-base64.xml.i>
+ <leafNode name="type">
+ <properties>
+ <help>SSH public key type</help>
+ <completionHelp>
+ <list>ssh-rsa</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ssh-rsa</format>
+ <description>Key pair based on RSA algorithm</description>
+ </valueHelp>
+ <constraint>
+ <regex>(ssh-rsa)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="private">
+ <properties>
+ <help>Private key</help>
+ </properties>
+ <children>
+ #include <include/pki/cli-private-key-base64.xml.i>
+ #include <include/pki/password-protected.xml.i>
+ </children>
+ </node>
+ </children>
+ </tagNode>
+ <tagNode name="openssh">
+ <properties>
+ <help>OpenSSH public and private keys</help>
+ </properties>
+ <children>
+ <node name="public">
+ <properties>
+ <help>Public key</help>
+ </properties>
+ <children>
+ #include <include/pki/cli-public-key-base64.xml.i>
</children>
</node>
<node name="private">
diff --git a/interface-definitions/protocols_rpki.xml.in b/interface-definitions/protocols_rpki.xml.in
index 6c71f69f3..54d69eadb 100644
--- a/interface-definitions/protocols_rpki.xml.in
+++ b/interface-definitions/protocols_rpki.xml.in
@@ -47,22 +47,7 @@
<help>RPKI SSH connection settings</help>
</properties>
<children>
- <leafNode name="private-key-file">
- <properties>
- <help>RPKI SSH private key file</help>
- <constraint>
- <validator name="file-path"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="public-key-file">
- <properties>
- <help>RPKI SSH public key file path</help>
- <constraint>
- <validator name="file-path"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/pki/openssh-key.xml.i>
#include <include/generic-username.xml.i>
</children>
</node>
diff --git a/interface-definitions/service_ipoe-server.xml.in b/interface-definitions/service_ipoe-server.xml.in
index 23d6e54d1..414c9a731 100644
--- a/interface-definitions/service_ipoe-server.xml.in
+++ b/interface-definitions/service_ipoe-server.xml.in
@@ -177,13 +177,18 @@
#include <include/accel-ppp/vlan.xml.i>
</children>
</tagNode>
- #include <include/accel-ppp/max-concurrent-sessions.xml.i>
- #include <include/name-server-ipv4-ipv6.xml.i>
#include <include/accel-ppp/client-ip-pool.xml.i>
- #include <include/accel-ppp/gateway-address-multi.xml.i>
#include <include/accel-ppp/client-ipv6-pool.xml.i>
#include <include/accel-ppp/default-pool.xml.i>
#include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/extended-scripts.xml.i>
+ #include <include/accel-ppp/gateway-address-multi.xml.i>
+ #include <include/accel-ppp/limits.xml.i>
+ #include <include/accel-ppp/max-concurrent-sessions.xml.i>
+ #include <include/accel-ppp/shaper.xml.i>
+ #include <include/accel-ppp/snmp.xml.i>
+ #include <include/generic-description.xml.i>
+ #include <include/name-server-ipv4-ipv6.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 477ed115f..9b5e4d3fb 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -49,9 +49,6 @@
</node>
</children>
</node>
- #include <include/accel-ppp/client-ip-pool.xml.i>
- #include <include/accel-ppp/client-ipv6-pool.xml.i>
- #include <include/name-server-ipv4-ipv6.xml.i>
<tagNode name="interface">
<properties>
<help>interface(s) to listen on</help>
@@ -63,35 +60,6 @@
#include <include/accel-ppp/vlan.xml.i>
</children>
</tagNode>
- #include <include/accel-ppp/gateway-address.xml.i>
- #include <include/accel-ppp/max-concurrent-sessions.xml.i>
- #include <include/accel-ppp/mtu-128-16384.xml.i>
- <node name="limits">
- <properties>
- <help>Limits the connection rate from a single source</help>
- </properties>
- <children>
- <leafNode name="connection-limit">
- <properties>
- <help>Acceptable rate of connections (e.g. 1/min, 60/sec)</help>
- <constraint>
- <regex>[0-9]+\/(min|sec)</regex>
- </constraint>
- <constraintErrorMessage>illegal value</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="burst">
- <properties>
- <help>Burst count</help>
- </properties>
- </leafNode>
- <leafNode name="timeout">
- <properties>
- <help>Timeout in seconds</help>
- </properties>
- </leafNode>
- </children>
- </node>
<leafNode name="service-name">
<properties>
<help>Service name</help>
@@ -102,15 +70,6 @@
<multi/>
</properties>
</leafNode>
- #include <include/accel-ppp/wins-server.xml.i>
- #include <include/accel-ppp/ppp-options.xml.i>
- <node name="ppp-options">
- <children>
- <leafNode name="min-mtu">
- <defaultValue>1280</defaultValue>
- </leafNode>
- </children>
- </node>
<tagNode name="pado-delay">
<properties>
<help>PADO delays</help>
@@ -164,61 +123,28 @@
</properties>
<defaultValue>replace</defaultValue>
</leafNode>
- #include <include/accel-ppp/shaper.xml.i>
- <node name="snmp">
- <properties>
- <help>Enable SNMP</help>
- </properties>
- <children>
- <leafNode name="master-agent">
- <properties>
- <help>enable SNMP master agent mode</help>
- <valueless />
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="extended-scripts">
- <properties>
- <help>Extended script execution</help>
- </properties>
+ #include <include/accel-ppp/client-ip-pool.xml.i>
+ #include <include/accel-ppp/client-ipv6-pool.xml.i>
+ #include <include/accel-ppp/default-pool.xml.i>
+ #include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/extended-scripts.xml.i>
+ #include <include/accel-ppp/gateway-address.xml.i>
+ #include <include/accel-ppp/limits.xml.i>
+ #include <include/accel-ppp/max-concurrent-sessions.xml.i>
+ #include <include/accel-ppp/mtu-128-16384.xml.i>
+ #include <include/accel-ppp/ppp-options.xml.i>
+ <node name="ppp-options">
<children>
- <leafNode name="on-pre-up">
- <properties>
- <help>Script to run before PPPoE session interface comes up</help>
- <constraint>
- <validator name="script"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="on-up">
- <properties>
- <help>Script to run when PPPoE session interface is completely configured and started</help>
- <constraint>
- <validator name="script"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="on-down">
- <properties>
- <help>Script to run when PPPoE session interface going to terminate</help>
- <constraint>
- <validator name="script"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="on-change">
- <properties>
- <help>Script to run when PPPoE session interface changed by RADIUS CoA handling</help>
- <constraint>
- <validator name="script"/>
- </constraint>
- </properties>
+ <leafNode name="min-mtu">
+ <defaultValue>1280</defaultValue>
</leafNode>
</children>
</node>
- #include <include/accel-ppp/default-pool.xml.i>
- #include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/shaper.xml.i>
+ #include <include/accel-ppp/snmp.xml.i>
+ #include <include/accel-ppp/wins-server.xml.i>
+ #include <include/generic-description.xml.i>
+ #include <include/name-server-ipv4-ipv6.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in
index 6148e3269..85a375db4 100644
--- a/interface-definitions/vpn_l2tp.xml.in
+++ b/interface-definitions/vpn_l2tp.xml.in
@@ -30,42 +30,6 @@
</node>
</children>
</node>
- #include <include/accel-ppp/max-concurrent-sessions.xml.i>
- #include <include/accel-ppp/mtu-128-16384.xml.i>
- <leafNode name="mtu">
- <defaultValue>1436</defaultValue>
- </leafNode>
- <leafNode name="outside-address">
- <properties>
- <help>External IP address to which VPN clients will connect</help>
- <constraint>
- <validator name="ipv4-address"/>
- </constraint>
- </properties>
- </leafNode>
- #include <include/accel-ppp/gateway-address.xml.i>
- #include <include/name-server-ipv4-ipv6.xml.i>
- <node name="lns">
- <properties>
- <help>L2TP Network Server (LNS)</help>
- </properties>
- <children>
- <leafNode name="shared-secret">
- <properties>
- <help>Tunnel password used to authenticate the client (LAC)</help>
- </properties>
- </leafNode>
- <leafNode name="host-name">
- <properties>
- <help>Sent to the client (LAC) in the Host-Name attribute</help>
- <constraint>
- #include <include/constraint/host-name.xml.i>
- </constraint>
- <constraintErrorMessage>Host-name must be alphanumeric and can contain hyphens</constraintErrorMessage>
- </properties>
- </leafNode>
- </children>
- </node>
<node name="ipsec-settings">
<properties>
<help>Internet Protocol Security (IPsec) for remote access L2TP VPN</help>
@@ -129,14 +93,53 @@
#include <include/ipsec/ike-group.xml.i>
</children>
</node>
- #include <include/accel-ppp/wins-server.xml.i>
+ <node name="lns">
+ <properties>
+ <help>L2TP Network Server (LNS)</help>
+ </properties>
+ <children>
+ <leafNode name="shared-secret">
+ <properties>
+ <help>Tunnel password used to authenticate the client (LAC)</help>
+ </properties>
+ </leafNode>
+ <leafNode name="host-name">
+ <properties>
+ <help>Sent to the client (LAC) in the Host-Name attribute</help>
+ <constraint>
+ #include <include/constraint/host-name.xml.i>
+ </constraint>
+ <constraintErrorMessage>Host-name must be alphanumeric and can contain hyphens</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="outside-address">
+ <properties>
+ <help>External IP address to which VPN clients will connect</help>
+ <constraint>
+ <validator name="ipv4-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
#include <include/accel-ppp/client-ip-pool.xml.i>
#include <include/accel-ppp/client-ipv6-pool.xml.i>
- #include <include/generic-description.xml.i>
- #include <include/dhcp-interface.xml.i>
- #include <include/accel-ppp/ppp-options.xml.i>
#include <include/accel-ppp/default-pool.xml.i>
#include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/extended-scripts.xml.i>
+ #include <include/accel-ppp/gateway-address.xml.i>
+ #include <include/accel-ppp/limits.xml.i>
+ #include <include/accel-ppp/max-concurrent-sessions.xml.i>
+ #include <include/accel-ppp/mtu-128-16384.xml.i>
+ <leafNode name="mtu">
+ <defaultValue>1436</defaultValue>
+ </leafNode>
+ #include <include/accel-ppp/ppp-options.xml.i>
+ #include <include/accel-ppp/shaper.xml.i>
+ #include <include/accel-ppp/snmp.xml.i>
+ #include <include/accel-ppp/wins-server.xml.i>
+ #include <include/generic-description.xml.i>
+ #include <include/name-server-ipv4-ipv6.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/vpn_pptp.xml.in b/interface-definitions/vpn_pptp.xml.in
index 2e2a3bec4..a63633f57 100644
--- a/interface-definitions/vpn_pptp.xml.in
+++ b/interface-definitions/vpn_pptp.xml.in
@@ -30,11 +30,6 @@
</node>
</children>
</node>
- #include <include/accel-ppp/max-concurrent-sessions.xml.i>
- #include <include/accel-ppp/mtu-128-16384.xml.i>
- <leafNode name="mtu">
- <defaultValue>1436</defaultValue>
- </leafNode>
<leafNode name="outside-address">
<properties>
<help>External IP address to which VPN clients will connect</help>
@@ -43,14 +38,24 @@
</constraint>
</properties>
</leafNode>
- #include <include/accel-ppp/gateway-address.xml.i>
- #include <include/name-server-ipv4-ipv6.xml.i>
- #include <include/accel-ppp/wins-server.xml.i>
#include <include/accel-ppp/client-ip-pool.xml.i>
- #include <include/accel-ppp/default-pool.xml.i>
#include <include/accel-ppp/client-ipv6-pool.xml.i>
+ #include <include/accel-ppp/default-pool.xml.i>
#include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/extended-scripts.xml.i>
+ #include <include/accel-ppp/gateway-address.xml.i>
+ #include <include/accel-ppp/limits.xml.i>
+ #include <include/accel-ppp/max-concurrent-sessions.xml.i>
+ #include <include/accel-ppp/mtu-128-16384.xml.i>
+ <leafNode name="mtu">
+ <defaultValue>1436</defaultValue>
+ </leafNode>
#include <include/accel-ppp/ppp-options.xml.i>
+ #include <include/accel-ppp/shaper.xml.i>
+ #include <include/accel-ppp/snmp.xml.i>
+ #include <include/accel-ppp/wins-server.xml.i>
+ #include <include/generic-description.xml.i>
+ #include <include/name-server-ipv4-ipv6.xml.i>
</children>
</node>
</children>
diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn_sstp.xml.in
index 0d5d53301..d23a001d5 100644
--- a/interface-definitions/vpn_sstp.xml.in
+++ b/interface-definitions/vpn_sstp.xml.in
@@ -25,19 +25,6 @@
</node>
</children>
</node>
- #include <include/accel-ppp/max-concurrent-sessions.xml.i>
- #include <include/interface/mtu-68-1500.xml.i>
- #include <include/accel-ppp/gateway-address.xml.i>
- #include <include/name-server-ipv4-ipv6.xml.i>
- #include <include/accel-ppp/client-ip-pool.xml.i>
- #include <include/accel-ppp/client-ipv6-pool.xml.i>
- #include <include/port-number.xml.i>
- <leafNode name="port">
- <defaultValue>443</defaultValue>
- </leafNode>
- #include <include/accel-ppp/default-pool.xml.i>
- #include <include/accel-ppp/default-ipv6-pool.xml.i>
- #include <include/accel-ppp/ppp-options.xml.i>
<node name="ssl">
<properties>
<help>SSL Certificate, SSL Key and CA</help>
@@ -47,6 +34,25 @@
#include <include/pki/certificate.xml.i>
</children>
</node>
+ #include <include/accel-ppp/client-ip-pool.xml.i>
+ #include <include/accel-ppp/client-ipv6-pool.xml.i>
+ #include <include/accel-ppp/default-pool.xml.i>
+ #include <include/accel-ppp/default-ipv6-pool.xml.i>
+ #include <include/accel-ppp/extended-scripts.xml.i>
+ #include <include/accel-ppp/gateway-address.xml.i>
+ #include <include/accel-ppp/limits.xml.i>
+ #include <include/accel-ppp/max-concurrent-sessions.xml.i>
+ #include <include/interface/mtu-68-1500.xml.i>
+ #include <include/port-number.xml.i>
+ <leafNode name="port">
+ <defaultValue>443</defaultValue>
+ </leafNode>
+ #include <include/accel-ppp/ppp-options.xml.i>
+ #include <include/accel-ppp/shaper.xml.i>
+ #include <include/accel-ppp/snmp.xml.i>
+ #include <include/accel-ppp/wins-server.xml.i>
+ #include <include/generic-description.xml.i>
+ #include <include/name-server-ipv4-ipv6.xml.i>
</children>
</node>
</children>
diff --git a/op-mode-definitions/dhcp.xml.in b/op-mode-definitions/dhcp.xml.in
index ceb321f3e..0db7471e5 100644
--- a/op-mode-definitions/dhcp.xml.in
+++ b/op-mode-definitions/dhcp.xml.in
@@ -80,6 +80,32 @@
</tagNode>
</children>
</node>
+ <node name="static-mappings">
+ <properties>
+ <help>Show DHCP server static mappings</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet</command>
+ <children>
+ <tagNode name="pool">
+ <properties>
+ <help>Show DHCP server static mappings for a specific pool</help>
+ <completionHelp>
+ <path>service dhcp-server shared-network-name</path>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet --pool $6</command>
+ </tagNode>
+ <tagNode name="sort">
+ <properties>
+ <help>Show DHCP server static mappings sorted by the specified key</help>
+ <completionHelp>
+ <list>ip mac duid pool</list>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet --sort $6</command>
+ </tagNode>
+ </children>
+ </node>
<node name="statistics">
<properties>
<help>Show DHCP server statistics</help>
@@ -130,7 +156,7 @@
<properties>
<help>Show DHCPv6 server leases sorted by the specified key</help>
<completionHelp>
- <list>end iaid_duid ip last_communication pool remaining state type</list>
+ <list>end duid ip last_communication pool remaining state type</list>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/dhcp.py show_server_leases --family inet6 --sort $6</command>
@@ -146,6 +172,32 @@
</tagNode>
</children>
</node>
+ <node name="static-mappings">
+ <properties>
+ <help>Show DHCPv6 server static mappings</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet6</command>
+ <children>
+ <tagNode name="pool">
+ <properties>
+ <help>Show DHCPv6 server static mappings for a specific pool</help>
+ <completionHelp>
+ <path>service dhcp-server shared-network-name</path>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet6 --pool $6</command>
+ </tagNode>
+ <tagNode name="sort">
+ <properties>
+ <help>Show DHCPv6 server static mappings sorted by the specified key</help>
+ <completionHelp>
+ <list>ip mac duid pool</list>
+ </completionHelp>
+ </properties>
+ <command>${vyos_op_scripts_dir}/dhcp.py show_server_static_mappings --family inet6 --sort $6</command>
+ </tagNode>
+ </children>
+ </node>
</children>
</node>
</children>
diff --git a/python/vyos/accel_ppp_util.py b/python/vyos/accel_ppp_util.py
index bd0c46a19..845b2f5f0 100644
--- a/python/vyos/accel_ppp_util.py
+++ b/python/vyos/accel_ppp_util.py
@@ -106,7 +106,26 @@ def get_pools_in_order(data: dict) -> list:
return pools
-def verify_accel_ppp_base_service(config, local_users=True):
+def verify_accel_ppp_name_servers(config):
+ if "name_server_ipv4" in config:
+ if len(config["name_server_ipv4"]) > 2:
+ raise ConfigError(
+ "Not more then two IPv4 DNS name-servers " "can be configured"
+ )
+ if "name_server_ipv6" in config:
+ if len(config["name_server_ipv6"]) > 3:
+ raise ConfigError(
+ "Not more then three IPv6 DNS name-servers " "can be configured"
+ )
+
+
+def verify_accel_ppp_wins_servers(config):
+ if 'wins_server' in config and len(config['wins_server']) > 2:
+ raise ConfigError(
+ 'Not more then two WINS name-servers can be configured')
+
+
+def verify_accel_ppp_authentication(config, local_users=True):
"""
Common helper function which must be used by all Accel-PPP services based
on get_config_dict()
@@ -148,17 +167,6 @@ def verify_accel_ppp_base_service(config, local_users=True):
if not dict_search('authentication.radius.dynamic_author.key', config):
raise ConfigError('DAE/CoA server key required!')
- if "name_server_ipv4" in config:
- if len(config["name_server_ipv4"]) > 2:
- raise ConfigError(
- "Not more then two IPv4 DNS name-servers " "can be configured"
- )
-
- if "name_server_ipv6" in config:
- if len(config["name_server_ipv6"]) > 3:
- raise ConfigError(
- "Not more then three IPv6 DNS name-servers " "can be configured"
- )
diff --git a/python/vyos/kea.py b/python/vyos/kea.py
index 7365c1f02..894ac9e9a 100644
--- a/python/vyos/kea.py
+++ b/python/vyos/kea.py
@@ -17,8 +17,6 @@ import json
import os
import socket
-from datetime import datetime
-
from vyos.template import is_ipv6
from vyos.template import isc_static_route
from vyos.template import netmask_from_cidr
@@ -293,29 +291,6 @@ def kea6_parse_subnet(subnet, config):
return out
-def kea_parse_leases(lease_path):
- contents = read_file(lease_path)
- lines = contents.split("\n")
- output = []
-
- if len(lines) < 2:
- return output
-
- headers = lines[0].split(",")
-
- for line in lines[1:]:
- line_out = dict(zip(headers, line.split(",")))
-
- lifetime = int(line_out['valid_lifetime'])
- expiry = int(line_out['expire'])
-
- line_out['start_timestamp'] = datetime.utcfromtimestamp(expiry - lifetime)
- line_out['expire_timestamp'] = datetime.utcfromtimestamp(expiry) if expiry else None
-
- output.append(line_out)
-
- return output
-
def _ctrl_socket_command(path, command, args=None):
if not os.path.exists(path):
return None
@@ -340,6 +315,16 @@ def _ctrl_socket_command(path, command, args=None):
return json.loads(result.decode('utf-8'))
+def kea_get_leases(inet):
+ ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
+
+ leases = _ctrl_socket_command(ctrl_socket, f'lease{inet}-get-all')
+
+ if not leases or 'result' not in leases or leases['result'] != 0:
+ return []
+
+ return leases['arguments']['leases']
+
def kea_get_active_config(inet):
ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket'
diff --git a/python/vyos/pki.py b/python/vyos/pki.py
index 792e24b76..02dece471 100644
--- a/python/vyos/pki.py
+++ b/python/vyos/pki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -20,7 +20,9 @@ import ipaddress
from cryptography import x509
from cryptography.exceptions import InvalidSignature
from cryptography.x509.extensions import ExtensionNotFound
-from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, ExtensionOID
+from cryptography.x509.oid import NameOID
+from cryptography.x509.oid import ExtendedKeyUsageOID
+from cryptography.x509.oid import ExtensionOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import dh
@@ -45,6 +47,8 @@ DH_BEGIN='-----BEGIN DH PARAMETERS-----\n'
DH_END='\n-----END DH PARAMETERS-----'
OVPN_BEGIN = '-----BEGIN OpenVPN Static key V{0}-----\n'
OVPN_END = '\n-----END OpenVPN Static key V{0}-----'
+OPENSSH_KEY_BEGIN='-----BEGIN OPENSSH PRIVATE KEY-----\n'
+OPENSSH_KEY_END='\n-----END OPENSSH PRIVATE KEY-----'
# Print functions
@@ -229,6 +233,12 @@ def wrap_public_key(raw_data):
def wrap_private_key(raw_data, passphrase=None):
return (KEY_ENC_BEGIN if passphrase else KEY_BEGIN) + raw_data + (KEY_ENC_END if passphrase else KEY_END)
+def wrap_openssh_public_key(raw_data, type):
+ return f'{type} {raw_data}'
+
+def wrap_openssh_private_key(raw_data):
+ return OPENSSH_KEY_BEGIN + raw_data + OPENSSH_KEY_END
+
def wrap_certificate_request(raw_data):
return CSR_BEGIN + raw_data + CSR_END
@@ -245,7 +255,6 @@ def wrap_openvpn_key(raw_data, version='1'):
return OVPN_BEGIN.format(version) + raw_data + OVPN_END.format(version)
# Load functions
-
def load_public_key(raw_data, wrap_tags=True):
if wrap_tags:
raw_data = wrap_public_key(raw_data)
@@ -267,6 +276,21 @@ def load_private_key(raw_data, passphrase=None, wrap_tags=True):
except ValueError:
return False
+def load_openssh_public_key(raw_data, type):
+ try:
+ return serialization.load_ssh_public_key(bytes(f'{type} {raw_data}', 'utf-8'))
+ except ValueError:
+ return False
+
+def load_openssh_private_key(raw_data, passphrase=None, wrap_tags=True):
+ if wrap_tags:
+ raw_data = wrap_openssh_private_key(raw_data)
+
+ try:
+ return serialization.load_ssh_private_key(bytes(raw_data, 'utf-8'), password=passphrase)
+ except ValueError:
+ return False
+
def load_certificate_request(raw_data, wrap_tags=True):
if wrap_tags:
raw_data = wrap_certificate_request(raw_data)
@@ -429,4 +453,3 @@ def sort_ca_chain(ca_names, pki_node):
from functools import cmp_to_key
return sorted(ca_names, key=cmp_to_key(lambda cert1, cert2: ca_cmp(cert1, cert2, pki_node)))
-
diff --git a/smoketest/bin/vyos-configtest-pki b/smoketest/bin/vyos-configtest-pki
index 2f8af0e61..e753193e9 100755
--- a/smoketest/bin/vyos-configtest-pki
+++ b/smoketest/bin/vyos-configtest-pki
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022, VyOS maintainers and contributors
+# Copyright (C) 2022-2024, 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
@@ -23,6 +23,7 @@ from vyos.pki import create_dh_parameters
from vyos.pki import encode_certificate
from vyos.pki import encode_dh_parameters
from vyos.pki import encode_private_key
+from vyos.utils.file import write_file
subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos'}
ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos CA'}
@@ -41,6 +42,40 @@ dh_pem = '/config/auth/ovpn_test_dh.pem'
s2s_key = '/config/auth/ovpn_test_site2site.key'
auth_key = '/config/auth/ovpn_test_tls_auth.key'
+rpki_ssh_priv_key = """
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1x
+Kf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rn
+jgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3Vz
+Wp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/F
+IjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfT
+aooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZll
+z6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV
+7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVh
+M80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfh
+noMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6j
+daWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5
+WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQ
+zPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafH
+TThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t
+1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTj
+IpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIue
+ozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL
+6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w1
+0JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh
++l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS2
+36JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBw
+oWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8
+BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdy
+e8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw==
+-----END OPENSSH PRIVATE KEY-----
+"""
+
+rpki_ssh_pub_key = """
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0el vyos@vyos
+"""
+
def create_cert(subject, cert_path, key_path, sign_by=None, sign_by_key=None, ca=False, sub_ca=False):
priv_key = create_private_key('rsa', 2048)
cert_req = create_certificate_request(subject, priv_key)
@@ -98,3 +133,7 @@ if __name__ == '__main__':
# OpenVPN Auth Key
system(f'openvpn --genkey secret {auth_key}')
+
+ write_file('/config/id_rsa', rpki_ssh_priv_key.strip())
+ write_file('/config/id_rsa.pub', rpki_ssh_pub_key.strip())
+ write_file('/config/known-hosts-file', '')
diff --git a/smoketest/config-tests/rpki-only b/smoketest/config-tests/rpki-only
new file mode 100644
index 000000000..569463b12
--- /dev/null
+++ b/smoketest/config-tests/rpki-only
@@ -0,0 +1,30 @@
+set interfaces ethernet eth0 address '192.0.2.1/24'
+set interfaces ethernet eth0 address '2001:db8::1/64'
+set interfaces loopback lo
+set pki openssh rpki-5.6.7.8 private key 'b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1xKf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rnjgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3VzWp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/FIjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfTaooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQzPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafHTThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTjIpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIueozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w10JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh+l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS236JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBwoWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdye8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw=='
+set pki openssh rpki-5.6.7.8 public key 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0el'
+set pki openssh rpki-5.6.7.8 public type 'ssh-rsa'
+set policy route-map ROUTES-IN rule 10 action 'permit'
+set policy route-map ROUTES-IN rule 10 match rpki 'valid'
+set policy route-map ROUTES-IN rule 10 set local-preference '300'
+set policy route-map ROUTES-IN rule 20 action 'permit'
+set policy route-map ROUTES-IN rule 20 match rpki 'notfound'
+set policy route-map ROUTES-IN rule 20 set local-preference '125'
+set policy route-map ROUTES-IN rule 30 action 'deny'
+set policy route-map ROUTES-IN rule 30 match rpki 'invalid'
+set protocols bgp neighbor 192.0.2.200 address-family ipv4-unicast route-map import 'ROUTES-IN'
+set protocols bgp neighbor 192.0.2.200 remote-as '200'
+set protocols bgp neighbor 2001:db8::200 address-family ipv6-unicast route-map import 'ROUTES-IN'
+set protocols bgp neighbor 2001:db8::200 remote-as '200'
+set protocols bgp system-as '100'
+set protocols rpki cache 1.2.3.4 port '3323'
+set protocols rpki cache 1.2.3.4 preference '10'
+set protocols rpki cache 5.6.7.8 port '2222'
+set protocols rpki cache 5.6.7.8 preference '20'
+set protocols rpki cache 5.6.7.8 ssh key 'rpki-5.6.7.8'
+set protocols rpki cache 5.6.7.8 ssh username 'vyos'
+set system host-name 'vyos'
+set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0'
+set system login user vyos authentication plaintext-password ''
+set system syslog global facility all level 'debug'
+set system console device ttyS0 speed '115200'
diff --git a/smoketest/configs/rpki-only b/smoketest/configs/rpki-only
new file mode 100644
index 000000000..98e9892ad
--- /dev/null
+++ b/smoketest/configs/rpki-only
@@ -0,0 +1,122 @@
+interfaces {
+ ethernet eth0 {
+ duplex auto
+ speed auto
+ address 192.0.2.1/24
+ address 2001:db8::1/64
+ }
+ loopback lo {
+ }
+}
+policy {
+ route-map ROUTES-IN {
+ rule 10 {
+ action permit
+ match {
+ rpki valid
+ }
+ set {
+ local-preference 300
+ }
+ }
+ rule 20 {
+ action permit
+ match {
+ rpki notfound
+ }
+ set {
+ local-preference 125
+ }
+ }
+ rule 30 {
+ action deny
+ match {
+ rpki invalid
+ }
+ }
+ }
+}
+protocols {
+ bgp 100 {
+ neighbor 192.0.2.200 {
+ address-family {
+ ipv4-unicast {
+ route-map {
+ import ROUTES-IN
+ }
+ }
+ }
+ remote-as 200
+ }
+ neighbor 2001:db8::200 {
+ address-family {
+ ipv6-unicast {
+ route-map {
+ import ROUTES-IN
+ }
+ }
+ }
+ remote-as 200
+ }
+ }
+ rpki {
+ cache 1.2.3.4 {
+ port 3323
+ preference 10
+ }
+ cache 5.6.7.8 {
+ port 2222
+ preference 20
+ ssh {
+ known-hosts-file "/config/known-hosts-file"
+ private-key-file "/config/id_rsa"
+ public-key-file "/config/id_rsa.pub"
+ username vyos
+ }
+ }
+ }
+}
+system {
+ config-management {
+ commit-revisions 200
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ conntrack {
+ modules {
+ ftp
+ h323
+ nfs
+ pptp
+ sip
+ sqlnet
+ tftp
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0
+ plaintext-password ""
+ }
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level debug
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:container@1:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.3.5
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 0e6e522b9..ac4bbcfe5 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -558,4 +558,53 @@ delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
self.assertEqual(conf['ppp']['lcp-echo-failure'], lcp_failure)
self.assertEqual(conf['ppp']['lcp-echo-interval'], lcp_interval)
- self.assertEqual(conf['ppp']['lcp-echo-timeout'], lcp_timeout) \ No newline at end of file
+ self.assertEqual(conf['ppp']['lcp-echo-timeout'], lcp_timeout)
+
+
+ def test_accel_wins_server(self):
+ self.basic_config()
+ winsservers = ["192.0.2.1", "192.0.2.2"]
+ for wins in winsservers:
+ self.set(["wins-server", wins])
+ self.cli_commit()
+ conf = ConfigParser(allow_no_value=True, delimiters="=", strict=False)
+ conf.read(self._config_file)
+ for ws in winsservers:
+ self.assertIn(ws, [conf["wins"]["wins1"], conf["wins"]["wins2"]])
+
+ def test_accel_snmp(self):
+ self.basic_config()
+ self.set(['snmp', 'master-agent'])
+ self.cli_commit()
+ conf = ConfigParser(allow_no_value=True, delimiters="=", strict=False)
+ conf.read(self._config_file)
+ self.assertEqual(conf['modules']['net-snmp'], None)
+ self.assertEqual(conf['snmp']['master'],'1')
+
+ def test_accel_shaper(self):
+ self.basic_config()
+ fwmark = '2'
+ self.set(['shaper', 'fwmark', fwmark])
+ self.cli_commit()
+ conf = ConfigParser(allow_no_value=True, delimiters="=", strict=False)
+ conf.read(self._config_file)
+ self.assertEqual(conf['modules']['shaper'], None)
+ self.assertEqual(conf['shaper']['verbose'], '1')
+ self.assertEqual(conf['shaper']['down-limiter'], 'tbf')
+ self.assertEqual(conf['shaper']['fwmark'], fwmark)
+
+ def test_accel_limits(self):
+ self.basic_config()
+ burst = '100'
+ timeout = '20'
+ limits = '1/min'
+ self.set(['limits', 'connection-limit', limits])
+ self.set(['limits', 'timeout', timeout])
+ self.set(['limits', 'burst', burst])
+ self.cli_commit()
+ conf = ConfigParser(allow_no_value=True, delimiters="=", strict=False)
+ conf.read(self._config_file)
+ self.assertEqual(conf['modules']['connlimit'], None)
+ self.assertEqual(conf['connlimit']['limit'], limits)
+ self.assertEqual(conf['connlimit']['burst'], burst)
+ self.assertEqual(conf['connlimit']['timeout'], timeout)
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 415f3436f..bc2848492 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -813,7 +813,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
def test_flow_offload(self):
- self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0'])
+ self.cli_set(['interfaces', 'ethernet', 'eth0', 'vif', '10'])
+ self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0.10'])
self.cli_set(['firewall', 'flowtable', 'smoketest', 'offload', 'hardware'])
# QEMU virtual NIC does not support hw-tc-offload
@@ -839,7 +840,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_search = [
['flowtable VYOS_FLOWTABLE_smoketest'],
['hook ingress priority filter'],
- ['devices = { eth0 }'],
+ ['devices = { eth0.10 }'],
['ct state { established, related }', 'meta l4proto { tcp, udp }', 'flow add @VYOS_FLOWTABLE_smoketest'],
]
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index eadd8a004..1d68ae08b 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -751,7 +751,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
def test_bgp_07_l2vpn_evpn(self):
vnis = ['10010', '10020', '10030']
- neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30']
+ soo = '1.2.3.4:10000'
evi_limit = '1000'
route_targets = ['1.1.1.1:100', '1.1.1.1:200', '1.1.1.1:300']
@@ -763,6 +763,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'default-originate', 'ipv6'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-rx'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'disable-ead-evi-tx'])
+ self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'mac-vrf', 'soo', soo])
for vni in vnis:
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw'])
self.cli_set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip'])
@@ -786,6 +787,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.assertIn(f' disable-ead-evi-rx', frrconfig)
self.assertIn(f' disable-ead-evi-tx', frrconfig)
self.assertIn(f' flooding disable', frrconfig)
+ self.assertIn(f' mac-vrf soo {soo}', frrconfig)
for vni in vnis:
vniconfig = self.getFRRconfig(f' vni {vni}')
self.assertIn(f'vni {vni}', vniconfig)
diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py
index c52c0dd76..29f03a26a 100755
--- a/smoketest/scripts/cli/test_protocols_rpki.py
+++ b/smoketest/scripts/cli/test_protocols_rpki.py
@@ -14,20 +14,93 @@
# 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
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
-from vyos.utils.process import cmd
+from vyos.utils.file import read_file
from vyos.utils.process import process_named_running
base_path = ['protocols', 'rpki']
PROCESS_NAME = 'bgpd'
-rpki_ssh_key = '/config/auth/id_rsa_rpki'
-rpki_ssh_pub = f'{rpki_ssh_key}.pub'
+rpki_key_name = 'rpki-smoketest'
+rpki_key_type = 'ssh-rsa'
+
+rpki_ssh_key = """
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1x
+Kf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rn
+jgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3Vz
+Wp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/F
+IjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfT
+aooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZll
+z6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV
+7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVh
+M80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfh
+noMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6j
+daWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5
+WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQ
+zPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafH
+TThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t
+1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTj
+IpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIue
+ozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL
+6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w1
+0JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh
++l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS2
+36JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBw
+oWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8
+BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdy
+e8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw==
+"""
+
+rpki_ssh_pub = """
+AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYi
+SO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqp
+FN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqy
+iGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD
+6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1
+AbbYRPIku+F9Nqig0tP0el
+"""
+
+rpki_ssh_key_replacement = """
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAtLPMwiGR3o6puPDbus9Yqoah9/7rv7i6ykykPmcEZ6ERnA0N6bl7
+LkQxnCuX270ukTTZOhROvQnvQYIZohCMz27Q16z7r+I755QXL0x8x4Gqhg/hQUY7UtX6ts
+db8+pO7G1PL4r9zT6/KJAF/wv86DezJ3I6TMaA7MCikXfQWJisBvhgAXF1+7V9CWaroGgV
+/hHzQJu1yd4cfsYoHyeDaZ+lwFw4egNItIy63fIGDxrnXaonJ1ODGQh7zWlpl/cwQR/KyJ
+P8vvOZ9olQ6syZV+DAcAo4Fe59wW2Zj4bl8bdGcdiDn0grkafxwTcg9ynr9kwQ8b66oXY4
+hwB4vlPFPwAAA8jkGyX45Bsl+AAAAAdzc2gtcnNhAAABAQC0s8zCIZHejqm48Nu6z1iqhq
+H3/uu/uLrKTKQ+ZwRnoRGcDQ3puXsuRDGcK5fbvS6RNNk6FE69Ce9BghmiEIzPbtDXrPuv
+4jvnlBcvTHzHgaqGD+FBRjtS1fq2x1vz6k7sbU8viv3NPr8okAX/C/zoN7MncjpMxoDswK
+KRd9BYmKwG+GABcXX7tX0JZqugaBX+EfNAm7XJ3hx+xigfJ4Npn6XAXDh6A0i0jLrd8gYP
+GuddqicnU4MZCHvNaWmX9zBBH8rIk/y+85n2iVDqzJlX4MBwCjgV7n3BbZmPhuXxt0Zx2I
+OfSCuRp/HBNyD3Kev2TBDxvrqhdjiHAHi+U8U/AAAAAwEAAQAAAQA99gkX5/rknXaE+9Hc
+VIzKrC+NodOkgetKwszuuNRB1HD9WVyT8A3U5307V5dSuaPmFoEF8UCugWGQzNONRq+B0T
+W7Po1u2dxAo/7vMQL4RfX60icjAroExWqakfFtycIWP8UPQFGWtxVFC12C/tFRrwe3Vuu2
+t7otdEBKMRM3zU0Hj88/5FIk/MDhththDCKTMe4+iwNKo30dyqSCckpTd2k5de9JYz8Aom
+87jtQcyDdynaELSo9CsA8KRPlozZ4VSWTVLH+Cv2TZWPL7hy79YvvIfuF/Sd6PGkNwG1Vj
+TAbq2Wx4uq+HmpNiz7W0LnbZtQJ7dzLA3FZlvQMC8fVBAAAAgQDWvImVZCyVWpoG+LnKY3
+joegjKRYKdgKRPCqGoIHiYsqCRxqSRW3jsuQCCvk4YO3/ZmqORiGktK+5r8R1QEtwg5qbi
+N7GZD34m7USNuqG2G/4puEly8syMmR6VRRvEURFQrpv2wniXNSefvsDc+WDqTfXGUxr+FT
+478wkzjwc/fAAAAIEA9uP0Ym3OC3cZ5FOvmu51lxo5lqPlUeE78axg2I4u/9Il8nOvSVuq
+B9X5wAUyGAGcUjT3EZmRAtL2sQxc5T0Vw3bnxCjzukEbFM+DRtYy1hXSOoGTTwKoMWBpho
+R3X5uRLUQL/22C4rd7tSJpjqnZXIH0B5z2fFh4vzu8/SrgCrUAAACBALtep4BcGJfjfhfF
+ODzQe7Rk7tsaX8pfNv6bQu0sR5C9pDURFRf0fRC0oqgeTuzq/vHPyNLsUUgTCpKWiLFmvU
+G9pelLT3XPPgzA+g0gycM0unuX8kkP3T5VQAM/7u0+h1CaJ8A6cCkzvDJxYdfio3WR60OP
+ulHg7HCcyomFLaSjAAAADGNwb0BMUjEud3VlMwECAwQFBg==
+"""
+
+rpki_ssh_pub_replacement = """
+AAAAB3NzaC1yc2EAAAADAQABAAABAQC0s8zCIZHejqm48Nu6z1iqhqH3/uu/uLrKTKQ+Zw
+RnoRGcDQ3puXsuRDGcK5fbvS6RNNk6FE69Ce9BghmiEIzPbtDXrPuv4jvnlBcvTHzHgaqG
+D+FBRjtS1fq2x1vz6k7sbU8viv3NPr8okAX/C/zoN7MncjpMxoDswKKRd9BYmKwG+GABcX
+X7tX0JZqugaBX+EfNAm7XJ3hx+xigfJ4Npn6XAXDh6A0i0jLrd8gYPGuddqicnU4MZCHvN
+aWmX9zBBH8rIk/y+85n2iVDqzJlX4MBwCjgV7n3BbZmPhuXxt0Zx2IOfSCuRp/HBNyD3Ke
+v2TBDxvrqhdjiHAHi+U8U/
+"""
class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
@classmethod
@@ -44,10 +117,6 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
self.cli_delete(base_path)
self.cli_commit()
- # Nothing RPKI specific should be left over in the config
- # frrconfig = self.getFRRconfig('rpki')
- # self.assertNotIn('rpki', frrconfig)
-
# check process health and continuity
self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME))
@@ -107,28 +176,52 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
},
}
- self.cli_set(base_path + ['polling-period', polling])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key.replace('\n','')])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub.replace('\n','')])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'type', rpki_key_type])
- for peer, peer_config in cache.items():
- self.cli_set(base_path + ['cache', peer, 'port', peer_config['port']])
- self.cli_set(base_path + ['cache', peer, 'preference', peer_config['preference']])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'username', peer_config['username']])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'public-key-file', rpki_ssh_pub])
- self.cli_set(base_path + ['cache', peer, 'ssh', 'private-key-file', rpki_ssh_key])
+ for cache_name, cache_config in cache.items():
+ self.cli_set(base_path + ['cache', cache_name, 'port', cache_config['port']])
+ self.cli_set(base_path + ['cache', cache_name, 'preference', cache_config['preference']])
+ self.cli_set(base_path + ['cache', cache_name, 'ssh', 'username', cache_config['username']])
+ self.cli_set(base_path + ['cache', cache_name, 'ssh', 'key', rpki_key_name])
# commit changes
self.cli_commit()
# Verify FRR configuration
frrconfig = self.getFRRconfig('rpki')
- self.assertIn(f'rpki polling_period {polling}', frrconfig)
+ for cache_name, cache_config in cache.items():
+ port = cache_config['port']
+ preference = cache_config['preference']
+ username = cache_config['username']
+ self.assertIn(f'rpki cache {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig)
+
+ # Verify content of SSH keys
+ tmp = read_file(f'/run/frr/id_rpki_{cache_name}')
+ self.assertIn(rpki_ssh_key.replace('\n',''), tmp)
+ tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub')
+ self.assertIn(rpki_ssh_pub.replace('\n',''), tmp)
+
+ # Change OpenSSH key and verify it was properly written to filesystem
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'private', 'key', rpki_ssh_key_replacement.replace('\n','')])
+ self.cli_set(['pki', 'openssh', rpki_key_name, 'public', 'key', rpki_ssh_pub_replacement.replace('\n','')])
+ # commit changes
+ self.cli_commit()
- for peer, peer_config in cache.items():
- port = peer_config['port']
- preference = peer_config['preference']
- username = peer_config['username']
- self.assertIn(f'rpki cache {peer} {port} {username} {rpki_ssh_key} {rpki_ssh_pub} preference {preference}', frrconfig)
+ for cache_name, cache_config in cache.items():
+ port = cache_config['port']
+ preference = cache_config['preference']
+ username = cache_config['username']
+ self.assertIn(f'rpki cache {cache_name} {port} {username} /run/frr/id_rpki_{cache_name} /run/frr/id_rpki_{cache_name}.pub preference {preference}', frrconfig)
+ # Verify content of SSH keys
+ tmp = read_file(f'/run/frr/id_rpki_{cache_name}')
+ self.assertIn(rpki_ssh_key_replacement.replace('\n',''), tmp)
+ tmp = read_file(f'/run/frr/id_rpki_{cache_name}.pub')
+ self.assertIn(rpki_ssh_pub_replacement.replace('\n',''), tmp)
+
+ self.cli_delete(['pki', 'openssh'])
def test_rpki_verify_preference(self):
cache = {
@@ -150,10 +243,5 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase):
with self.assertRaises(ConfigSessionError):
self.cli_commit()
-
if __name__ == '__main__':
- # Create OpenSSH keypair used in RPKI tests
- if not os.path.isfile(rpki_ssh_key):
- cmd(f'ssh-keygen -t rsa -f {rpki_ssh_key} -N ""')
-
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_ipoe-server.py b/smoketest/scripts/cli/test_service_ipoe-server.py
index 20a168b58..5f1cf9ad1 100755
--- a/smoketest/scripts/cli/test_service_ipoe-server.py
+++ b/smoketest/scripts/cli/test_service_ipoe-server.py
@@ -232,5 +232,9 @@ delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
def test_accel_ppp_options(self):
pass
+ @unittest.skip("WINS server is not used in IPoE")
+ def test_accel_wins_server(self):
+ pass
+
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index cea34138e..ce237a6e7 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -328,10 +328,10 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
nftables_search = [
['ct timeout ct-timeout-1 {'],
['protocol tcp'],
- ['policy = { syn_sent : 77, established : 99, close : 88 }'],
+ ['policy = { syn_sent : 1m17s, established : 1m39s, close : 1m28s }'],
['ct timeout ct-timeout-2 {'],
['protocol udp'],
- ['policy = { unreplied : 55 }'],
+ ['policy = { unreplied : 55s }'],
['chain VYOS_CT_TIMEOUT {'],
['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'ct timeout set "ct-timeout-1"'],
['iifname "eth1"', 'meta l4proto udp', 'ip saddr 198.51.100.1', 'ct timeout set "ct-timeout-2"']
@@ -340,7 +340,7 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
nftables6_search = [
['ct timeout ct-timeout-1 {'],
['protocol tcp'],
- ['policy = { last_ack : 33, time_wait : 22 }'],
+ ['policy = { last_ack : 33s, time_wait : 22s }'],
['chain VYOS_CT_TIMEOUT {'],
['iifname "eth2"', 'meta l4proto tcp', 'ip6 saddr 2001:db8::1', 'ct timeout set "ct-timeout-1"']
]
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py
index 4be40e99e..3ab6ac5c3 100755
--- a/src/conf_mode/pki.py
+++ b/src/conf_mode/pki.py
@@ -24,11 +24,12 @@ from vyos.config import config_dict_merge
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
from vyos.configdict import node_changed
-from vyos.configdiff import Diff
from vyos.defaults import directories
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
from vyos.pki import load_public_key
+from vyos.pki import load_openssh_public_key
+from vyos.pki import load_openssh_private_key
from vyos.pki import load_private_key
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
@@ -64,6 +65,10 @@ sync_search = [
'path': ['interfaces', 'sstpc'],
},
{
+ 'keys': ['key'],
+ 'path': ['protocols', 'rpki', 'cache'],
+ },
+ {
'keys': ['certificate', 'ca_certificate', 'local_key', 'remote_key'],
'path': ['vpn', 'ipsec'],
},
@@ -86,7 +91,8 @@ sync_translate = {
'remote_key': 'key_pair',
'shared_secret_key': 'openvpn',
'auth_key': 'openvpn',
- 'crypt_key': 'openvpn'
+ 'crypt_key': 'openvpn',
+ 'key': 'openssh',
}
def certbot_delete(certificate):
@@ -150,6 +156,11 @@ def get_config(config=None):
if 'changed' not in pki: pki.update({'changed':{}})
pki['changed'].update({'key_pair' : tmp})
+ tmp = node_changed(conf, base + ['openssh'], recursive=True)
+ if tmp:
+ if 'changed' not in pki: pki.update({'changed':{}})
+ pki['changed'].update({'openssh' : tmp})
+
tmp = node_changed(conf, base + ['openvpn', 'shared-secret'], recursive=True)
if tmp:
if 'changed' not in pki: pki.update({'changed':{}})
@@ -241,6 +252,17 @@ def is_valid_private_key(raw_data, protected=False):
return True
return load_private_key(raw_data, passphrase=None, wrap_tags=True)
+def is_valid_openssh_public_key(raw_data, type):
+ # If it loads correctly we're good, or return False
+ return load_openssh_public_key(raw_data, type)
+
+def is_valid_openssh_private_key(raw_data, protected=False):
+ # If it loads correctly we're good, or return False
+ # With encrypted private keys, we always return true as we cannot ask for password to verify
+ if protected:
+ return True
+ return load_openssh_private_key(raw_data, passphrase=None, wrap_tags=True)
+
def is_valid_crl(raw_data):
# If it loads correctly we're good, or return False
return load_crl(raw_data, wrap_tags=True)
@@ -322,6 +344,20 @@ def verify(pki):
if not is_valid_private_key(private['key'], protected):
raise ConfigError(f'Invalid private key on key-pair "{name}"')
+ if 'openssh' in pki:
+ for name, key_conf in pki['openssh'].items():
+ if 'public' in key_conf and 'key' in key_conf['public']:
+ if 'type' not in key_conf['public']:
+ raise ConfigError(f'Must define OpenSSH public key type for "{name}"')
+ if not is_valid_openssh_public_key(key_conf['public']['key'], key_conf['public']['type']):
+ raise ConfigError(f'Invalid OpenSSH public key "{name}"')
+
+ if 'private' in key_conf and 'key' in key_conf['private']:
+ private = key_conf['private']
+ protected = 'password_protected' in private
+ if not is_valid_openssh_private_key(private['key'], protected):
+ raise ConfigError(f'Invalid OpenSSH private key "{name}"')
+
if 'x509' in pki:
if 'default' in pki['x509']:
default_values = pki['x509']['default']
diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py
index 609b39065..c13e52a3d 100755
--- a/src/conf_mode/protocols_eigrp.py
+++ b/src/conf_mode/protocols_eigrp.py
@@ -19,6 +19,7 @@ from sys import argv
from vyos.config import Config
from vyos.configdict import dict_merge
+from vyos.configverify import verify_vrf
from vyos.template import render_to_string
from vyos import ConfigError
from vyos import frr
@@ -72,7 +73,14 @@ def get_config(config=None):
return eigrp
def verify(eigrp):
- pass
+ if not eigrp or 'deleted' in eigrp:
+ return
+
+ if 'system_as' not in eigrp:
+ raise ConfigError('EIGRP system-as must be defined!')
+
+ if 'vrf' in eigrp:
+ verify_vrf(eigrp)
def generate(eigrp):
if not eigrp or 'deleted' in eigrp:
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index 0fc14e868..a59ecf3e4 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -16,16 +16,22 @@
import os
+from glob import glob
from sys import exit
from vyos.config import Config
+from vyos.pki import wrap_openssh_public_key
+from vyos.pki import wrap_openssh_private_key
from vyos.template import render_to_string
-from vyos.utils.dict import dict_search
+from vyos.utils.dict import dict_search_args
+from vyos.utils.file import write_file
from vyos import ConfigError
from vyos import frr
from vyos import airbag
airbag.enable()
+rpki_ssh_key_base = '/run/frr/id_rpki'
+
def get_config(config=None):
if config:
conf = config
@@ -33,7 +39,8 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'rpki']
- rpki = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ rpki = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True, with_pki=True)
# Bail out early if configuration tree does not exist
if not conf.exists(base):
rpki.update({'deleted' : ''})
@@ -63,22 +70,40 @@ def verify(rpki):
preferences.append(preference)
if 'ssh' in peer_config:
- files = ['private_key_file', 'public_key_file']
- for file in files:
- if file not in peer_config['ssh']:
- raise ConfigError('RPKI+SSH requires username and public/private ' \
- 'key file to be defined!')
+ if 'username' not in peer_config['ssh']:
+ raise ConfigError('RPKI+SSH requires username to be defined!')
+
+ if 'key' not in peer_config['ssh'] or 'openssh' not in rpki['pki']:
+ raise ConfigError('RPKI+SSH requires key to be defined!')
- filename = peer_config['ssh'][file]
- if not os.path.exists(filename):
- raise ConfigError(f'RPKI SSH {file.replace("-","-")} "{filename}" does not exist!')
+ if peer_config['ssh']['key'] not in rpki['pki']['openssh']:
+ raise ConfigError('RPKI+SSH key not found on PKI subsystem!')
return None
def generate(rpki):
+ for key in glob(f'{rpki_ssh_key_base}*'):
+ os.unlink(key)
+
if not rpki:
return
+
+ if 'cache' in rpki:
+ for cache, cache_config in rpki['cache'].items():
+ if 'ssh' in cache_config:
+ key_name = cache_config['ssh']['key']
+ public_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'key')
+ public_key_type = dict_search_args(rpki['pki'], 'openssh', key_name, 'public', 'type')
+ private_key_data = dict_search_args(rpki['pki'], 'openssh', key_name, 'private', 'key')
+
+ cache_config['ssh']['public_key_file'] = f'{rpki_ssh_key_base}_{cache}.pub'
+ cache_config['ssh']['private_key_file'] = f'{rpki_ssh_key_base}_{cache}'
+
+ write_file(cache_config['ssh']['public_key_file'], wrap_openssh_public_key(public_key_data, public_key_type))
+ write_file(cache_config['ssh']['private_key_file'], wrap_openssh_private_key(private_key_data))
+
rpki['new_frr_config'] = render_to_string('frr/rpki.frr.j2', rpki)
+
return None
def apply(rpki):
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index 5f72b983c..852b714eb 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -25,8 +25,10 @@ from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
from vyos.accel_ppp_util import get_pools_in_order
+from vyos.accel_ppp_util import verify_accel_ppp_name_servers
+from vyos.accel_ppp_util import verify_accel_ppp_wins_servers
from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
-from vyos.accel_ppp_util import verify_accel_ppp_base_service
+from vyos.accel_ppp_util import verify_accel_ppp_authentication
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -69,8 +71,10 @@ def verify(ipoe):
raise ConfigError('Option "client-subnet" incompatible with "vlan"!'
'Use "ipoe client-ip-pool" instead.')
- verify_accel_ppp_base_service(ipoe, local_users=False)
+ verify_accel_ppp_authentication(ipoe, local_users=False)
verify_accel_ppp_ip_pool(ipoe)
+ verify_accel_ppp_name_servers(ipoe)
+ verify_accel_ppp_wins_servers(ipoe)
return None
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index c2dfbdb44..c9d1e805f 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -25,7 +25,9 @@ from vyos.configverify import verify_interface_exists
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.accel_ppp_util import verify_accel_ppp_base_service
+from vyos.accel_ppp_util import verify_accel_ppp_name_servers
+from vyos.accel_ppp_util import verify_accel_ppp_wins_servers
+from vyos.accel_ppp_util import verify_accel_ppp_authentication
from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
from vyos.accel_ppp_util import get_pools_in_order
from vyos import ConfigError
@@ -67,11 +69,11 @@ def verify(pppoe):
if not pppoe:
return None
- verify_accel_ppp_base_service(pppoe)
+ verify_accel_ppp_authentication(pppoe)
verify_accel_ppp_ip_pool(pppoe)
+ verify_accel_ppp_name_servers(pppoe)
+ verify_accel_ppp_wins_servers(pppoe)
- if 'wins_server' in pppoe and len(pppoe['wins_server']) > 2:
- raise ConfigError('Not more then two WINS name-servers can be configured')
if 'interface' not in pppoe:
raise ConfigError('At least one listen interface must be defined!')
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 266381754..04ccbcec3 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -24,7 +24,9 @@ from vyos.configdict import get_accel_dict
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.accel_ppp_util import verify_accel_ppp_base_service
+from vyos.accel_ppp_util import verify_accel_ppp_name_servers
+from vyos.accel_ppp_util import verify_accel_ppp_wins_servers
+from vyos.accel_ppp_util import verify_accel_ppp_authentication
from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
from vyos.accel_ppp_util import get_pools_in_order
from vyos import ConfigError
@@ -62,12 +64,10 @@ def verify(l2tp):
if not l2tp:
return None
- verify_accel_ppp_base_service(l2tp)
+ verify_accel_ppp_authentication(l2tp)
verify_accel_ppp_ip_pool(l2tp)
-
- if 'wins_server' in l2tp and len(l2tp['wins_server']) > 2:
- raise ConfigError(
- 'Not more then two WINS name-servers can be configured')
+ verify_accel_ppp_name_servers(l2tp)
+ verify_accel_ppp_wins_servers(l2tp)
return None
diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py
index b1d5067d5..c0d8330bd 100755
--- a/src/conf_mode/vpn_pptp.py
+++ b/src/conf_mode/vpn_pptp.py
@@ -22,7 +22,9 @@ from vyos.config import Config
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.accel_ppp_util import verify_accel_ppp_base_service
+from vyos.accel_ppp_util import verify_accel_ppp_name_servers
+from vyos.accel_ppp_util import verify_accel_ppp_wins_servers
+from vyos.accel_ppp_util import verify_accel_ppp_authentication
from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
from vyos.accel_ppp_util import get_pools_in_order
from vyos import ConfigError
@@ -60,12 +62,10 @@ def verify(pptp):
if not pptp:
return None
- verify_accel_ppp_base_service(pptp)
+ verify_accel_ppp_authentication(pptp)
verify_accel_ppp_ip_pool(pptp)
-
- if 'wins_server' in pptp and len(pptp['wins_server']) > 2:
- raise ConfigError(
- 'Not more then two WINS name-servers can be configured')
+ verify_accel_ppp_name_servers(pptp)
+ verify_accel_ppp_wins_servers(pptp)
def generate(pptp):
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index 5c229fe62..8661a8aff 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -26,7 +26,9 @@ from vyos.template import render
from vyos.utils.process import call
from vyos.utils.network import check_port_availability
from vyos.utils.dict import dict_search
-from vyos.accel_ppp_util import verify_accel_ppp_base_service
+from vyos.accel_ppp_util import verify_accel_ppp_name_servers
+from vyos.accel_ppp_util import verify_accel_ppp_wins_servers
+from vyos.accel_ppp_util import verify_accel_ppp_authentication
from vyos.accel_ppp_util import verify_accel_ppp_ip_pool
from vyos.accel_ppp_util import get_pools_in_order
from vyos.utils.network import is_listen_port_bind_service
@@ -43,48 +45,18 @@ cert_file_path = os.path.join(cfg_dir, 'sstp-cert.pem')
cert_key_path = os.path.join(cfg_dir, 'sstp-cert.key')
ca_cert_file_path = os.path.join(cfg_dir, 'sstp-ca.pem')
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
- base = ['vpn', 'sstp']
- if not conf.exists(base):
- return None
-
- # retrieve common dictionary keys
- sstp = get_accel_dict(conf, base, sstp_chap_secrets, with_pki=True)
- if dict_search('client_ip_pool', sstp):
- # Multiple named pools require ordered values T5099
- sstp['ordered_named_pools'] = get_pools_in_order(dict_search('client_ip_pool', sstp))
-
- sstp['server_type'] = 'sstp'
- return sstp
-
-
-def verify(sstp):
- if not sstp:
- return None
-
- port = sstp.get('port')
- proto = 'tcp'
- if check_port_availability('0.0.0.0', int(port), proto) is not True and \
- not is_listen_port_bind_service(int(port), 'accel-pppd'):
- raise ConfigError(f'"{proto}" port "{port}" is used by another service')
-
- verify_accel_ppp_base_service(sstp)
- verify_accel_ppp_ip_pool(sstp)
+def verify_certificate(config):
#
# SSL certificate checks
#
- if not sstp['pki']:
+ if not config['pki']:
raise ConfigError('PKI is not configured')
- if 'ssl' not in sstp:
+ if 'ssl' not in config:
raise ConfigError('SSL missing on SSTP config')
- ssl = sstp['ssl']
+ ssl = config['ssl']
# CA
if 'ca_certificate' not in ssl:
@@ -92,10 +64,10 @@ def verify(sstp):
ca_name = ssl['ca_certificate']
- if ca_name not in sstp['pki']['ca']:
+ if ca_name not in config['pki']['ca']:
raise ConfigError('Invalid CA certificate on SSTP config')
- if 'certificate' not in sstp['pki']['ca'][ca_name]:
+ if 'certificate' not in config['pki']['ca'][ca_name]:
raise ConfigError('Missing certificate data for CA certificate on SSTP config')
# Certificate
@@ -104,10 +76,10 @@ def verify(sstp):
cert_name = ssl['certificate']
- if cert_name not in sstp['pki']['certificate']:
+ if cert_name not in config['pki']['certificate']:
raise ConfigError('Invalid certificate on SSTP config')
- pki_cert = sstp['pki']['certificate'][cert_name]
+ pki_cert = config['pki']['certificate'][cert_name]
if 'certificate' not in pki_cert:
raise ConfigError('Missing certificate data for certificate on SSTP config')
@@ -118,6 +90,43 @@ def verify(sstp):
if 'password_protected' in pki_cert['private']:
raise ConfigError('Encrypted private key is not supported on SSTP config')
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+ base = ['vpn', 'sstp']
+ if not conf.exists(base):
+ return None
+
+ # retrieve common dictionary keys
+ sstp = get_accel_dict(conf, base, sstp_chap_secrets, with_pki=True)
+ if dict_search('client_ip_pool', sstp):
+ # Multiple named pools require ordered values T5099
+ sstp['ordered_named_pools'] = get_pools_in_order(dict_search('client_ip_pool', sstp))
+
+ sstp['server_type'] = 'sstp'
+ return sstp
+
+
+def verify(sstp):
+ if not sstp:
+ return None
+
+ port = sstp.get('port')
+ proto = 'tcp'
+ if check_port_availability('0.0.0.0', int(port), proto) is not True and \
+ not is_listen_port_bind_service(int(port), 'accel-pppd'):
+ raise ConfigError(f'"{proto}" port "{port}" is used by another service')
+
+ verify_accel_ppp_authentication(sstp)
+ verify_accel_ppp_ip_pool(sstp)
+ verify_accel_ppp_name_servers(sstp)
+ verify_accel_ppp_wins_servers(sstp)
+ verify_certificate(sstp)
+
+
def generate(sstp):
if not sstp:
return None
@@ -143,6 +152,7 @@ def generate(sstp):
return sstp
+
def apply(sstp):
if not sstp:
call('systemctl stop accel-ppp@sstp.service')
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 2b4fac5ef..eac3e7e47 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -1,5 +1,5 @@
#!/bin/bash
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -449,7 +449,7 @@ start ()
run_postconfig_scripts
tmp=$(${vyos_libexec_dir}/read-saved-value.py --path "protocols rpki cache")
- if [ ! -z $tmp ]; then
+ if [[ ! -z "$tmp" ]]; then
vtysh -c "rpki start"
fi
}
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
index 71fbbe8a1..f8b6de560 100755
--- a/src/migration-scripts/ipsec/6-to-7
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -63,7 +63,7 @@ if config.exists(ipsec_site_base):
changes_made = True
peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509']
- pki_name = 'peer_' + peer.replace(".", "-")
+ pki_name = 'peer_' + peer.replace(".", "-").replace("@", "")
if config.exists(peer_x509_base + ['cert-file']):
cert_file = config.return_value(peer_x509_base + ['cert-file'])
diff --git a/src/migration-scripts/l2tp/8-to-9 b/src/migration-scripts/l2tp/8-to-9
new file mode 100755
index 000000000..e85a3892b
--- /dev/null
+++ b/src/migration-scripts/l2tp/8-to-9
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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/>.
+
+# Deleted 'dhcp-interface' from l2tp
+
+import os
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+
+if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['vpn', 'l2tp', 'remote-access']
+if not config.exists(base):
+ exit(0)
+
+#deleting unused dhcp-interface
+if config.exists(base + ['dhcp-interface']):
+ config.delete(base + ['dhcp-interface'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)
diff --git a/src/migration-scripts/rpki/1-to-2 b/src/migration-scripts/rpki/1-to-2
index 559440bba..50d4a3dfc 100755
--- a/src/migration-scripts/rpki/1-to-2
+++ b/src/migration-scripts/rpki/1-to-2
@@ -19,7 +19,11 @@
from sys import exit
from sys import argv
+
from vyos.configtree import ConfigTree
+from vyos.pki import OPENSSH_KEY_BEGIN
+from vyos.pki import OPENSSH_KEY_END
+from vyos.utils.file import read_file
if len(argv) < 2:
print("Must specify file name!")
@@ -43,6 +47,24 @@ if config.exists(base + ['cache']):
if config.exists(ssh_node + ['known-hosts-file']):
config.delete(ssh_node + ['known-hosts-file'])
+ if config.exists(base + ['cache', cache, 'ssh']):
+ private_key_node = base + ['cache', cache, 'ssh', 'private-key-file']
+ private_key_file = config.return_value(private_key_node)
+ private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','')
+
+ public_key_node = base + ['cache', cache, 'ssh', 'public-key-file']
+ public_key_file = config.return_value(public_key_node)
+ public_key = read_file(public_key_file).split()
+
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key)
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1])
+ config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0])
+ config.set_tag(['pki', 'openssh'])
+ config.set(ssh_node + ['key'], value=f'rpki-{cache}')
+
+ config.delete(private_key_node)
+ config.delete(public_key_node)
+
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py
index a64acec31..1d9ad0e76 100755
--- a/src/op_mode/dhcp.py
+++ b/src/op_mode/dhcp.py
@@ -29,8 +29,8 @@ from vyos.base import Warning
from vyos.configquery import ConfigTreeQuery
from vyos.kea import kea_get_active_config
+from vyos.kea import kea_get_leases
from vyos.kea import kea_get_pool_from_subnet_id
-from vyos.kea import kea_parse_leases
from vyos.utils.process import is_systemd_service_running
time_string = "%a %b %d %H:%M:%S %Z %Y"
@@ -38,7 +38,8 @@ time_string = "%a %b %d %H:%M:%S %Z %Y"
config = ConfigTreeQuery()
lease_valid_states = ['all', 'active', 'free', 'expired', 'released', 'abandoned', 'reset', 'backup']
sort_valid_inet = ['end', 'mac', 'hostname', 'ip', 'pool', 'remaining', 'start', 'state']
-sort_valid_inet6 = ['end', 'iaid_duid', 'ip', 'last_communication', 'pool', 'remaining', 'state', 'type']
+sort_valid_inet6 = ['end', 'duid', 'ip', 'last_communication', 'pool', 'remaining', 'state', 'type']
+mapping_sort_valid = ['mac', 'ip', 'pool', 'duid']
ArgFamily = typing.Literal['inet', 'inet6']
ArgState = typing.Literal['all', 'active', 'free', 'expired', 'released', 'abandoned', 'reset', 'backup']
@@ -77,8 +78,7 @@ def _get_raw_server_leases(family='inet', pool=None, sorted=None, state=[], orig
:return list
"""
inet_suffix = '6' if family == 'inet6' else '4'
- lease_file = f'/config/dhcp/dhcp{inet_suffix}-leases.csv'
- leases = kea_parse_leases(lease_file)
+ leases = kea_get_leases(inet_suffix)
if pool is None:
pool = _get_dhcp_pools(family=family)
@@ -89,28 +89,37 @@ def _get_raw_server_leases(family='inet', pool=None, sorted=None, state=[], orig
data = []
for lease in leases:
+ lifetime = lease['valid-lft']
+ expiry = (lease['cltt'] + lifetime)
+
+ lease['start_timestamp'] = datetime.utcfromtimestamp(expiry - lifetime)
+ lease['expire_timestamp'] = datetime.utcfromtimestamp(expiry) if expiry else None
+
data_lease = {}
- data_lease['ip'] = lease['address']
- lease_state_long = {'0': 'active', '1': 'rejected', '2': 'expired'}
+ data_lease['ip'] = lease['ip-address']
+ lease_state_long = {0: 'active', 1: 'rejected', 2: 'expired'}
data_lease['state'] = lease_state_long[lease['state']]
- data_lease['pool'] = kea_get_pool_from_subnet_id(active_config, inet_suffix, lease['subnet_id']) if active_config else '-'
+ data_lease['pool'] = kea_get_pool_from_subnet_id(active_config, inet_suffix, lease['subnet-id']) if active_config else '-'
data_lease['end'] = lease['expire_timestamp'].timestamp() if lease['expire_timestamp'] else None
data_lease['origin'] = 'local' # TODO: Determine remote in HA
if family == 'inet':
- data_lease['mac'] = lease['hwaddr']
+ data_lease['mac'] = lease['hw-address']
data_lease['start'] = lease['start_timestamp'].timestamp()
data_lease['hostname'] = lease['hostname']
if family == 'inet6':
data_lease['last_communication'] = lease['start_timestamp'].timestamp()
- data_lease['iaid_duid'] = _format_hex_string(lease['duid'])
- lease_types_long = {'0': 'non-temporary', '1': 'temporary', '2': 'prefix delegation'}
- data_lease['type'] = lease_types_long[lease['lease_type']]
+ data_lease['duid'] = _format_hex_string(lease['duid'])
+ data_lease['type'] = lease['type']
+
+ if lease['type'] == 'IA_PD':
+ prefix_len = lease['prefix-len']
+ data_lease['ip'] += f'/{prefix_len}'
data_lease['remaining'] = '-'
- if lease['expire']:
+ if lease['valid-lft'] > 0:
data_lease['remaining'] = lease['expire_timestamp'] - datetime.utcnow()
if data_lease['remaining'].days >= 0:
@@ -172,11 +181,11 @@ def _get_formatted_server_leases(raw_data, family='inet'):
remain = lease.get('remaining')
lease_type = lease.get('type')
pool = lease.get('pool')
- host_identifier = lease.get('iaid_duid')
+ host_identifier = lease.get('duid')
data_entries.append([ipaddr, state, start, end, remain, lease_type, pool, host_identifier])
headers = ['IPv6 address', 'State', 'Last communication', 'Lease expiration', 'Remaining', 'Type', 'Pool',
- 'IAID_DUID']
+ 'DUID']
output = tabulate(data_entries, headers, numalign='left')
return output
@@ -241,6 +250,47 @@ def _get_formatted_pool_statistics(pool_data, family='inet'):
output = tabulate(data_entries, headers, numalign='left')
return output
+def _get_raw_server_static_mappings(family='inet', pool=None, sorted=None):
+ if pool is None:
+ pool = _get_dhcp_pools(family=family)
+ else:
+ pool = [pool]
+
+ v = 'v6' if family == 'inet6' else ''
+ mappings = []
+ for p in pool:
+ pool_config = config.get_config_dict(['service', f'dhcp{v}-server', 'shared-network-name', p],
+ get_first_key=True)
+ if 'subnet' in pool_config:
+ for subnet, subnet_config in pool_config['subnet'].items():
+ if 'static-mapping' in subnet_config:
+ for name, mapping_config in subnet_config['static-mapping'].items():
+ mapping = {'pool': p, 'subnet': subnet, 'name': name}
+ mapping.update(mapping_config)
+ mappings.append(mapping)
+
+ if sorted:
+ if sorted == 'ip':
+ data.sort(key = lambda x:ip_address(x['ip-address']))
+ else:
+ data.sort(key = lambda x:x[sorted])
+ return mappings
+
+def _get_formatted_server_static_mappings(raw_data, family='inet'):
+ data_entries = []
+ for entry in raw_data:
+ pool = entry.get('pool')
+ subnet = entry.get('subnet')
+ name = entry.get('name')
+ ip_addr = entry.get('ip-address', 'N/A')
+ mac_addr = entry.get('mac', 'N/A')
+ duid = entry.get('duid', 'N/A')
+ description = entry.get('description', 'N/A')
+ data_entries.append([pool, subnet, name, ip_addr, mac_addr, duid, description])
+
+ headers = ['Pool', 'Subnet', 'Name', 'IP Address', 'MAC Address', 'DUID', 'Description']
+ output = tabulate(data_entries, headers, numalign='left')
+ return output
def _verify(func):
"""Decorator checks if DHCP(v6) config exists"""
@@ -294,6 +344,21 @@ def show_server_leases(raw: bool, family: ArgFamily, pool: typing.Optional[str],
else:
return _get_formatted_server_leases(lease_data, family=family)
+@_verify
+def show_server_static_mappings(raw: bool, family: ArgFamily, pool: typing.Optional[str],
+ sorted: typing.Optional[str]):
+ v = 'v6' if family == 'inet6' else ''
+ if pool and pool not in _get_dhcp_pools(family=family):
+ raise vyos.opmode.IncorrectValue(f'DHCP{v} pool "{pool}" does not exist!')
+
+ if sorted and sorted not in mapping_sort_valid:
+ raise vyos.opmode.IncorrectValue(f'DHCP{v} sort "{sorted}" is invalid!')
+
+ static_mappings = _get_raw_server_static_mappings(family=family, pool=pool, sorted=sorted)
+ if raw:
+ return static_mappings
+ else:
+ return _get_formatted_server_static_mappings(static_mappings, family=family)
def _get_raw_client_leases(family='inet', interface=None):
from time import mktime