summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--data/configd-include.json2
-rw-r--r--data/templates/accel-ppp/chap-secrets.config_dict.j2 (renamed from data/templates/accel-ppp/chap-secrets.config_dict.tmpl)10
-rw-r--r--data/templates/accel-ppp/chap-secrets.ipoe.j2 (renamed from data/templates/accel-ppp/chap-secrets.ipoe.tmpl)22
-rw-r--r--data/templates/accel-ppp/chap-secrets.j2 (renamed from data/templates/accel-ppp/chap-secrets.tmpl)10
-rw-r--r--data/templates/accel-ppp/config_shaper_radius.j23
-rw-r--r--data/templates/accel-ppp/ipoe.config.j2 (renamed from data/templates/accel-ppp/ipoe.config.tmpl)92
-rw-r--r--data/templates/accel-ppp/l2tp.config.j2 (renamed from data/templates/accel-ppp/l2tp.config.tmpl)69
-rw-r--r--data/templates/accel-ppp/pppoe.config.j2 (renamed from data/templates/accel-ppp/pppoe.config.tmpl)70
-rw-r--r--data/templates/accel-ppp/pptp.config.j2 (renamed from data/templates/accel-ppp/pptp.config.tmpl)32
-rw-r--r--data/templates/accel-ppp/sstp.config.j2 (renamed from data/templates/accel-ppp/sstp.config.tmpl)0
-rw-r--r--data/templates/bcast-relay/udp-broadcast-relay.j2 (renamed from data/templates/bcast-relay/udp-broadcast-relay.tmpl)0
-rw-r--r--data/templates/conntrack/nftables-ct.j248
-rw-r--r--data/templates/conntrack/nftables-ct.tmpl48
-rw-r--r--data/templates/conntrack/sysctl.conf.j2 (renamed from data/templates/conntrack/sysctl.conf.tmpl)0
-rw-r--r--data/templates/conntrack/vyos_nf_conntrack.conf.j2 (renamed from data/templates/conntrack/vyos_nf_conntrack.conf.tmpl)0
-rw-r--r--data/templates/conntrackd/conntrackd.conf.j2 (renamed from data/templates/conntrackd/conntrackd.conf.tmpl)48
-rw-r--r--data/templates/conntrackd/conntrackd.op-mode.j213
-rw-r--r--data/templates/conntrackd/conntrackd.op-mode.tmpl13
-rw-r--r--data/templates/conserver/conserver.conf.j2 (renamed from data/templates/conserver/conserver.conf.tmpl)2
-rw-r--r--data/templates/conserver/dropbear@.service.j2 (renamed from data/templates/conserver/dropbear@.service.tmpl)0
-rw-r--r--data/templates/container/registries.conf.j2 (renamed from data/templates/containers/registries.conf.j2)2
-rw-r--r--data/templates/container/storage.conf.j24
-rw-r--r--data/templates/containers/storage.conf.j25
-rw-r--r--data/templates/firewall/nftables-defines.j232
-rw-r--r--data/templates/firewall/nftables-defines.tmpl32
-rw-r--r--data/templates/firewall/nftables-nat.j2 (renamed from data/templates/firewall/nftables-nat.tmpl)182
-rw-r--r--data/templates/firewall/nftables-nat66.j2 (renamed from data/templates/firewall/nftables-nat66.tmpl)74
-rw-r--r--data/templates/firewall/nftables-policy.j2 (renamed from data/templates/firewall/nftables-policy.tmpl)30
-rw-r--r--data/templates/firewall/nftables-vrf-zones.j2 (renamed from data/templates/firewall/nftables-vrf-zones.tmpl)0
-rw-r--r--data/templates/firewall/nftables.j2 (renamed from data/templates/firewall/nftables.tmpl)72
-rw-r--r--data/templates/firewall/upnpd.conf.j2 (renamed from data/templates/firewall/upnpd.conf.tmpl)34
-rw-r--r--data/templates/frr/daemons.frr.tmpl54
-rw-r--r--data/templates/frr/policy.frr.j217
-rw-r--r--data/templates/getty/serial-getty.service.j2 (renamed from data/templates/getty/serial-getty.service.tmpl)0
-rw-r--r--data/templates/high-availability/keepalived.conf.j2169
-rw-r--r--data/templates/high-availability/keepalived.conf.tmpl169
-rw-r--r--data/templates/https/nginx.default.j2 (renamed from data/templates/https/nginx.default.tmpl)33
-rw-r--r--data/templates/https/override.conf.j2 (renamed from data/templates/https/override.conf.tmpl)0
-rw-r--r--data/templates/https/vyos-http-api.service.j2 (renamed from data/templates/https/vyos-http-api.service.tmpl)0
-rw-r--r--data/templates/ids/fastnetmon.j2 (renamed from data/templates/ids/fastnetmon.tmpl)16
-rw-r--r--data/templates/ids/fastnetmon_networks_list.j2 (renamed from data/templates/ids/fastnetmon_networks_list.tmpl)4
-rw-r--r--data/templates/igmp-proxy/igmpproxy.conf.j2 (renamed from data/templates/igmp-proxy/igmpproxy.conf.tmpl)26
-rw-r--r--data/templates/ipsec/charon.j2 (renamed from data/templates/ipsec/charon.tmpl)11
-rw-r--r--data/templates/ipsec/charon/dhcp.conf.j2 (renamed from data/templates/ipsec/charon/dhcp.conf.tmpl)0
-rw-r--r--data/templates/ipsec/charon/eap-radius.conf.j2 (renamed from data/templates/ipsec/charon/eap-radius.conf.tmpl)14
-rw-r--r--data/templates/ipsec/interfaces_use.conf.j2 (renamed from data/templates/ipsec/interfaces_use.conf.tmpl)4
-rw-r--r--data/templates/ipsec/ios_profile.j2 (renamed from data/templates/ipsec/ios_profile.tmpl)0
-rw-r--r--data/templates/ipsec/ipsec.conf.j219
-rw-r--r--data/templates/ipsec/ipsec.conf.tmpl18
-rw-r--r--data/templates/ipsec/ipsec.secrets.j2 (renamed from data/templates/ipsec/ipsec.secrets.tmpl)4
-rw-r--r--data/templates/ipsec/swanctl.conf.j2131
-rw-r--r--data/templates/ipsec/swanctl.conf.tmpl131
-rw-r--r--data/templates/ipsec/swanctl/l2tp.j2 (renamed from data/templates/ipsec/swanctl/l2tp.tmpl)8
-rw-r--r--data/templates/ipsec/swanctl/peer.j2 (renamed from data/templates/ipsec/swanctl/peer.tmpl)150
-rw-r--r--data/templates/ipsec/swanctl/profile.j2 (renamed from data/templates/ipsec/swanctl/profile.tmpl)24
-rw-r--r--data/templates/ipsec/swanctl/remote_access.j2 (renamed from data/templates/ipsec/swanctl/remote_access.tmpl)37
-rw-r--r--data/templates/ipsec/windows_profile.j2 (renamed from data/templates/ipsec/windows_profile.tmpl)0
-rw-r--r--data/templates/lcd/LCDd.conf.j2 (renamed from data/templates/lcd/LCDd.conf.tmpl)16
-rw-r--r--data/templates/lcd/lcdproc.conf.j2 (renamed from data/templates/lcd/lcdproc.conf.tmpl)0
-rw-r--r--data/templates/lldp/lldpd.j22
-rw-r--r--data/templates/lldp/lldpd.tmpl2
-rw-r--r--data/templates/lldp/vyos.conf.j2 (renamed from data/templates/lldp/vyos.conf.tmpl)26
-rw-r--r--data/templates/login/authorized_keys.j2 (renamed from data/templates/login/authorized_keys.tmpl)4
-rw-r--r--data/templates/login/pam_radius_auth.conf.j236
-rw-r--r--data/templates/login/pam_radius_auth.conf.tmpl36
-rw-r--r--data/templates/logs/logrotate/vyos-atop.j2 (renamed from data/templates/logs/logrotate/vyos-atop.tmpl)0
-rw-r--r--data/templates/logs/logrotate/vyos-rsyslog.j2 (renamed from data/templates/logs/logrotate/vyos-rsyslog.tmpl)0
-rw-r--r--data/templates/mdns-repeater/avahi-daemon.j2 (renamed from data/templates/mdns-repeater/avahi-daemon.tmpl)0
-rw-r--r--data/templates/monitoring/override.conf.j2 (renamed from data/templates/monitoring/override.conf.tmpl)0
-rw-r--r--data/templates/monitoring/syslog_telegraf.j2 (renamed from data/templates/monitoring/syslog_telegraf.tmpl)0
-rw-r--r--data/templates/monitoring/systemd_vyos_telegraf_service.j2 (renamed from data/templates/monitoring/systemd_vyos_telegraf_service.tmpl)0
-rw-r--r--data/templates/monitoring/telegraf.j2122
-rw-r--r--data/templates/monitoring/telegraf.tmpl60
-rw-r--r--data/templates/ndppd/ndppd.conf.j244
-rw-r--r--data/templates/ndppd/ndppd.conf.tmpl44
-rw-r--r--data/templates/nhrp/opennhrp.conf.j242
-rw-r--r--data/templates/nhrp/opennhrp.conf.tmpl41
-rw-r--r--data/templates/ocserv/ocserv_config.j2 (renamed from data/templates/ocserv/ocserv_config.tmpl)38
-rw-r--r--data/templates/ocserv/ocserv_otp_usr.j2 (renamed from data/templates/ocserv/ocserv_otp_usr.tmpl)8
-rw-r--r--data/templates/ocserv/ocserv_passwd.j2 (renamed from data/templates/ocserv/ocserv_passwd.tmpl)0
-rw-r--r--data/templates/ocserv/radius_conf.j2 (renamed from data/templates/ocserv/radius_conf.tmpl)12
-rw-r--r--data/templates/ocserv/radius_servers.j27
-rw-r--r--data/templates/ocserv/radius_servers.tmpl7
-rw-r--r--data/templates/pmacct/override.conf.j2 (renamed from data/templates/pmacct/override.conf.tmpl)0
-rw-r--r--data/templates/pmacct/uacctd.conf.j280
-rw-r--r--data/templates/pmacct/uacctd.conf.tmpl74
-rw-r--r--data/templates/pppoe/ip-down.script.tmpl38
-rw-r--r--data/templates/pppoe/ip-pre-up.script.tmpl18
-rw-r--r--data/templates/pppoe/ip-up.script.tmpl49
-rw-r--r--data/templates/pppoe/ipv6-up.script.tmpl46
-rw-r--r--data/templates/pppoe/peer.j2 (renamed from data/templates/pppoe/peer.tmpl)6
-rw-r--r--data/templates/router-advert/radvd.conf.j2 (renamed from data/templates/router-advert/radvd.conf.tmpl)64
-rw-r--r--data/templates/snmp/etc.snmp.conf.j2 (renamed from data/templates/snmp/etc.snmp.conf.tmpl)0
-rw-r--r--data/templates/snmp/etc.snmpd.conf.j2182
-rw-r--r--data/templates/snmp/etc.snmpd.conf.tmpl182
-rw-r--r--data/templates/snmp/override.conf.j2 (renamed from data/templates/snmp/override.conf.tmpl)0
-rw-r--r--data/templates/snmp/usr.snmpd.conf.j2 (renamed from data/templates/snmp/usr.snmpd.conf.tmpl)4
-rw-r--r--data/templates/snmp/var.snmpd.conf.j2 (renamed from data/templates/snmp/var.snmpd.conf.tmpl)12
-rw-r--r--data/templates/squid/sg_acl.conf.j2 (renamed from data/templates/squid/sg_acl.conf.tmpl)0
-rw-r--r--data/templates/squid/squid.conf.j2 (renamed from data/templates/squid/squid.conf.tmpl)38
-rw-r--r--data/templates/squid/squidGuard.conf.j2124
-rw-r--r--data/templates/squid/squidGuard.conf.tmpl124
-rw-r--r--data/templates/ssh/sshguard_config.j227
-rw-r--r--data/templates/ssh/sshguard_whitelist.j27
-rw-r--r--data/templates/syslog/logrotate.j2 (renamed from data/templates/syslog/logrotate.tmpl)0
-rw-r--r--data/templates/syslog/rsyslog.conf.j2 (renamed from data/templates/syslog/rsyslog.conf.tmpl)50
-rw-r--r--data/templates/system/curlrc.j2 (renamed from data/templates/system/curlrc.tmpl)0
-rw-r--r--data/templates/system/ssh_config.j2 (renamed from data/templates/system/ssh_config.tmpl)0
-rw-r--r--data/templates/system/sysctl.conf.j2 (renamed from data/templates/system/sysctl.conf.tmpl)4
-rw-r--r--data/templates/tftp-server/default.j2 (renamed from data/templates/tftp-server/default.tmpl)1
-rw-r--r--data/templates/vrf/vrf.conf.j2 (renamed from data/templates/vrf/vrf.conf.tmpl)4
-rw-r--r--data/templates/zone_policy/nftables.j2 (renamed from data/templates/zone_policy/nftables.tmpl)100
-rw-r--r--debian/control1
-rw-r--r--interface-definitions/container.xml.in (renamed from interface-definitions/containers.xml.in)2
-rw-r--r--interface-definitions/flow-accounting-conf.xml.in4
-rw-r--r--interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i14
-rw-r--r--interface-definitions/include/auth-local-users.xml.i68
-rw-r--r--interface-definitions/include/firewall/common-rule.xml.i26
-rw-r--r--interface-definitions/include/ipsec/local-address.xml.i1
-rw-r--r--interface-definitions/include/monitoring/url.xml.i15
-rw-r--r--interface-definitions/include/version/quagga-version.xml.i2
-rw-r--r--interface-definitions/policy-local-route.xml.in4
-rw-r--r--interface-definitions/policy.xml.in95
-rw-r--r--interface-definitions/protocols-nhrp.xml.in2
-rw-r--r--interface-definitions/service_conntrack-sync.xml.in3
-rw-r--r--interface-definitions/service_monitoring_telegraf.xml.in219
-rw-r--r--interface-definitions/ssh.xml.in72
-rw-r--r--interface-definitions/system-frr.xml.in77
-rw-r--r--interface-definitions/vpn_openconnect.xml.in76
-rw-r--r--interface-definitions/vrf.xml.in16
-rw-r--r--op-mode-definitions/container.xml.in (renamed from op-mode-definitions/containers.xml.in)12
-rw-r--r--op-mode-definitions/monitor-log.xml.in24
-rw-r--r--op-mode-definitions/show-log.xml.in12
-rw-r--r--op-mode-definitions/show-system.xml.in4
-rw-r--r--op-mode-definitions/traceroute.xml.in220
-rw-r--r--python/vyos/cpu.py102
-rw-r--r--python/vyos/firewall.py9
-rw-r--r--smoketest/configs.no-load/firewall-big (renamed from smoketest/configs/firewall-big)0
-rw-r--r--smoketest/configs/bgp-big-as-cloud4
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py39
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py66
-rwxr-xr-xsmoketest/scripts/cli/test_policy_route.py35
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_bgp.py15
-rwxr-xr-xsmoketest/scripts/cli/test_service_ssh.py49
-rwxr-xr-xsmoketest/scripts/cli/test_system_flow-accounting.py94
-rwxr-xr-xsmoketest/scripts/cli/test_system_frr.py146
-rwxr-xr-xsmoketest/scripts/cli/test_vrf.py24
-rwxr-xr-xsrc/conf_mode/bcast_relay.py4
-rwxr-xr-xsrc/conf_mode/conntrack.py6
-rwxr-xr-xsrc/conf_mode/conntrack_sync.py7
-rwxr-xr-xsrc/conf_mode/container.py (renamed from src/conf_mode/containers.py)31
-rwxr-xr-xsrc/conf_mode/firewall.py4
-rwxr-xr-xsrc/conf_mode/flow_accounting_conf.py20
-rwxr-xr-xsrc/conf_mode/high-availability.py10
-rwxr-xr-xsrc/conf_mode/http-api.py2
-rwxr-xr-xsrc/conf_mode/https.py4
-rwxr-xr-xsrc/conf_mode/igmp_proxy.py2
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py2
-rwxr-xr-xsrc/conf_mode/lldp.py4
-rwxr-xr-xsrc/conf_mode/nat.py2
-rwxr-xr-xsrc/conf_mode/nat66.py4
-rwxr-xr-xsrc/conf_mode/policy-route.py2
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py10
-rwxr-xr-xsrc/conf_mode/protocols_nhrp.py13
-rwxr-xr-xsrc/conf_mode/service_console-server.py4
-rwxr-xr-xsrc/conf_mode/service_ids_fastnetmon.py4
-rwxr-xr-xsrc/conf_mode/service_ipoe-server.py4
-rwxr-xr-xsrc/conf_mode/service_mdns-repeater.py4
-rwxr-xr-xsrc/conf_mode/service_monitoring_telegraf.py74
-rwxr-xr-xsrc/conf_mode/service_pppoe-server.py4
-rwxr-xr-xsrc/conf_mode/service_router-advert.py2
-rwxr-xr-xsrc/conf_mode/service_upnp.py2
-rwxr-xr-xsrc/conf_mode/service_webproxy.py6
-rwxr-xr-xsrc/conf_mode/snmp.py20
-rwxr-xr-xsrc/conf_mode/ssh.py19
-rwxr-xr-xsrc/conf_mode/system-login.py4
-rwxr-xr-xsrc/conf_mode/system-logs.py4
-rwxr-xr-xsrc/conf_mode/system-option.py4
-rwxr-xr-xsrc/conf_mode/system-syslog.py4
-rwxr-xr-xsrc/conf_mode/system_console.py2
-rwxr-xr-xsrc/conf_mode/system_frr.py91
-rwxr-xr-xsrc/conf_mode/system_lcd.py6
-rwxr-xr-xsrc/conf_mode/system_sysctl.py2
-rwxr-xr-xsrc/conf_mode/tftp_server.py2
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py16
-rwxr-xr-xsrc/conf_mode/vpn_l2tp.py4
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py18
-rwxr-xr-xsrc/conf_mode/vpn_pptp.py4
-rwxr-xr-xsrc/conf_mode/vpn_sstp.py4
-rwxr-xr-xsrc/conf_mode/vrf.py18
-rwxr-xr-xsrc/conf_mode/zone_policy.py2
-rw-r--r--src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper2
-rwxr-xr-xsrc/migration-scripts/quagga/9-to-1062
-rwxr-xr-xsrc/op_mode/conntrack_sync.py2
-rwxr-xr-xsrc/op_mode/containers_op.py80
-rwxr-xr-xsrc/op_mode/ikev2_profile_generator.py4
-rwxr-xr-xsrc/op_mode/show_openvpn.py23
-rwxr-xr-xsrc/op_mode/show_uptime.py17
-rwxr-xr-xsrc/op_mode/traceroute.py207
-rwxr-xr-xsrc/validators/as-number-list29
201 files changed, 3726 insertions, 2479 deletions
diff --git a/Makefile b/Makefile
index 3e838540c..2333eebed 100644
--- a/Makefile
+++ b/Makefile
@@ -60,9 +60,10 @@ op_mode_definitions: $(op_xml_obj)
rm -f $(OP_TMPL_DIR)/show/node.def
rm -f $(OP_TMPL_DIR)/show/system/node.def
- # XXX: ping must be able to recursivly call itself as the
+ # XXX: ping and traceroute must be able to recursivly call itself as the
# options are provided from the script itself
ln -s ../node.tag $(OP_TMPL_DIR)/ping/node.tag/node.tag/
+ ln -s ../node.tag $(OP_TMPL_DIR)/traceroute/node.tag/node.tag/
# XXX: test if there are empty node.def files - this is not allowed as these
# could mask help strings or mandatory priority statements
diff --git a/data/configd-include.json b/data/configd-include.json
index da2233bc1..5a4912e30 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -1,7 +1,7 @@
[
"arp.py",
"bcast_relay.py",
-"containers.py",
+"container.py",
"conntrack.py",
"conntrack_sync.py",
"dhcp_relay.py",
diff --git a/data/templates/accel-ppp/chap-secrets.config_dict.tmpl b/data/templates/accel-ppp/chap-secrets.config_dict.j2
index d4e8bb2aa..51e66d57c 100644
--- a/data/templates/accel-ppp/chap-secrets.config_dict.tmpl
+++ b/data/templates/accel-ppp/chap-secrets.config_dict.j2
@@ -1,10 +1,10 @@
# username server password acceptable local IP addresses shaper
{% if authentication.local_users.username is vyos_defined %}
-{% for user, user_config in authentication.local_users.username.items() if user_config.disabled is not vyos_defined %}
-{% if user_config.rate_limit is vyos_defined %}
+{% for user, user_config in authentication.local_users.username.items() if user_config.disabled is not vyos_defined %}
+{% if user_config.rate_limit is vyos_defined %}
{{ "%-12s" | format(user) }} * {{ "%-16s" | format(user_config.password) }} {{ "%-16s" | format(user_config.static_ip) }} {{ user_config.rate_limit.download }}/{{ user_config.rate_limit.upload }}
-{% else %}
+{% else %}
{{ "%-12s" | format(user) }} * {{ "%-16s" | format(user_config.password) }} {{ "%-16s" | format(user_config.static_ip) }}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/accel-ppp/chap-secrets.ipoe.tmpl b/data/templates/accel-ppp/chap-secrets.ipoe.j2
index 1df878fcf..a1430ec22 100644
--- a/data/templates/accel-ppp/chap-secrets.ipoe.tmpl
+++ b/data/templates/accel-ppp/chap-secrets.ipoe.j2
@@ -1,18 +1,18 @@
# username server password acceptable local IP addresses shaper
{% for interface in auth_interfaces %}
-{% for mac in interface.mac %}
-{% if mac.rate_upload and mac.rate_download %}
-{% if mac.vlan_id %}
+{% for mac in interface.mac %}
+{% if mac.rate_upload and mac.rate_download %}
+{% if mac.vlan_id %}
{{ interface.name }}.{{ mac.vlan_id }} * {{ mac.address | lower }} * {{ mac.rate_download }}/{{ mac.rate_upload }}
-{% else %}
+{% else %}
{{ interface.name }} * {{ mac.address | lower }} * {{ mac.rate_download }}/{{ mac.rate_upload }}
-{% endif %}
-{% else %}
-{% if mac.vlan_id %}
+{% endif %}
+{% else %}
+{% if mac.vlan_id %}
{{ interface.name }}.{{ mac.vlan_id }} * {{ mac.address | lower }} *
-{% else %}
+{% else %}
{{ interface.name }} * {{ mac.address | lower }} *
-{% endif %}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
{% endfor %}
diff --git a/data/templates/accel-ppp/chap-secrets.tmpl b/data/templates/accel-ppp/chap-secrets.j2
index 6cace5401..cc3ddc28f 100644
--- a/data/templates/accel-ppp/chap-secrets.tmpl
+++ b/data/templates/accel-ppp/chap-secrets.j2
@@ -1,10 +1,10 @@
# username server password acceptable local IP addresses shaper
{% for user in local_users %}
-{% if user.state == 'enabled' %}
-{% if user.upload and user.download %}
+{% if user.state == 'enabled' %}
+{% if user.upload and user.download %}
{{ "%-12s" | format(user.name) }} * {{ "%-16s" | format(user.password) }} {{ "%-16s" | format(user.ip) }} {{ user.download }}/{{ user.upload }}
-{% else %}
+{% else %}
{{ "%-12s" | format(user.name) }} * {{ "%-16s" | format(user.password) }} {{ "%-16s" | format(user.ip) }}
-{% endif %}
-{% endif %}
+{% endif %}
+{% endif %}
{% endfor %}
diff --git a/data/templates/accel-ppp/config_shaper_radius.j2 b/data/templates/accel-ppp/config_shaper_radius.j2
index c256647e4..942cdf132 100644
--- a/data/templates/accel-ppp/config_shaper_radius.j2
+++ b/data/templates/accel-ppp/config_shaper_radius.j2
@@ -6,5 +6,8 @@ attr={{ authentication.radius.rate_limit.attribute }}
{% if authentication.radius.rate_limit.vendor is vyos_defined %}
vendor={{ authentication.radius.rate_limit.vendor }}
{% endif %}
+{% if authentication.radius.rate_limit.multiplier is vyos_defined %}
+rate-multiplier={{ authentication.radius.rate_limit.multiplier }}
+{% endif %}
{% endif %}
{% endif %}
diff --git a/data/templates/accel-ppp/ipoe.config.tmpl b/data/templates/accel-ppp/ipoe.config.j2
index 92c2d5715..3c0d47b27 100644
--- a/data/templates/accel-ppp/ipoe.config.tmpl
+++ b/data/templates/accel-ppp/ipoe.config.j2
@@ -1,3 +1,4 @@
+{# j2lint: disable=operator-enclosed-by-spaces #}
### generated by ipoe.py ###
[modules]
log_syslog
@@ -24,45 +25,50 @@ level=5
[ipoe]
verbose=1
{% for interface in interfaces %}
-{% if interface.vlan_mon %}
-interface=re:{{ interface.name }}\.\d+,{% else %}interface={{ interface.name }},{% endif %}shared={{ interface.shared }},mode={{ interface.mode }},ifcfg={{ interface.ifcfg }}{{ ',range=' + interface.range if interface.range is defined and interface.range is not none }},start={{ interface.sess_start }},ipv6=1
+{% set tmp = 'interface=' %}
+{% if interface.vlan_mon %}
+{% set tmp = tmp ~ 're:' ~ interface.name ~ '\.\d+' %}
+{% else %}
+{% set tmp = tmp ~ interface.name %}
+{% endif %}
+{{ tmp }},shared={{ interface.shared }},mode={{ interface.mode }},ifcfg={{ interface.ifcfg }}{{ ',range=' ~ interface.range if interface.range is defined and interface.range is not none }},start={{ interface.sess_start }},ipv6=1
{% endfor %}
-{% if auth_mode == 'noauth' %}
+{% if auth_mode == 'noauth' %}
noauth=1
{% if client_named_ip_pool %}
-{% for pool in client_named_ip_pool %}
-{% if pool.subnet is defined %}
+{% for pool in client_named_ip_pool %}
+{% if pool.subnet is defined %}
ip-pool={{ pool.name }}
-{% endif %}
-{% if pool.gateway_address is defined %}
+{% endif %}
+{% if pool.gateway_address is defined %}
gw-ip-address={{ pool.gateway_address }}/{{ pool.subnet.split('/')[1] }}
-{% endif %}
-{% endfor%}
+{% endif %}
+{% endfor %}
{% endif %}
-{% elif auth_mode == 'local' %}
+{% elif auth_mode == 'local' %}
username=ifname
password=csid
{% endif %}
proxy-arp=1
{% for interface in interfaces %}
-{% if (interface.shared == '0') and (interface.vlan_mon) %}
+{% if (interface.shared == '0') and (interface.vlan_mon) %}
vlan-mon={{ interface.name }},{{ interface.vlan_mon | join(',') }}
-{% endif %}
+{% endif %}
{% endfor %}
{% if dnsv4 %}
[dns]
-{% for dns in dnsv4 %}
+{% for dns in dnsv4 %}
dns{{ loop.index }}={{ dns }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if dnsv6 %}
[ipv6-dns]
-{% for dns in dnsv6 %}
+{% for dns in dnsv6 %}
{{ dns }}
-{% endfor %}
+{% endfor %}
{% endif %}
[ipv6-nd]
@@ -73,24 +79,24 @@ verbose=1
{% if client_named_ip_pool %}
[ip-pool]
-{% for pool in client_named_ip_pool %}
-{% if pool.subnet is defined %}
+{% for pool in client_named_ip_pool %}
+{% if pool.subnet is defined %}
{{ pool.subnet }},name={{ pool.name }}
-{% endif %}
-{% if pool.gateway_address is defined %}
+{% endif %}
+{% if pool.gateway_address is defined %}
gw-ip-address={{ pool.gateway_address }}/{{ pool.subnet.split('/')[1] }}
-{% endif %}
-{% endfor%}
+{% endif %}
+{% endfor %}
{% endif %}
{% if client_ipv6_pool %}
[ipv6-pool]
-{% for p in client_ipv6_pool %}
+{% for p in client_ipv6_pool %}
{{ p.prefix }},{{ p.mask }}
-{% endfor %}
-{% for p in client_ipv6_delegate_prefix %}
+{% endfor %}
+{% for p in client_ipv6_delegate_prefix %}
delegate={{ p.prefix }},{{ p.mask }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if auth_mode == 'local' %}
@@ -99,39 +105,37 @@ chap-secrets={{ chap_secrets_file }}
{% elif auth_mode == 'radius' %}
[radius]
verbose=1
-{% for r in radius_server %}
+{% for r in radius_server %}
server={{ r.server }},{{ r.key }},auth-port={{ r.port }},acct-port={{ r.acct_port }},req-limit=0,fail-time={{ r.fail_time }}
-{% endfor %}
+{% endfor %}
-{% if radius_acct_inter_jitter %}
+{% if radius_acct_inter_jitter %}
acct-interim-jitter={{ radius_acct_inter_jitter }}
-{% endif %}
+{% endif %}
acct-timeout={{ radius_acct_tmo }}
timeout={{ radius_timeout }}
max-try={{ radius_max_try }}
-{% if radius_nas_id %}
+{% if radius_nas_id %}
nas-identifier={{ radius_nas_id }}
-{% endif %}
-{% if radius_nas_ip %}
+{% endif %}
+{% if radius_nas_ip %}
nas-ip-address={{ radius_nas_ip }}
-{% endif %}
-{% if radius_source_address %}
+{% endif %}
+{% if radius_source_address %}
bind={{ radius_source_address }}
-{% endif %}
-
-{% if radius_dynamic_author %}
+{% endif %}
+{% if radius_dynamic_author %}
dae-server={{ radius_dynamic_author.server }}:{{ radius_dynamic_author.port }},{{ radius_dynamic_author.key }}
-{% endif %}
-
-{% if radius_shaper_attr %}
+{% endif %}
+{% if radius_shaper_attr %}
[shaper]
verbose=1
attr={{ radius_shaper_attr }}
-{% if radius_shaper_vendor %}
+{% if radius_shaper_vendor %}
vendor={{ radius_shaper_vendor }}
-{% endif %}
-{% endif %}
+{% endif %}
+{% endif %}
{% endif %}
[cli]
diff --git a/data/templates/accel-ppp/l2tp.config.tmpl b/data/templates/accel-ppp/l2tp.config.j2
index 9fcda76d4..9eeaf7622 100644
--- a/data/templates/accel-ppp/l2tp.config.tmpl
+++ b/data/templates/accel-ppp/l2tp.config.j2
@@ -3,9 +3,9 @@
log_syslog
l2tp
chap-secrets
-{% for proto in auth_proto: %}
-{{proto}}
-{% endfor%}
+{% for proto in auth_proto %}
+{{ proto }}
+{% endfor %}
{% if auth_mode == 'radius' %}
radius
@@ -18,7 +18,7 @@ ipv6_nd
ipv6_dhcp
[core]
-thread-count={{thread_cnt}}
+thread-count={{ thread_cnt }}
[log]
syslog=accel-l2tp,daemon
@@ -27,23 +27,23 @@ level=5
{% if dnsv4 %}
[dns]
-{% for dns in dnsv4 %}
+{% for dns in dnsv4 %}
dns{{ loop.index }}={{ dns }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if dnsv6 %}
[ipv6-dns]
-{% for dns in dnsv6 %}
+{% for dns in dnsv6 %}
{{ dns }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if wins %}
[wins]
-{% for server in wins %}
+{% for server in wins %}
wins{{ loop.index }}={{ server }}
-{% endfor %}
+{% endfor %}
{% endif %}
[l2tp]
@@ -66,14 +66,14 @@ host-name={{ lns_host_name }}
{% if client_ip_pool or client_ip_subnets %}
[ip-pool]
-{% if client_ip_pool %}
+{% if client_ip_pool %}
{{ client_ip_pool }}
-{% endif %}
-{% if client_ip_subnets %}
-{% for sn in client_ip_subnets %}
-{{sn}}
-{% endfor %}
-{% endif %}
+{% endif %}
+{% if client_ip_subnets %}
+{% for sn in client_ip_subnets %}
+{{ sn }}
+{% endfor %}
+{% endif %}
{% endif %}
{% if gateway_address %}
gw-ip-address={{ gateway_address }}
@@ -85,27 +85,24 @@ chap-secrets={{ chap_secrets_file }}
{% elif auth_mode == 'radius' %}
[radius]
verbose=1
-{% for r in radius_server %}
+{% for r in radius_server %}
server={{ r.server }},{{ r.key }},auth-port={{ r.port }},acct-port={{ r.acct_port }},req-limit=0,fail-time={{ r.fail_time }}
-{% endfor %}
-
-{% if radius_acct_inter_jitter %}
+{% endfor %}
+{% if radius_acct_inter_jitter %}
acct-interim-jitter={{ radius_acct_inter_jitter }}
-{% endif %}
-
+{% endif %}
acct-timeout={{ radius_acct_tmo }}
timeout={{ radius_timeout }}
max-try={{ radius_max_try }}
-
-{% if radius_nas_id %}
+{% if radius_nas_id %}
nas-identifier={{ radius_nas_id }}
-{% endif %}
-{% if radius_nas_ip %}
+{% endif %}
+{% if radius_nas_ip %}
nas-ip-address={{ radius_nas_ip }}
-{% endif %}
-{% if radius_source_address %}
+{% endif %}
+{% if radius_source_address %}
bind={{ radius_source_address }}
-{% endif %}
+{% endif %}
{% endif %}
{% if gateway_address %}
gw-ip-address={{ gateway_address }}
@@ -128,12 +125,12 @@ ipv6=allow
{% if client_ipv6_pool %}
[ipv6-pool]
-{% for p in client_ipv6_pool %}
+{% for p in client_ipv6_pool %}
{{ p.prefix }},{{ p.mask }}
-{% endfor %}
-{% for p in client_ipv6_delegate_prefix %}
+{% endfor %}
+{% for p in client_ipv6_delegate_prefix %}
delegate={{ p.prefix }},{{ p.mask }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if client_ipv6_delegate_prefix %}
@@ -145,9 +142,9 @@ verbose=1
[shaper]
verbose=1
attr={{ radius_shaper_attr }}
-{% if radius_shaper_vendor %}
+{% if radius_shaper_vendor %}
vendor={{ radius_shaper_vendor }}
-{% endif %}
+{% endif %}
{% endif %}
[cli]
diff --git a/data/templates/accel-ppp/pppoe.config.tmpl b/data/templates/accel-ppp/pppoe.config.j2
index 81b98cc81..0a92e2d54 100644
--- a/data/templates/accel-ppp/pppoe.config.tmpl
+++ b/data/templates/accel-ppp/pppoe.config.j2
@@ -49,9 +49,9 @@ disable
{% if wins_server is vyos_defined %}
[wins]
-{% for server in wins_server %}
+{% for server in wins_server %}
wins{{ loop.index }}={{ server }}
-{% endfor %}
+{% endfor %}
{% endif %}
{# Common chap-secrets and RADIUS server/option definitions #}
@@ -85,12 +85,12 @@ ipv4={{ ppp_options.ipv4 }}
{# IPv6 #}
{% if ppp_options.ipv6 is vyos_defined %}
ipv6={{ ppp_options.ipv6 }}
-{% if ppp_options.ipv6_intf_id is vyos_defined %}
+{% if ppp_options.ipv6_intf_id is vyos_defined %}
ipv6-intf-id={{ ppp_options.ipv6_intf_id }}
-{% endif %}
-{% if ppp_options.ipv6_peer_intf_id is vyos_defined %}
+{% endif %}
+{% if ppp_options.ipv6_peer_intf_id is vyos_defined %}
ipv6-peer-intf-id={{ ppp_options.ipv6_peer_intf_id }}
-{% endif %}
+{% endif %}
ipv6-accept-peer-intf-id={{ "1" if ppp_options.ipv6_accept_peer_intf_id is vyos_defined else "0" }}
{% endif %}
{# MTU #}
@@ -104,23 +104,23 @@ verbose=1
ac-name={{ access_concentrator }}
{% if interface is vyos_defined %}
-{% for iface, iface_config in interface.items() %}
-{% if iface_config.vlan_id is not vyos_defined and iface_config.vlan_range is not vyos_defined %}
+{% for iface, iface_config in interface.items() %}
+{% if iface_config.vlan_id is not vyos_defined and iface_config.vlan_range is not vyos_defined %}
interface={{ iface }}
-{% endif %}
-{% if iface_config.vlan_range is vyos_defined %}
-{% for regex in iface_config.regex %}
+{% endif %}
+{% if iface_config.vlan_range is vyos_defined %}
+{% for regex in iface_config.regex %}
interface=re:^{{ iface | replace('.', '\\.') }}\.({{ regex }})$
-{% endfor %}
+{% endfor %}
vlan-mon={{ iface }},{{ iface_config.vlan_range | join(',') }}
-{% endif %}
-{% if iface_config.vlan_id is vyos_defined %}
-{% for vlan in iface_config.vlan_id %}
+{% endif %}
+{% if iface_config.vlan_id is vyos_defined %}
+{% for vlan in iface_config.vlan_id %}
vlan-mon={{ iface }},{{ vlan }}
interface=re:^{{ iface | replace('.', '\\.') }}\.{{ vlan }}$
-{% endfor %}
-{% endif %}
-{% endfor %}
+{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
{% if service_name %}
@@ -128,14 +128,14 @@ service-name={{ service_name | join(',') }}
{% endif %}
{% if pado_delay %}
-{% set pado_delay_param = namespace(value='0') %}
-{% for delay in pado_delay|sort(attribute='0') %}
-{% if not loop.last %}
-{% set pado_delay_param.value = pado_delay_param.value + ',' + delay + ':' + pado_delay[delay].sessions %}
-{% else %}
-{% set pado_delay_param.value = pado_delay_param.value + ',-1:' + pado_delay[delay].sessions %}
-{% endif %}
-{% endfor %}
+{% set pado_delay_param = namespace(value='0') %}
+{% for delay in pado_delay | sort(attribute='0') %}
+{% if not loop.last %}
+{% set pado_delay_param.value = pado_delay_param.value + ',' + delay + ':' + pado_delay[delay].sessions %}
+{% else %}
+{% set pado_delay_param.value = pado_delay_param.value + ',-1:' + pado_delay[delay].sessions %}
+{% endif %}
+{% endfor %}
pado-delay={{ pado_delay_param.value }}
{% endif %}
{% if authentication.radius.called_sid_format is vyos_defined %}
@@ -144,15 +144,15 @@ called-sid={{ authentication.radius.called_sid_format }}
{% if limits is vyos_defined %}
[connlimit]
-{% if limits.connection_limit is vyos_defined %}
+{% if limits.connection_limit is vyos_defined %}
limit={{ limits.connection_limit }}
-{% endif %}
-{% if limits.burst is vyos_defined %}
+{% endif %}
+{% if limits.burst is vyos_defined %}
burst={{ limits.burst }}
-{% endif %}
-{% if limits.timeout is vyos_defined %}
+{% endif %}
+{% if limits.timeout is vyos_defined %}
timeout={{ limits.timeout }}
-{% endif %}
+{% endif %}
{% endif %}
{# Common RADIUS shaper configuration #}
@@ -162,10 +162,10 @@ timeout={{ limits.timeout }}
[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 %}
+{% 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 %}
+{% endfor %}
{% endif %}
[cli]
diff --git a/data/templates/accel-ppp/pptp.config.tmpl b/data/templates/accel-ppp/pptp.config.j2
index 3cfc4a906..cc1a45d6b 100644
--- a/data/templates/accel-ppp/pptp.config.tmpl
+++ b/data/templates/accel-ppp/pptp.config.j2
@@ -10,7 +10,7 @@ radius
{% endif %}
ippool
{% for proto in auth_proto %}
-{{proto}}
+{{ proto }}
{% endfor %}
[core]
@@ -23,16 +23,16 @@ level=5
{% if dnsv4 %}
[dns]
-{% for dns in dnsv4 %}
+{% for dns in dnsv4 %}
dns{{ loop.index }}={{ dns }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if wins %}
[wins]
-{% for server in wins %}
+{% for server in wins %}
wins{{ loop.index }}={{ server }}
-{% endfor %}
+{% endfor %}
{% endif %}
@@ -42,7 +42,7 @@ ifname=pptp%d
bind={{ outside_addr }}
{% endif %}
verbose=1
-ppp-max-mtu={{mtu}}
+ppp-max-mtu={{ mtu }}
mppe={{ ppp_mppe }}
echo-interval=10
echo-failure=3
@@ -66,27 +66,27 @@ chap-secrets={{ chap_secrets_file }}
{% elif auth_mode == 'radius' %}
[radius]
verbose=1
-{% for r in radius_server %}
+{% for r in radius_server %}
server={{ r.server }},{{ r.key }},auth-port={{ r.port }},acct-port={{ r.acct_port }},req-limit=0,fail-time={{ r.fail_time }}
-{% endfor %}
+{% endfor %}
-{% if radius_acct_inter_jitter %}
+{% if radius_acct_inter_jitter %}
acct-interim-jitter={{ radius_acct_inter_jitter }}
-{% endif %}
+{% endif %}
acct-timeout={{ radius_acct_tmo }}
timeout={{ radius_timeout }}
max-try={{ radius_max_try }}
-{% if radius_nas_id %}
+{% if radius_nas_id %}
nas-identifier={{ radius_nas_id }}
-{% endif %}
-{% if radius_nas_ip %}
+{% endif %}
+{% if radius_nas_ip %}
nas-ip-address={{ radius_nas_ip }}
-{% endif %}
-{% if radius_source_address %}
+{% endif %}
+{% if radius_source_address %}
bind={{ radius_source_address }}
-{% endif %}
+{% endif %}
{% endif %}
{# Both chap-secrets and radius block required the gw-ip-address #}
{% if gw_ip is defined and gw_ip is not none %}
diff --git a/data/templates/accel-ppp/sstp.config.tmpl b/data/templates/accel-ppp/sstp.config.j2
index 5c6f19306..5c6f19306 100644
--- a/data/templates/accel-ppp/sstp.config.tmpl
+++ b/data/templates/accel-ppp/sstp.config.j2
diff --git a/data/templates/bcast-relay/udp-broadcast-relay.tmpl b/data/templates/bcast-relay/udp-broadcast-relay.j2
index 75740e04c..75740e04c 100644
--- a/data/templates/bcast-relay/udp-broadcast-relay.tmpl
+++ b/data/templates/bcast-relay/udp-broadcast-relay.j2
diff --git a/data/templates/conntrack/nftables-ct.j2 b/data/templates/conntrack/nftables-ct.j2
new file mode 100644
index 000000000..16a03fc6e
--- /dev/null
+++ b/data/templates/conntrack/nftables-ct.j2
@@ -0,0 +1,48 @@
+#!/usr/sbin/nft -f
+
+{% set nft_ct_ignore_name = 'VYOS_CT_IGNORE' %}
+{% set nft_ct_timeout_name = 'VYOS_CT_TIMEOUT' %}
+
+# we first flush all chains and render the content from scratch - this makes
+# any delta check obsolete
+flush chain raw {{ nft_ct_ignore_name }}
+flush chain raw {{ nft_ct_timeout_name }}
+
+table raw {
+ chain {{ nft_ct_ignore_name }} {
+{% if ignore.rule is vyos_defined %}
+{% for rule, rule_config in ignore.rule.items() %}
+ # rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
+{% set nft_command = '' %}
+{% if rule_config.inbound_interface is vyos_defined %}
+{% set nft_command = nft_command ~ ' iifname ' ~ rule_config.inbound_interface %}
+{% endif %}
+{% if rule_config.protocol is vyos_defined %}
+{% set nft_command = nft_command ~ ' ip protocol ' ~ rule_config.protocol %}
+{% endif %}
+{% if rule_config.destination.address is vyos_defined %}
+{% set nft_command = nft_command ~ ' ip daddr ' ~ rule_config.destination.address %}
+{% endif %}
+{% if rule_config.destination.port is vyos_defined %}
+{% set nft_command = nft_command ~ ' ' ~ rule_config.protocol ~ ' dport { ' ~ rule_config.destination.port ~ ' }' %}
+{% endif %}
+{% if rule_config.source.address is vyos_defined %}
+{% set nft_command = nft_command ~ ' ip saddr ' ~ rule_config.source.address %}
+{% endif %}
+{% if rule_config.source.port is vyos_defined %}
+{% set nft_command = nft_command ~ ' ' ~ rule_config.protocol ~ ' sport { ' ~ rule_config.source.port ~ ' }' %}
+{% endif %}
+ {{ nft_command }} counter notrack comment ignore-{{ rule }}
+{% endfor %}
+{% endif %}
+ return
+ }
+ chain {{ nft_ct_timeout_name }} {
+{% if timeout.custom.rule is vyos_defined %}
+{% for rule, rule_config in timeout.custom.rule.items() %}
+ # rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
+{% endfor %}
+{% endif %}
+ return
+ }
+}
diff --git a/data/templates/conntrack/nftables-ct.tmpl b/data/templates/conntrack/nftables-ct.tmpl
deleted file mode 100644
index 569e73df1..000000000
--- a/data/templates/conntrack/nftables-ct.tmpl
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/sbin/nft -f
-
-{% set nft_ct_ignore_name = 'VYOS_CT_IGNORE' %}
-{% set nft_ct_timeout_name = 'VYOS_CT_TIMEOUT' %}
-
-# we first flush all chains and render the content from scratch - this makes
-# any delta check obsolete
-flush chain raw {{ nft_ct_ignore_name }}
-flush chain raw {{ nft_ct_timeout_name }}
-
-table raw {
- chain {{ nft_ct_ignore_name }} {
-{% if ignore.rule is vyos_defined %}
-{% for rule, rule_config in ignore.rule.items() %}
- # rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
-{% set nft_command = '' %}
-{% if rule_config.inbound_interface is vyos_defined %}
-{% set nft_command = nft_command ~ ' iifname ' ~ rule_config.inbound_interface %}
-{% endif %}
-{% if rule_config.protocol is vyos_defined %}
-{% set nft_command = nft_command ~ ' ip protocol ' ~ rule_config.protocol %}
-{% endif %}
-{% if rule_config.destination.address is vyos_defined %}
-{% set nft_command = nft_command ~ ' ip daddr ' ~ rule_config.destination.address %}
-{% endif %}
-{% if rule_config.destination.port is vyos_defined %}
-{% set nft_command = nft_command ~ ' ' ~ rule_config.protocol ~ ' dport { ' ~ rule_config.destination.port ~ ' }' %}
-{% endif %}
-{% if rule_config.source.address is vyos_defined %}
-{% set nft_command = nft_command ~ ' ip saddr ' ~ rule_config.source.address %}
-{% endif %}
-{% if rule_config.source.port is vyos_defined %}
-{% set nft_command = nft_command ~ ' ' ~ rule_config.protocol ~ ' sport { ' ~ rule_config.source.port ~ ' }' %}
-{% endif %}
- {{ nft_command }} counter notrack comment ignore-{{ rule }}
-{% endfor %}
-{% endif %}
- return
- }
- chain {{ nft_ct_timeout_name }} {
-{% if timeout.custom.rule is vyos_defined %}
-{% for rule, rule_config in timeout.custom.rule.items() %}
- # rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
-{% endfor %}
-{% endif %}
- return
- }
-}
diff --git a/data/templates/conntrack/sysctl.conf.tmpl b/data/templates/conntrack/sysctl.conf.j2
index 075402c04..075402c04 100644
--- a/data/templates/conntrack/sysctl.conf.tmpl
+++ b/data/templates/conntrack/sysctl.conf.j2
diff --git a/data/templates/conntrack/vyos_nf_conntrack.conf.tmpl b/data/templates/conntrack/vyos_nf_conntrack.conf.j2
index 111459485..111459485 100644
--- a/data/templates/conntrack/vyos_nf_conntrack.conf.tmpl
+++ b/data/templates/conntrack/vyos_nf_conntrack.conf.j2
diff --git a/data/templates/conntrackd/conntrackd.conf.tmpl b/data/templates/conntrackd/conntrackd.conf.j2
index 80e7254a0..66024869d 100644
--- a/data/templates/conntrackd/conntrackd.conf.tmpl
+++ b/data/templates/conntrackd/conntrackd.conf.j2
@@ -6,11 +6,11 @@ Sync {
DisableExternalCache {{ 'on' if disable_external_cache is vyos_defined else 'off' }}
}
{% for iface, iface_config in interface.items() %}
-{% if iface_config.peer is vyos_defined %}
+{% if iface_config.peer is vyos_defined %}
UDP {
-{% if listen_address is vyos_defined %}
+{% if listen_address is vyos_defined %}
IPv4_address {{ listen_address }}
-{% endif %}
+{% endif %}
IPv4_Destination_Address {{ iface_config.peer }}
Port {{ iface_config.port if iface_config.port is vyos_defined else '3780' }}
Interface {{ iface }}
@@ -18,9 +18,9 @@ Sync {
RcvSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
Checksum on
}
-{% else %}
+{% else %}
Multicast {
-{% set ip_address = iface | get_ipv4 %}
+{% set ip_address = iface | get_ipv4 %}
IPv4_address {{ mcast_group }}
Group {{ iface_config.port if iface_config.port is vyos_defined else '3780' }}
IPv4_interface {{ ip_address[0] | ip_from_cidr }}
@@ -29,19 +29,19 @@ Sync {
RcvSocketBuffer {{ sync_queue_size | int *1024 *1024 }}
Checksum on
}
-{% endif %}
+{% endif %}
{% endfor %}
{% if expect_sync is vyos_defined %}
Options {
-{% if 'all' in expect_sync %}
+{% if 'all' in expect_sync %}
ExpectationSync on
-{% else %}
+{% else %}
ExpectationSync {
-{% for protocol in expect_sync %}
+{% for protocol in expect_sync %}
{{ protocol }}
-{% endfor %}
+{% endfor %}
}
-{% endif %}
+{% endif %}
}
{% endif %}
}
@@ -85,27 +85,27 @@ General {
NetlinkEventsReliable on
{% if ignore_address is vyos_defined or accept_protocol is vyos_defined %}
Filter From Userspace {
-{% if ignore_address is vyos_defined %}
+{% if ignore_address is vyos_defined %}
Address Ignore {
-{% for address in ignore_address if address | is_ipv4 %}
+{% for address in ignore_address if address | is_ipv4 %}
IPv4_address {{ address }}
-{% endfor %}
-{% for address in ignore_address if address | is_ipv6 %}
+{% endfor %}
+{% for address in ignore_address if address | is_ipv6 %}
IPv6_address {{ address }}
-{% endfor %}
+{% endfor %}
}
-{% endif %}
-{% if accept_protocol is vyos_defined %}
+{% endif %}
+{% if accept_protocol is vyos_defined %}
Protocol Accept {
-{% for protocol in accept_protocol %}
-{% if protocol == 'icmp6' %}
+{% for protocol in accept_protocol %}
+{% if protocol == 'icmp6' %}
IPv6-ICMP
-{% else %}
+{% else %}
{{ protocol | upper }}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
}
-{% endif %}
+{% endif %}
}
{% endif %}
}
diff --git a/data/templates/conntrackd/conntrackd.op-mode.j2 b/data/templates/conntrackd/conntrackd.op-mode.j2
new file mode 100644
index 000000000..82f7e2859
--- /dev/null
+++ b/data/templates/conntrackd/conntrackd.op-mode.j2
@@ -0,0 +1,13 @@
+Source Destination Protocol
+{% for parsed in data if parsed.flow.meta is vyos_defined %}
+{% for key in parsed.flow.meta %}
+{% if key['@direction'] == 'original' %}
+{% set saddr = key.layer3.src | bracketize_ipv6 %}
+{% set sport = key.layer4.sport %}
+{% set daddr = key.layer3.dst | bracketize_ipv6 %}
+{% set dport = key.layer4.dport %}
+{% set protocol = key.layer4['@protoname'] %}
+{{ "%-48s" | format(saddr ~ ':' ~ sport) }} {{ "%-48s" | format(daddr ~ ':' ~ dport) }} {{ protocol }}
+{% endif %}
+{% endfor %}
+{% endfor %}
diff --git a/data/templates/conntrackd/conntrackd.op-mode.tmpl b/data/templates/conntrackd/conntrackd.op-mode.tmpl
deleted file mode 100644
index c3f6911ce..000000000
--- a/data/templates/conntrackd/conntrackd.op-mode.tmpl
+++ /dev/null
@@ -1,13 +0,0 @@
-Source Destination Protocol
-{% for parsed in data if parsed.flow.meta is vyos_defined %}
-{% for key in parsed.flow.meta %}
-{% if key['@direction'] == 'original' %}
-{% set saddr = key.layer3.src | bracketize_ipv6 %}
-{% set sport = key.layer4.sport %}
-{% set daddr = key.layer3.dst | bracketize_ipv6 %}
-{% set dport = key.layer4.dport %}
-{% set protocol = key.layer4['@protoname'] %}
-{{ "%-48s" | format(saddr ~ ':' ~ sport) }} {{ "%-48s" | format(daddr ~ ':' ~ dport) }} {{ protocol }}
-{% endif %}
-{% endfor %}
-{% endfor %}
diff --git a/data/templates/conserver/conserver.conf.tmpl b/data/templates/conserver/conserver.conf.j2
index 4e7b5d8d7..1823657d7 100644
--- a/data/templates/conserver/conserver.conf.tmpl
+++ b/data/templates/conserver/conserver.conf.j2
@@ -17,7 +17,7 @@ default * {
##
{% for key, value in device.items() %}
{# Depending on our USB serial console we could require a path adjustment #}
-{% set path = '/dev' if key.startswith('ttyS') else '/dev/serial/by-bus' %}
+{% set path = '/dev' if key.startswith('ttyS') else '/dev/serial/by-bus' %}
console {{ key }} {
master localhost;
type device;
diff --git a/data/templates/conserver/dropbear@.service.tmpl b/data/templates/conserver/dropbear@.service.j2
index e355dab43..e355dab43 100644
--- a/data/templates/conserver/dropbear@.service.tmpl
+++ b/data/templates/conserver/dropbear@.service.j2
diff --git a/data/templates/containers/registries.conf.j2 b/data/templates/container/registries.conf.j2
index 4057bb452..2e86466a1 100644
--- a/data/templates/containers/registries.conf.j2
+++ b/data/templates/container/registries.conf.j2
@@ -1,4 +1,4 @@
-### Autogenerated by /usr/libexec/vyos/conf_mode/containers.py ###
+### Autogenerated by container.py ###
# For more information on this configuration file, see containers-registries.conf(5).
#
diff --git a/data/templates/container/storage.conf.j2 b/data/templates/container/storage.conf.j2
new file mode 100644
index 000000000..665f9bf95
--- /dev/null
+++ b/data/templates/container/storage.conf.j2
@@ -0,0 +1,4 @@
+### Autogenerated by container.py ###
+[storage]
+ driver = "vfs"
+ graphroot = "/usr/lib/live/mount/persistence/container/storage"
diff --git a/data/templates/containers/storage.conf.j2 b/data/templates/containers/storage.conf.j2
deleted file mode 100644
index 3a69b7252..000000000
--- a/data/templates/containers/storage.conf.j2
+++ /dev/null
@@ -1,5 +0,0 @@
-### Autogenerated by /usr/libexec/vyos/conf_mode/containers.py ###
-
-[storage]
- driver = "vfs"
- graphroot = "/config/containers/storage"
diff --git a/data/templates/firewall/nftables-defines.j2 b/data/templates/firewall/nftables-defines.j2
new file mode 100644
index 000000000..4fa92f2e3
--- /dev/null
+++ b/data/templates/firewall/nftables-defines.j2
@@ -0,0 +1,32 @@
+{% if group is vyos_defined %}
+{% if group.address_group is vyos_defined %}
+{% for group_name, group_conf in group.address_group.items() %}
+define A_{{ group_name }} = { {{ group_conf.address | join(",") }} }
+{% endfor %}
+{% endif %}
+{% if group.ipv6_address_group is vyos_defined %}
+{% for group_name, group_conf in group.ipv6_address_group.items() %}
+define A6_{{ group_name }} = { {{ group_conf.address | join(",") }} }
+{% endfor %}
+{% endif %}
+{% if group.mac_group is vyos_defined %}
+{% for group_name, group_conf in group.mac_group.items() %}
+define M_{{ group_name }} = { {{ group_conf.mac_address | join(",") }} }
+{% endfor %}
+{% endif %}
+{% if group.network_group is vyos_defined %}
+{% for group_name, group_conf in group.network_group.items() %}
+define N_{{ group_name }} = { {{ group_conf.network | join(",") }} }
+{% endfor %}
+{% endif %}
+{% if group.ipv6_network_group is vyos_defined %}
+{% for group_name, group_conf in group.ipv6_network_group.items() %}
+define N6_{{ group_name }} = { {{ group_conf.network | join(",") }} }
+{% endfor %}
+{% endif %}
+{% if group.port_group is vyos_defined %}
+{% for group_name, group_conf in group.port_group.items() %}
+define P_{{ group_name }} = { {{ group_conf.port | join(",") }} }
+{% endfor %}
+{% endif %}
+{% endif %} \ No newline at end of file
diff --git a/data/templates/firewall/nftables-defines.tmpl b/data/templates/firewall/nftables-defines.tmpl
deleted file mode 100644
index 66d31093b..000000000
--- a/data/templates/firewall/nftables-defines.tmpl
+++ /dev/null
@@ -1,32 +0,0 @@
-{% if group is vyos_defined %}
-{% if group.address_group is vyos_defined %}
-{% for group_name, group_conf in group.address_group.items() %}
-define A_{{ group_name }} = { {{ group_conf.address | join(",") }} }
-{% endfor %}
-{% endif %}
-{% if group.ipv6_address_group is vyos_defined %}
-{% for group_name, group_conf in group.ipv6_address_group.items() %}
-define A6_{{ group_name }} = { {{ group_conf.address | join(",") }} }
-{% endfor %}
-{% endif %}
-{% if group.mac_group is vyos_defined %}
-{% for group_name, group_conf in group.mac_group.items() %}
-define M_{{ group_name }} = { {{ group_conf.mac_address | join(",") }} }
-{% endfor %}
-{% endif %}
-{% if group.network_group is vyos_defined %}
-{% for group_name, group_conf in group.network_group.items() %}
-define N_{{ group_name }} = { {{ group_conf.network | join(",") }} }
-{% endfor %}
-{% endif %}
-{% if group.ipv6_network_group is vyos_defined %}
-{% for group_name, group_conf in group.ipv6_network_group.items() %}
-define N6_{{ group_name }} = { {{ group_conf.network | join(",") }} }
-{% endfor %}
-{% endif %}
-{% if group.port_group is vyos_defined %}
-{% for group_name, group_conf in group.port_group.items() %}
-define P_{{ group_name }} = { {{ group_conf.port | join(",") }} }
-{% endfor %}
-{% endif %}
-{% endif %} \ No newline at end of file
diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.j2
index 63aa48c77..1481e9104 100644
--- a/data/templates/firewall/nftables-nat.tmpl
+++ b/data/templates/firewall/nftables-nat.j2
@@ -1,141 +1,141 @@
#!/usr/sbin/nft -f
{% macro nat_rule(rule, config, chain) %}
-{% set comment = '' %}
-{% set base_log = '' %}
-{% set src_addr = 'ip saddr ' ~ config.source.address.replace('!','!= ') if config.source.address is vyos_defined %}
-{% set dst_addr = 'ip daddr ' ~ config.destination.address.replace('!','!= ') if config.destination.address is vyos_defined %}
-{# negated port groups need special treatment, move != in front of { } group #}
-{% if config.source.port is vyos_defined and config.source.port.startswith('!') %}
+{% set comment = '' %}
+{% set base_log = '' %}
+{% set src_addr = 'ip saddr ' ~ config.source.address.replace('!','!= ') if config.source.address is vyos_defined %}
+{% set dst_addr = 'ip daddr ' ~ config.destination.address.replace('!','!= ') if config.destination.address is vyos_defined %}
+{# negated port groups need special treatment, move != in front of { } group #}
+{% if config.source.port is vyos_defined and config.source.port.startswith('!') %}
{% set src_port = 'sport != { ' ~ config.source.port.replace('!','') ~ ' }' %}
-{% else %}
+{% else %}
{% set src_port = 'sport { ' ~ config.source.port ~ ' }' if config.source.port is vyos_defined %}
-{% endif %}
-{# negated port groups need special treatment, move != in front of { } group #}
-{% if config.destination.port is vyos_defined and config.destination.port.startswith('!') %}
+{% endif %}
+{# negated port groups need special treatment, move != in front of { } group #}
+{% if config.destination.port is vyos_defined and config.destination.port.startswith('!') %}
{% set dst_port = 'dport != { ' ~ config.destination.port.replace('!','') ~ ' }' %}
-{% else %}
+{% else %}
{% set dst_port = 'dport { ' ~ config.destination.port ~ ' }' if config.destination.port is vyos_defined %}
-{% endif %}
-{% if chain is vyos_defined('PREROUTING') %}
+{% endif %}
+{% if chain is vyos_defined('PREROUTING') %}
{% set comment = 'DST-NAT-' ~ rule %}
{% set base_log = '[NAT-DST-' ~ rule %}
{% set interface = ' iifname "' ~ config.inbound_interface ~ '"' if config.inbound_interface is vyos_defined and config.inbound_interface is not vyos_defined('any') else '' %}
{% if config.translation.address is vyos_defined %}
-{# support 1:1 network translation #}
-{% if config.translation.address | is_ip_network %}
-{% set trns_addr = 'dnat ip prefix to ip daddr map { ' ~ config.destination.address ~ ' : ' ~ config.translation.address ~ ' }' %}
-{# we can now clear out the dst_addr part as it's already covered in aboves map #}
-{% set dst_addr = '' %}
-{% else %}
-{% set trns_addr = 'dnat to ' ~ config.translation.address %}
-{% endif %}
+{# support 1:1 network translation #}
+{% if config.translation.address | is_ip_network %}
+{% set trns_addr = 'dnat ip prefix to ip daddr map { ' ~ config.destination.address ~ ' : ' ~ config.translation.address ~ ' }' %}
+{# we can now clear out the dst_addr part as it's already covered in aboves map #}
+{% set dst_addr = '' %}
+{% else %}
+{% set trns_addr = 'dnat to ' ~ config.translation.address %}
+{% endif %}
{% endif %}
-{% elif chain is vyos_defined('POSTROUTING') %}
+{% elif chain is vyos_defined('POSTROUTING') %}
{% set comment = 'SRC-NAT-' ~ rule %}
{% set base_log = '[NAT-SRC-' ~ rule %}
{% set interface = ' oifname "' ~ config.outbound_interface ~ '"' if config.outbound_interface is vyos_defined and config.outbound_interface is not vyos_defined('any') else '' %}
{% if config.translation.address is vyos_defined %}
-{% if config.translation.address is vyos_defined('masquerade') %}
-{% set trns_addr = config.translation.address %}
-{% if config.translation.port is vyos_defined %}
-{% set trns_addr = trns_addr ~ ' to ' %}
+{% if config.translation.address is vyos_defined('masquerade') %}
+{% set trns_addr = config.translation.address %}
+{% if config.translation.port is vyos_defined %}
+{% set trns_addr = trns_addr ~ ' to ' %}
+{% endif %}
+{# support 1:1 network translation #}
+{% elif config.translation.address | is_ip_network %}
+{% set trns_addr = 'snat ip prefix to ip saddr map { ' ~ config.source.address ~ ' : ' ~ config.translation.address ~ ' }' %}
+{# we can now clear out the src_addr part as it's already covered in aboves map #}
+{% set src_addr = '' %}
+{% else %}
+{% set trns_addr = 'snat to ' ~ config.translation.address %}
{% endif %}
-{# support 1:1 network translation #}
-{% elif config.translation.address | is_ip_network %}
-{% set trns_addr = 'snat ip prefix to ip saddr map { ' ~ config.source.address ~ ' : ' ~ config.translation.address ~ ' }' %}
-{# we can now clear out the src_addr part as it's already covered in aboves map #}
-{% set src_addr = '' %}
-{% else %}
-{% set trns_addr = 'snat to ' ~ config.translation.address %}
-{% endif %}
{% endif %}
-{% endif %}
-{% set trns_port = ':' ~ config.translation.port if config.translation.port is vyos_defined %}
-{# protocol has a default value thus it is always present #}
-{% if config.protocol is vyos_defined('tcp_udp') %}
+{% endif %}
+{% set trns_port = ':' ~ config.translation.port if config.translation.port is vyos_defined %}
+{# protocol has a default value thus it is always present #}
+{% if config.protocol is vyos_defined('tcp_udp') %}
{% set protocol = 'tcp' %}
{% set comment = comment ~ ' tcp_udp' %}
-{% else %}
+{% else %}
{% set protocol = config.protocol %}
-{% endif %}
-{% if config.log is vyos_defined %}
+{% endif %}
+{% if config.log is vyos_defined %}
{% if config.exclude is vyos_defined %}
-{% set log = base_log ~ '-EXCL]' %}
+{% set log = base_log ~ '-EXCL]' %}
{% elif config.translation.address is vyos_defined('masquerade') %}
-{% set log = base_log +'-MASQ]' %}
+{% set log = base_log ~ '-MASQ]' %}
{% else %}
-{% set log = base_log ~ ']' %}
+{% set log = base_log ~ ']' %}
{% endif %}
-{% endif %}
-{% if config.exclude is vyos_defined %}
+{% endif %}
+{% if config.exclude is vyos_defined %}
{# rule has been marked as 'exclude' thus we simply return here #}
{% set trns_addr = 'return' %}
{% set trns_port = '' %}
-{% endif %}
-{# T1083: NAT address and port translation options #}
-{% if config.translation.options is vyos_defined %}
+{% endif %}
+{# T1083: NAT address and port translation options #}
+{% if config.translation.options is vyos_defined %}
{% if config.translation.options.address_mapping is vyos_defined('persistent') %}
{% set trns_opts_addr = 'persistent' %}
{% endif %}
{% if config.translation.options.port_mapping is vyos_defined('random') %}
-{% set trns_opts_port = 'random' %}
+{% set trns_opts_port = 'random' %}
{% elif config.translation.options.port_mapping is vyos_defined('fully-random') %}
-{% set trns_opts_port = 'fully-random' %}
+{% set trns_opts_port = 'fully-random' %}
{% endif %}
-{% endif %}
-{% if trns_opts_addr is vyos_defined and trns_opts_port is vyos_defined %}
+{% endif %}
+{% if trns_opts_addr is vyos_defined and trns_opts_port is vyos_defined %}
{% set trns_opts = trns_opts_addr ~ ',' ~ trns_opts_port %}
-{% elif trns_opts_addr is vyos_defined %}
+{% elif trns_opts_addr is vyos_defined %}
{% set trns_opts = trns_opts_addr %}
-{% elif trns_opts_port is vyos_defined %}
+{% elif trns_opts_port is vyos_defined %}
{% set trns_opts = trns_opts_port %}
-{% endif %}
-{% set output = 'add rule ip nat ' ~ chain ~ interface %}
-{% if protocol is not vyos_defined('all') %}
+{% endif %}
+{% set output = 'add rule ip nat ' ~ chain ~ interface %}
+{% if protocol is not vyos_defined('all') %}
{% set output = output ~ ' ip protocol ' ~ protocol %}
-{% endif %}
-{% if src_addr is vyos_defined %}
+{% endif %}
+{% if src_addr is vyos_defined %}
{% set output = output ~ ' ' ~ src_addr %}
-{% endif %}
-{% if src_port is vyos_defined %}
+{% endif %}
+{% if src_port is vyos_defined %}
{% set output = output ~ ' ' ~ protocol ~ ' ' ~ src_port %}
-{% endif %}
-{% if dst_addr is vyos_defined %}
+{% endif %}
+{% if dst_addr is vyos_defined %}
{% set output = output ~ ' ' ~ dst_addr %}
-{% endif %}
-{% if dst_port is vyos_defined %}
+{% endif %}
+{% if dst_port is vyos_defined %}
{% set output = output ~ ' ' ~ protocol ~ ' ' ~ dst_port %}
-{% endif %}
-{# Count packets #}
-{% set output = output ~ ' counter' %}
-{# Special handling of log option, we must repeat the entire rule before the #}
-{# NAT translation options are added, this is essential #}
-{% if log is vyos_defined %}
+{% endif %}
+{# Count packets #}
+{% set output = output ~ ' counter' %}
+{# Special handling of log option, we must repeat the entire rule before the #}
+{# NAT translation options are added, this is essential #}
+{% if log is vyos_defined %}
{% set log_output = output ~ ' log prefix "' ~ log ~ '" comment "' ~ comment ~ '"' %}
-{% endif %}
-{% if trns_addr is vyos_defined %}
+{% endif %}
+{% if trns_addr is vyos_defined %}
{% set output = output ~ ' ' ~ trns_addr %}
-{% endif %}
-{% if trns_port is vyos_defined %}
+{% endif %}
+{% if trns_port is vyos_defined %}
{# Do not add a whitespace here, translation port must be directly added after IP address #}
{# e.g. 192.0.2.10:3389 #}
{% set output = output ~ trns_port %}
-{% endif %}
-{% if trns_opts is vyos_defined %}
+{% endif %}
+{% if trns_opts is vyos_defined %}
{% set output = output ~ ' ' ~ trns_opts %}
-{% endif %}
-{% if comment is vyos_defined %}
+{% endif %}
+{% if comment is vyos_defined %}
{% set output = output ~ ' comment "' ~ comment ~ '"' %}
-{% endif %}
-{{ log_output if log_output is vyos_defined}}
+{% endif %}
+{{ log_output if log_output is vyos_defined }}
{{ output }}
-{# Special handling if protocol is tcp_udp, we must repeat the entire rule with udp as protocol #}
-{% if config.protocol is vyos_defined('tcp_udp') %}
+{# Special handling if protocol is tcp_udp, we must repeat the entire rule with udp as protocol #}
+{% if config.protocol is vyos_defined('tcp_udp') %}
{# Beware of trailing whitespace, without it the comment tcp_udp will be changed to udp_udp #}
{{ log_output | replace('tcp ', 'udp ') if log_output is vyos_defined }}
{{ output | replace('tcp ', 'udp ') }}
-{% endif %}
+{% endif %}
{% endmacro %}
# Start with clean SNAT and DNAT chains
@@ -143,7 +143,7 @@ flush chain ip nat PREROUTING
flush chain ip nat POSTROUTING
{% if helper_functions is vyos_defined('remove') %}
{# NAT if going to be disabled - remove rules and targets from nftables #}
-{% set base_command = 'delete rule ip raw' %}
+{% set base_command = 'delete rule ip raw' %}
{{ base_command }} PREROUTING handle {{ pre_ct_ignore }}
{{ base_command }} OUTPUT handle {{ out_ct_ignore }}
{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
@@ -155,7 +155,7 @@ delete chain ip raw NAT_CONNTRACK
{# NAT if enabled - add targets to nftables #}
add chain ip raw NAT_CONNTRACK
add rule ip raw NAT_CONNTRACK counter accept
-{% set base_command = 'add rule ip raw' %}
+{% set base_command = 'add rule ip raw' %}
{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYOS_CT_HELPER
{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYOS_CT_HELPER
{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
@@ -167,16 +167,16 @@ add rule ip raw NAT_CONNTRACK counter accept
#
add rule ip nat PREROUTING counter jump VYOS_PRE_DNAT_HOOK
{% if destination.rule is vyos_defined %}
-{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
+{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
{{ nat_rule(rule, config, 'PREROUTING') }}
-{% endfor %}
+{% endfor %}
{% endif %}
#
# Source NAT rules build up here
#
add rule ip nat POSTROUTING counter jump VYOS_PRE_SNAT_HOOK
{% if source.rule is vyos_defined %}
-{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
+{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
{{ nat_rule(rule, config, 'POSTROUTING') }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/firewall/nftables-nat66.tmpl b/data/templates/firewall/nftables-nat66.j2
index ed98b888a..003b138b2 100644
--- a/data/templates/firewall/nftables-nat66.tmpl
+++ b/data/templates/firewall/nftables-nat66.j2
@@ -1,22 +1,22 @@
#!/usr/sbin/nft -f
{% macro nptv6_rule(rule,config, chain) %}
-{% set comment = '' %}
-{% set base_log = '' %}
-{% set src_prefix = 'ip6 saddr ' ~ config.source.prefix if config.source.prefix is vyos_defined %}
-{% set dest_address = 'ip6 daddr ' ~ config.destination.address if config.destination.address is vyos_defined %}
-{% if chain is vyos_defined('PREROUTING') %}
+{% set comment = '' %}
+{% set base_log = '' %}
+{% set src_prefix = 'ip6 saddr ' ~ config.source.prefix if config.source.prefix is vyos_defined %}
+{% set dest_address = 'ip6 daddr ' ~ config.destination.address if config.destination.address is vyos_defined %}
+{% if chain is vyos_defined('PREROUTING') %}
{% set comment = 'DST-NAT66-' ~ rule %}
{% set base_log = '[NAT66-DST-' ~ rule %}
{% set interface = ' iifname "' ~ config.inbound_interface ~ '"' if config.inbound_interface is vyos_defined and config.inbound_interface is not vyos_defined('any') else '' %}
{% if config.translation.address | is_ip_network %}
-{# support 1:1 network translation #}
-{% set dnat_type = 'dnat prefix to ' %}
+{# support 1:1 network translation #}
+{% set dnat_type = 'dnat prefix to ' %}
{% else %}
-{% set dnat_type = 'dnat to ' %}
+{% set dnat_type = 'dnat to ' %}
{% endif %}
{% set trns_address = dnat_type ~ config.translation.address if config.translation.address is vyos_defined %}
-{% elif chain is vyos_defined('POSTROUTING') %}
+{% elif chain is vyos_defined('POSTROUTING') %}
{% set comment = 'SRC-NAT66-' ~ rule %}
{% set base_log = '[NAT66-SRC-' ~ rule %}
{% if config.translation.address is vyos_defined %}
@@ -33,34 +33,34 @@
{% endif %}
{% endif %}
{% set interface = ' oifname "' ~ config.outbound_interface ~ '"' if config.outbound_interface is vyos_defined else '' %}
-{% endif %}
-{% if config.log is vyos_defined %}
+{% endif %}
+{% if config.log is vyos_defined %}
{% if config.translation.address is vyos_defined('masquerade') %}
-{% set log = base_log +'-MASQ]' %}
+{% set log = base_log ~ '-MASQ]' %}
{% else %}
-{% set log = base_log ~ ']' %}
+{% set log = base_log ~ ']' %}
{% endif %}
-{% endif %}
-{% set output = 'add rule ip6 nat ' ~ chain ~ interface %}
-{# Count packets #}
-{% set output = output ~ ' counter' %}
-{# Special handling of log option, we must repeat the entire rule before the #}
-{# NAT translation options are added, this is essential #}
-{% if log is vyos_defined %}
+{% endif %}
+{% set output = 'add rule ip6 nat ' ~ chain ~ interface %}
+{# Count packets #}
+{% set output = output ~ ' counter' %}
+{# Special handling of log option, we must repeat the entire rule before the #}
+{# NAT translation options are added, this is essential #}
+{% if log is vyos_defined %}
{% set log_output = output ~ ' log prefix "' ~ log ~ '" comment "' ~ comment ~ '"' %}
-{% endif %}
-{% if src_prefix is vyos_defined %}
+{% endif %}
+{% if src_prefix is vyos_defined %}
{% set output = output ~ ' ' ~ src_prefix %}
-{% endif %}
-{% if dest_address is vyos_defined %}
+{% endif %}
+{% if dest_address is vyos_defined %}
{% set output = output ~ ' ' ~ dest_address %}
-{% endif %}
-{% if trns_address is vyos_defined %}
+{% endif %}
+{% if trns_address is vyos_defined %}
{% set output = output ~ ' ' ~ trns_address %}
-{% endif %}
-{% if comment is vyos_defined %}
+{% endif %}
+{% if comment is vyos_defined %}
{% set output = output ~ ' comment "' ~ comment ~ '"' %}
-{% endif %}
+{% endif %}
{{ log_output if log_output is vyos_defined }}
{{ output }}
{% endmacro %}
@@ -69,9 +69,9 @@
flush table ip6 nat
{% if helper_functions is vyos_defined('remove') %}
{# NAT if going to be disabled - remove rules and targets from nftables #}
-{% set base_command = 'delete rule ip6 raw' %}
-{{base_command}} PREROUTING handle {{ pre_ct_conntrack }}
-{{base_command}} OUTPUT handle {{ out_ct_conntrack }}
+{% set base_command = 'delete rule ip6 raw' %}
+{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
+{{ base_command }} OUTPUT handle {{ out_ct_conntrack }}
delete chain ip6 raw NAT_CONNTRACK
@@ -79,7 +79,7 @@ delete chain ip6 raw NAT_CONNTRACK
{# NAT if enabled - add targets to nftables #}
add chain ip6 raw NAT_CONNTRACK
add rule ip6 raw NAT_CONNTRACK counter accept
-{% set base_command = 'add rule ip6 raw' %}
+{% set base_command = 'add rule ip6 raw' %}
{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
{% endif %}
@@ -88,15 +88,15 @@ add rule ip6 raw NAT_CONNTRACK counter accept
# Destination NAT66 rules build up here
#
{% if destination.rule is vyos_defined %}
-{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
+{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
{{ nptv6_rule(rule, config, 'PREROUTING') }}
-{% endfor %}
+{% endfor %}
{% endif %}
#
# Source NAT66 rules build up here
#
{% if source.rule is vyos_defined %}
-{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
+{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
{{ nptv6_rule(rule, config, 'POSTROUTING') }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/firewall/nftables-policy.tmpl b/data/templates/firewall/nftables-policy.j2
index d1b0fa56e..0154c9f7e 100644
--- a/data/templates/firewall/nftables-policy.tmpl
+++ b/data/templates/firewall/nftables-policy.j2
@@ -1,9 +1,9 @@
#!/usr/sbin/nft -f
{% if cleanup_commands is vyos_defined %}
-{% for command in cleanup_commands %}
+{% for command in cleanup_commands %}
{{ command }}
-{% endfor %}
+{% endfor %}
{% endif %}
include "/run/nftables_defines.conf"
@@ -18,17 +18,17 @@ table ip mangle {
}
{% endif %}
{% if route is vyos_defined %}
-{% for route_text, conf in route.items() %}
+{% for route_text, conf in route.items() %}
chain VYOS_PBR_{{ route_text }} {
-{% if conf.rule is vyos_defined %}
-{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
{{ rule_conf | nft_rule(route_text, rule_id, 'ip') }}
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
{{ conf | nft_default_rule(route_text) }}
}
-{% endfor %}
-{%- endif %}
+{% endfor %}
+{% endif %}
}
table ip6 mangle {
@@ -41,15 +41,15 @@ table ip6 mangle {
}
{% endif %}
{% if route6 is vyos_defined %}
-{% for route_text, conf in route6.items() %}
+{% for route_text, conf in route6.items() %}
chain VYOS_PBR6_{{ route_text }} {
-{% if conf.rule is vyos_defined %}
-{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
{{ rule_conf | nft_rule(route_text, rule_id, 'ip6') }}
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
{{ conf | nft_default_rule(route_text) }}
}
-{% endfor %}
+{% endfor %}
{% endif %}
}
diff --git a/data/templates/firewall/nftables-vrf-zones.tmpl b/data/templates/firewall/nftables-vrf-zones.j2
index eecf47b78..eecf47b78 100644
--- a/data/templates/firewall/nftables-vrf-zones.tmpl
+++ b/data/templates/firewall/nftables-vrf-zones.j2
diff --git a/data/templates/firewall/nftables.tmpl b/data/templates/firewall/nftables.j2
index 3a3f2e04c..fac3fad03 100644
--- a/data/templates/firewall/nftables.tmpl
+++ b/data/templates/firewall/nftables.j2
@@ -1,9 +1,9 @@
#!/usr/sbin/nft -f
{% if cleanup_commands is vyos_defined %}
-{% for command in cleanup_commands %}
+{% for command in cleanup_commands %}
{{ command }}
-{% endfor %}
+{% endfor %}
{% endif %}
include "/run/nftables_defines.conf"
@@ -31,39 +31,39 @@ table ip filter {
}
{% endif %}
{% if name is vyos_defined %}
-{% set ns = namespace(sets=[]) %}
-{% for name_text, conf in name.items() %}
+{% set ns = namespace(sets=[]) %}
+{% for name_text, conf in name.items() %}
chain NAME_{{ name_text }} {
-{% if conf.rule is vyos_defined %}
-{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
{{ rule_conf | nft_rule(name_text, rule_id) }}
-{% if rule_conf.recent is vyos_defined %}
-{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
{% endif %}
-{% endfor %}
-{% endif %}
{{ conf | nft_default_rule(name_text) }}
}
-{% endfor %}
-{% for set_name in ns.sets %}
+{% endfor %}
+{% for set_name in ns.sets %}
set RECENT_{{ set_name }} {
type ipv4_addr
size 65535
flags dynamic
}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if state_policy is vyos_defined %}
chain VYOS_STATE_POLICY {
-{% if state_policy.established is vyos_defined %}
+{% if state_policy.established is vyos_defined %}
{{ state_policy.established | nft_state_policy('established') }}
-{% endif %}
-{% if state_policy.invalid is vyos_defined %}
+{% endif %}
+{% if state_policy.invalid is vyos_defined %}
{{ state_policy.invalid | nft_state_policy('invalid') }}
-{% endif %}
-{% if state_policy.related is vyos_defined %}
+{% endif %}
+{% if state_policy.related is vyos_defined %}
{{ state_policy.related | nft_state_policy('related') }}
-{% endif %}
+{% endif %}
return
}
{% endif %}
@@ -92,39 +92,39 @@ table ip6 filter {
}
{% endif %}
{% if ipv6_name is vyos_defined %}
-{% set ns = namespace(sets=[]) %}
-{% for name_text, conf in ipv6_name.items() %}
+{% set ns = namespace(sets=[]) %}
+{% for name_text, conf in ipv6_name.items() %}
chain NAME6_{{ name_text }} {
-{% if conf.rule is vyos_defined %}
-{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
{{ rule_conf | nft_rule(name_text, rule_id, 'ip6') }}
-{% if rule_conf.recent is vyos_defined %}
-{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
{% endif %}
-{% endfor %}
-{% endif %}
{{ conf | nft_default_rule(name_text) }}
}
-{% endfor %}
-{% for set_name in ns.sets %}
+{% endfor %}
+{% for set_name in ns.sets %}
set RECENT6_{{ set_name }} {
type ipv6_addr
size 65535
flags dynamic
}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if state_policy is vyos_defined %}
chain VYOS_STATE_POLICY6 {
-{% if state_policy.established is vyos_defined %}
+{% if state_policy.established is vyos_defined %}
{{ state_policy.established | nft_state_policy('established', ipv6=True) }}
-{% endif %}
-{% if state_policy.invalid is vyos_defined %}
+{% endif %}
+{% if state_policy.invalid is vyos_defined %}
{{ state_policy.invalid | nft_state_policy('invalid', ipv6=True) }}
-{% endif %}
-{% if state_policy.related is vyos_defined %}
+{% endif %}
+{% if state_policy.related is vyos_defined %}
{{ state_policy.related | nft_state_policy('related', ipv6=True) }}
-{% endif %}
+{% endif %}
return
}
{% endif %}
diff --git a/data/templates/firewall/upnpd.conf.tmpl b/data/templates/firewall/upnpd.conf.j2
index 6e73995fa..27573cbf9 100644
--- a/data/templates/firewall/upnpd.conf.tmpl
+++ b/data/templates/firewall/upnpd.conf.j2
@@ -5,9 +5,9 @@ ext_ifname={{ wan_interface }}
{% if wan_ip is vyos_defined %}
# If the WAN interface has several IP addresses, you
# can specify the one to use below
-{% for addr in wan_ip %}
+{% for addr in wan_ip %}
ext_ip={{ addr }}
-{% endfor %}
+{% endfor %}
{% endif %}
# LAN network interfaces IPs / networks
@@ -20,15 +20,15 @@ ext_ip={{ addr }}
# When MULTIPLE_EXTERNAL_IP is enabled, the external IP
# address associated with the subnet follows. For example:
# listening_ip=192.168.0.1/24 88.22.44.13
-{% for addr in listen %}
-{% if addr | is_ipv4 %}
+{% for addr in listen %}
+{% if addr | is_ipv4 %}
listening_ip={{ addr }}
-{% elif addr | is_ipv6 %}
+{% elif addr | is_ipv6 %}
ipv6_listening_ip={{ addr }}
-{% else %}
+{% else %}
listening_ip={{ addr }}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
# CAUTION: mixing up WAN and LAN interfaces may introduce security risks!
@@ -57,12 +57,12 @@ enable_upnp=yes
# PCP
# Configure the minimum and maximum lifetime of a port mapping in seconds
# 120s and 86400s (24h) are suggested values from PCP-base
-{% if pcp_lifetime.max is vyos_defined %}
+{% if pcp_lifetime.max is vyos_defined %}
max_lifetime={{ pcp_lifetime.max }}
-{% endif %}
-{% if pcp_lifetime.min is vyos_defined %}
+{% endif %}
+{% if pcp_lifetime.min is vyos_defined %}
min_lifetime={{ pcp_lifetime.min }}
-{% endif %}
+{% endif %}
{% endif %}
@@ -142,11 +142,11 @@ lease_file=/config/upnp.leases
# modify the IP ranges to match their own internal networks, and
# also consider implementing network-specific restrictions
# CAUTION: failure to enforce any rules may permit insecure requests to be made!
-{% for rule, config in rules.items() %}
-{% if config.disable is vyos_defined %}
-{{ config.action}} {{ config.external_port_range }} {{ config.ip }} {{ config.internal_port_range }}
-{% endif %}
-{% endfor %}
+{% for rule, config in rules.items() %}
+{% if config.disable is vyos_defined %}
+{{ config.action }} {{ config.external_port_range }} {{ config.ip }} {{ config.internal_port_range }}
+{% endif %}
+{% endfor %}
{% endif %}
{% if stun is vyos_defined %}
diff --git a/data/templates/frr/daemons.frr.tmpl b/data/templates/frr/daemons.frr.tmpl
new file mode 100644
index 000000000..ab7b14d6b
--- /dev/null
+++ b/data/templates/frr/daemons.frr.tmpl
@@ -0,0 +1,54 @@
+zebra=yes
+bgpd=yes
+ospfd=yes
+ospf6d=yes
+ripd=yes
+ripngd=yes
+isisd=yes
+pimd=no
+ldpd=yes
+nhrpd=no
+eigrpd=no
+babeld=no
+sharpd=no
+pbrd=no
+bfdd=yes
+staticd=yes
+
+vtysh_enable=yes
+zebra_options=" -s 90000000 --daemon -A 127.0.0.1
+{%- if irdp is defined %} -M irdp{% endif -%}
+{%- if snmp is defined and snmp.zebra is defined %} -M snmp{% endif -%}
+"
+bgpd_options=" --daemon -A 127.0.0.1
+{%- if bmp is defined %} -M bmp{% endif -%}
+{%- if snmp is defined and snmp.bgpd is defined %} -M snmp{% endif -%}
+"
+ospfd_options=" --daemon -A 127.0.0.1
+{%- if snmp is defined and snmp.ospfd is defined %} -M snmp{% endif -%}
+"
+ospf6d_options=" --daemon -A ::1
+{%- if snmp is defined and snmp.ospf6d is defined %} -M snmp{% endif -%}
+"
+ripd_options=" --daemon -A 127.0.0.1
+{%- if snmp is defined and snmp.ripd is defined %} -M snmp{% endif -%}
+"
+ripngd_options=" --daemon -A ::1"
+isisd_options=" --daemon -A 127.0.0.1
+{%- if snmp is defined and snmp.isisd is defined %} -M snmp{% endif -%}
+"
+pimd_options=" --daemon -A 127.0.0.1"
+ldpd_options=" --daemon -A 127.0.0.1
+{%- if snmp is defined and snmp.ldpd is defined %} -M snmp{% endif -%}
+"
+nhrpd_options=" --daemon -A 127.0.0.1"
+eigrpd_options=" --daemon -A 127.0.0.1"
+babeld_options=" --daemon -A 127.0.0.1"
+sharpd_options=" --daemon -A 127.0.0.1"
+pbrd_options=" --daemon -A 127.0.0.1"
+staticd_options=" --daemon -A 127.0.0.1"
+bfdd_options=" --daemon -A 127.0.0.1"
+
+watchfrr_enable=no
+valgrind_enable=no
+
diff --git a/data/templates/frr/policy.frr.j2 b/data/templates/frr/policy.frr.j2
index 9f3097f82..a42b73e98 100644
--- a/data/templates/frr/policy.frr.j2
+++ b/data/templates/frr/policy.frr.j2
@@ -238,11 +238,14 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }}
{% if rule_config.set.aggregator.as is vyos_defined and rule_config.set.aggregator.ip is vyos_defined %}
set aggregator as {{ rule_config.set.aggregator.as }} {{ rule_config.set.aggregator.ip }}
{% endif %}
-{% if rule_config.set.as_path_exclude is vyos_defined %}
- set as-path exclude {{ rule_config.set.as_path_exclude }}
+{% if rule_config.set.as_path.exclude is vyos_defined %}
+ set as-path exclude {{ rule_config.set.as_path.exclude }}
{% endif %}
-{% if rule_config.set.as_path_prepend is vyos_defined %}
- set as-path prepend {{ rule_config.set.as_path_prepend }}
+{% if rule_config.set.as_path.prepend is vyos_defined %}
+ set as-path prepend {{ rule_config.set.as_path.prepend }}
+{% endif %}
+{% if rule_config.set.as_path.prepend_last_as is vyos_defined %}
+ set as-path prepend last-as {{ rule_config.set.as_path.prepend_last_as }}
{% endif %}
{% if rule_config.set.atomic_aggregate is vyos_defined %}
set atomic-aggregate
@@ -256,6 +259,12 @@ route-map {{ route_map }} {{ rule_config.action }} {{ rule }}
{% if rule_config.set.distance is vyos_defined %}
set distance {{ rule_config.set.distance }}
{% endif %}
+{% if rule_config.set.evpn.gateway.ipv4 is vyos_defined %}
+ set evpn gateway-ip ipv4 {{ rule_config.set.evpn.gateway.ipv4 }}
+{% endif %}
+{% if rule_config.set.evpn.gateway.ipv6 is vyos_defined %}
+ set evpn gateway-ip ipv6 {{ rule_config.set.evpn.gateway.ipv6 }}
+{% endif %}
{% if rule_config.set.extcommunity.bandwidth is vyos_defined %}
set extcommunity bandwidth {{ rule_config.set.extcommunity.bandwidth }}
{% endif %}
diff --git a/data/templates/getty/serial-getty.service.tmpl b/data/templates/getty/serial-getty.service.j2
index 0183eae7d..0183eae7d 100644
--- a/data/templates/getty/serial-getty.service.tmpl
+++ b/data/templates/getty/serial-getty.service.j2
diff --git a/data/templates/high-availability/keepalived.conf.j2 b/data/templates/high-availability/keepalived.conf.j2
new file mode 100644
index 000000000..6684dbc2c
--- /dev/null
+++ b/data/templates/high-availability/keepalived.conf.j2
@@ -0,0 +1,169 @@
+# Autogenerated by VyOS
+# Do not edit this file, all your changes will be lost
+# on next commit or reboot
+
+global_defs {
+ dynamic_interfaces
+ script_user root
+ notify_fifo /run/keepalived/keepalived_notify_fifo
+ notify_fifo_script /usr/libexec/vyos/system/keepalived-fifo.py
+}
+
+{% if vrrp.group is vyos_defined %}
+{% for name, group_config in vrrp.group.items() if group_config.disable is not vyos_defined %}
+{% if group_config.health_check.script is vyos_defined %}
+vrrp_script healthcheck_{{ name }} {
+ script "{{ group_config.health_check.script }}"
+ interval {{ group_config.health_check.interval }}
+ fall {{ group_config.health_check.failure_count }}
+ rise 1
+}
+{% endif %}
+vrrp_instance {{ name }} {
+{% if group_config.description is vyos_defined %}
+ # {{ group_config.description }}
+{% endif %}
+ state BACKUP
+ interface {{ group_config.interface }}
+ virtual_router_id {{ group_config.vrid }}
+ priority {{ group_config.priority }}
+ advert_int {{ group_config.advertise_interval }}
+{% if group_config.track.exclude_vrrp_interface is vyos_defined %}
+ dont_track_primary
+{% endif %}
+{% if group_config.no_preempt is not vyos_defined and group_config.preempt_delay is vyos_defined %}
+ preempt_delay {{ group_config.preempt_delay }}
+{% elif group_config.no_preempt is vyos_defined %}
+ nopreempt
+{% endif %}
+{% if group_config.peer_address is vyos_defined %}
+ unicast_peer { {{ group_config.peer_address }} }
+{% endif %}
+{% if group_config.hello_source_address is vyos_defined %}
+{% if group_config.peer_address is vyos_defined %}
+ unicast_src_ip {{ group_config.hello_source_address }}
+{% else %}
+ mcast_src_ip {{ group_config.hello_source_address }}
+{% endif %}
+{% endif %}
+{% if group_config.rfc3768_compatibility is vyos_defined and group_config.peer_address is vyos_defined %}
+ use_vmac {{ group_config.interface }}v{{ group_config.vrid }}
+ vmac_xmit_base
+{% elif group_config.rfc3768_compatibility is vyos_defined %}
+ use_vmac {{ group_config.interface }}v{{ group_config.vrid }}
+{% endif %}
+{% if group_config.authentication is vyos_defined %}
+ authentication {
+ auth_pass "{{ group_config.authentication.password }}"
+{% if group_config.authentication.type is vyos_defined('plaintext-password') %}
+ auth_type PASS
+{% else %}
+ auth_type {{ group_config.authentication.type | upper }}
+{% endif %}
+ }
+{% endif %}
+{% if group_config.address is vyos_defined %}
+ virtual_ipaddress {
+{% for addr, addr_config in group_config.address.items() %}
+ {{ addr }}{{ ' dev ' + addr_config.interface if addr_config.interface is vyos_defined }}
+{% endfor %}
+ }
+{% endif %}
+{% if group_config.excluded_address is vyos_defined %}
+ virtual_ipaddress_excluded {
+{% for addr in group_config.excluded_address %}
+ {{ addr }}
+{% endfor %}
+ }
+{% endif %}
+{% if group_config.track.interface is vyos_defined %}
+ track_interface {
+{% for interface in group_config.track.interface %}
+ {{ interface }}
+{% endfor %}
+ }
+{% endif %}
+{% if group_config.health_check.script is vyos_defined %}
+ track_script {
+ healthcheck_{{ name }}
+ }
+{% endif %}
+}
+{% endfor %}
+{% endif %}
+
+{% if vrrp.sync_group is vyos_defined %}
+{% for name, sync_group_config in vrrp.sync_group.items() if sync_group_config.disable is not vyos_defined %}
+vrrp_sync_group {{ name }} {
+ group {
+{% if sync_group_config.member is vyos_defined %}
+{% for member in sync_group_config.member %}
+ {{ member }}
+{% endfor %}
+{% endif %}
+ }
+
+{# Health-check scripts should be in section sync-group if member is part of the sync-group T4081 #}
+{% if vrrp.group is vyos_defined %}
+{% for name, group_config in vrrp.group.items() if group_config.disable is not vyos_defined %}
+{% if group_config.health_check.script is vyos_defined and name in sync_group_config.member %}
+ track_script {
+ healthcheck_{{ name }}
+ }
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if conntrack_sync_group is vyos_defined(name) %}
+{% set vyos_helper = "/usr/libexec/vyos/vyos-vrrp-conntracksync.sh" %}
+ notify_master "{{ vyos_helper }} master {{ name }}"
+ notify_backup "{{ vyos_helper }} backup {{ name }}"
+ notify_fault "{{ vyos_helper }} fault {{ name }}"
+{% endif %}
+}
+{% endfor %}
+{% endif %}
+
+{% if virtual_server is vyos_defined %}
+# Virtual-server configuration
+{% for vserver, vserver_config in virtual_server.items() %}
+virtual_server {{ vserver }} {{ vserver_config.port }} {
+ delay_loop {{ vserver_config.delay_loop }}
+{% if vserver_config.algorithm is vyos_defined('round-robin') %}
+ lb_algo rr
+{% elif vserver_config.algorithm is vyos_defined('weighted-round-robin') %}
+ lb_algo wrr
+{% elif vserver_config.algorithm is vyos_defined('least-connection') %}
+ lb_algo lc
+{% elif vserver_config.algorithm is vyos_defined('weighted-least-connection') %}
+ lb_algo wlc
+{% elif vserver_config.algorithm is vyos_defined('source-hashing') %}
+ lb_algo sh
+{% elif vserver_config.algorithm is vyos_defined('destination-hashing') %}
+ lb_algo dh
+{% elif vserver_config.algorithm is vyos_defined('locality-based-least-connection') %}
+ lb_algo lblc
+{% endif %}
+{% if vserver_config.forward_method is vyos_defined('nat') %}
+ lb_kind NAT
+{% elif vserver_config.forward_method is vyos_defined('direct') %}
+ lb_kind DR
+{% elif vserver_config.forward_method is vyos_defined('tunnel') %}
+ lb_kind TUN
+{% endif %}
+ persistence_timeout {{ vserver_config.persistence_timeout }}
+ protocol {{ vserver_config.protocol | upper }}
+{% if vserver_config.real_server is vyos_defined %}
+{% for rserver, rserver_config in vserver_config.real_server.items() %}
+ real_server {{ rserver }} {{ rserver_config.port }} {
+ weight 1
+ {{ vserver_config.protocol | upper }}_CHECK {
+{% if rserver_config.connection_timeout is vyos_defined %}
+ connect_timeout {{ rserver_config.connection_timeout }}
+{% endif %}
+ }
+ }
+{% endfor %}
+{% endif %}
+}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/high-availability/keepalived.conf.tmpl b/data/templates/high-availability/keepalived.conf.tmpl
deleted file mode 100644
index 202760251..000000000
--- a/data/templates/high-availability/keepalived.conf.tmpl
+++ /dev/null
@@ -1,169 +0,0 @@
-# Autogenerated by VyOS
-# Do not edit this file, all your changes will be lost
-# on next commit or reboot
-
-global_defs {
- dynamic_interfaces
- script_user root
- notify_fifo /run/keepalived/keepalived_notify_fifo
- notify_fifo_script /usr/libexec/vyos/system/keepalived-fifo.py
-}
-
-{% if vrrp.group is vyos_defined %}
-{% for name, group_config in vrrp.group.items() if group_config.disable is not vyos_defined %}
-{% if group_config.health_check.script is vyos_defined %}
-vrrp_script healthcheck_{{ name }} {
- script "{{ group_config.health_check.script }}"
- interval {{ group_config.health_check.interval }}
- fall {{ group_config.health_check.failure_count }}
- rise 1
-}
-{% endif %}
-vrrp_instance {{ name }} {
-{% if group_config.description is vyos_defined %}
- # {{ group_config.description }}
-{% endif %}
- state BACKUP
- interface {{ group_config.interface }}
- virtual_router_id {{ group_config.vrid }}
- priority {{ group_config.priority }}
- advert_int {{ group_config.advertise_interval }}
-{% if group_config.track.exclude_vrrp_interface is vyos_defined %}
- dont_track_primary
-{% endif %}
-{% if group_config.no_preempt is not vyos_defined and group_config.preempt_delay is vyos_defined %}
- preempt_delay {{ group_config.preempt_delay }}
-{% elif group_config.no_preempt is vyos_defined %}
- nopreempt
-{% endif %}
-{% if group_config.peer_address is vyos_defined %}
- unicast_peer { {{ group_config.peer_address }} }
-{% endif %}
-{% if group_config.hello_source_address is vyos_defined %}
-{% if group_config.peer_address is vyos_defined %}
- unicast_src_ip {{ group_config.hello_source_address }}
-{% else %}
- mcast_src_ip {{ group_config.hello_source_address }}
-{% endif %}
-{% endif %}
-{% if group_config.rfc3768_compatibility is vyos_defined and group_config.peer_address is vyos_defined %}
- use_vmac {{ group_config.interface }}v{{ group_config.vrid }}
- vmac_xmit_base
-{% elif group_config.rfc3768_compatibility is vyos_defined %}
- use_vmac {{ group_config.interface }}v{{ group_config.vrid }}
-{% endif %}
-{% if group_config.authentication is vyos_defined %}
- authentication {
- auth_pass "{{ group_config.authentication.password }}"
-{% if group_config.authentication.type is vyos_defined('plaintext-password') %}
- auth_type PASS
-{% else %}
- auth_type {{ group_config.authentication.type | upper }}
-{% endif %}
- }
-{% endif %}
-{% if group_config.address is vyos_defined %}
- virtual_ipaddress {
-{% for addr, addr_config in group_config.address.items() %}
- {{ addr }}{{ ' dev ' + addr_config.interface if addr_config.interface is vyos_defined }}
-{% endfor %}
- }
-{% endif %}
-{% if group_config.excluded_address is vyos_defined %}
- virtual_ipaddress_excluded {
-{% for addr in group_config.excluded_address %}
- {{ addr }}
-{% endfor %}
- }
-{% endif %}
-{% if group_config.track.interface is vyos_defined %}
- track_interface {
-{% for interface in group_config.track.interface %}
- {{ interface }}
-{% endfor %}
- }
-{% endif %}
-{% if group_config.health_check.script is vyos_defined %}
- track_script {
- healthcheck_{{ name }}
- }
-{% endif %}
-}
-{% endfor %}
-{% endif %}
-
-{% if vrrp.sync_group is vyos_defined %}
-{% for name, sync_group_config in vrrp.sync_group.items() if sync_group_config.disable is not vyos_defined %}
-vrrp_sync_group {{ name }} {
- group {
-{% if sync_group_config.member is vyos_defined %}
-{% for member in sync_group_config.member %}
- {{ member }}
-{% endfor %}
-{% endif %}
- }
-
-{# Health-check scripts should be in section sync-group if member is part of the sync-group T4081 #}
-{% if vrrp.group is vyos_defined %}
-{% for name, group_config in vrrp.group.items() if group_config.disable is not vyos_defined %}
-{% if group_config.health_check.script is vyos_defined and name in sync_group_config.member %}
- track_script {
- healthcheck_{{ name }}
- }
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if conntrack_sync_group is vyos_defined(name) %}
-{% set vyos_helper = "/usr/libexec/vyos/vyos-vrrp-conntracksync.sh" %}
- notify_master "{{ vyos_helper }} master {{ name }}"
- notify_backup "{{ vyos_helper }} backup {{ name }}"
- notify_fault "{{ vyos_helper }} fault {{ name }}"
-{% endif %}
-}
-{% endfor %}
-{% endif %}
-
-{% if virtual_server is vyos_defined %}
-# Virtual-server configuration
-{% for vserver, vserver_config in virtual_server.items() %}
-virtual_server {{ vserver }} {{ vserver_config.port }} {
- delay_loop {{ vserver_config.delay_loop }}
-{% if vserver_config.algorithm is vyos_defined('round-robin') %}
- lb_algo rr
-{% elif vserver_config.algorithm is vyos_defined('weighted-round-robin') %}
- lb_algo wrr
-{% elif vserver_config.algorithm is vyos_defined('least-connection') %}
- lb_algo lc
-{% elif vserver_config.algorithm is vyos_defined('weighted-least-connection') %}
- lb_algo wlc
-{% elif vserver_config.algorithm is vyos_defined('source-hashing') %}
- lb_algo sh
-{% elif vserver_config.algorithm is vyos_defined('destination-hashing') %}
- lb_algo dh
-{% elif vserver_config.algorithm is vyos_defined('locality-based-least-connection') %}
- lb_algo lblc
-{% endif %}
-{% if vserver_config.forward_method is vyos_defined('nat') %}
- lb_kind NAT
-{% elif vserver_config.forward_method is vyos_defined('direct') %}
- lb_kind DR
-{% elif vserver_config.forward_method is vyos_defined('tunnel') %}
- lb_kind TUN
-{% endif %}
- persistence_timeout {{ vserver_config.persistence_timeout }}
- protocol {{ vserver_config.protocol | upper }}
-{% if vserver_config.real_server is vyos_defined %}
-{% for rserver, rserver_config in vserver_config.real_server.items() %}
- real_server {{ rserver }} {{ rserver_config.port }} {
- weight 1
- {{ vserver_config.protocol | upper }}_CHECK {
-{% if rserver_config.connection_timeout is vyos_defined %}
- connect_timeout {{ rserver_config.connection_timeout }}
-{% endif %}
- }
- }
-{% endfor %}
-{% endif %}
-}
-{% endfor %}
-{% endif %}
diff --git a/data/templates/https/nginx.default.tmpl b/data/templates/https/nginx.default.j2
index a51505270..70e62ae7a 100644
--- a/data/templates/https/nginx.default.tmpl
+++ b/data/templates/https/nginx.default.j2
@@ -1,59 +1,56 @@
### Autogenerated by https.py ###
# Default server configuration
-#
{% for server in server_block_list %}
server {
-
# SSL configuration
#
-{% if server.address == '*' %}
+{% if server.address == '*' %}
listen {{ server.port }} ssl;
listen [::]:{{ server.port }} ssl;
-{% else %}
+{% else %}
listen {{ server.address | bracketize_ipv6 }}:{{ server.port }} ssl;
-{% endif %}
+{% endif %}
-{% for name in server.name %}
+{% for name in server.name %}
server_name {{ name }};
-{% endfor %}
+{% endfor %}
-{% if server.certbot %}
+{% if server.certbot %}
ssl_certificate {{ server.certbot_dir }}/live/{{ server.certbot_domain_dir }}/fullchain.pem;
ssl_certificate_key {{ server.certbot_dir }}/live/{{ server.certbot_domain_dir }}/privkey.pem;
include {{ server.certbot_dir }}/options-ssl-nginx.conf;
ssl_dhparam {{ server.certbot_dir }}/ssl-dhparams.pem;
-{% elif server.vyos_cert %}
+{% elif server.vyos_cert %}
ssl_certificate {{ server.vyos_cert.crt }};
ssl_certificate_key {{ server.vyos_cert.key }};
-{% else %}
+{% else %}
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
include snippets/snakeoil.conf;
-{% endif %}
+{% endif %}
ssl_protocols TLSv1.2 TLSv1.3;
# proxy settings for HTTP API, if enabled; 503, if not
location ~ /(retrieve|configure|config-file|image|generate|show|docs|openapi.json|redoc|graphql) {
-{% if server.api %}
-{% if server.api.socket %}
+{% if server.api %}
+{% if server.api.socket %}
proxy_pass http://unix:/run/api.sock;
-{% else %}
+{% else %}
proxy_pass http://localhost:{{ server.api.port }};
-{% endif %}
+{% endif %}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600;
proxy_buffering off;
-{% else %}
+{% else %}
return 503;
-{% endif %}
+{% endif %}
}
error_page 497 =301 https://$host:{{ server.port }}$request_uri;
-
}
{% endfor %}
diff --git a/data/templates/https/override.conf.tmpl b/data/templates/https/override.conf.j2
index c2c191b06..c2c191b06 100644
--- a/data/templates/https/override.conf.tmpl
+++ b/data/templates/https/override.conf.j2
diff --git a/data/templates/https/vyos-http-api.service.tmpl b/data/templates/https/vyos-http-api.service.j2
index fb424e06c..fb424e06c 100644
--- a/data/templates/https/vyos-http-api.service.tmpl
+++ b/data/templates/https/vyos-http-api.service.j2
diff --git a/data/templates/ids/fastnetmon.tmpl b/data/templates/ids/fastnetmon.j2
index b6bef9a68..c482002fa 100644
--- a/data/templates/ids/fastnetmon.tmpl
+++ b/data/templates/ids/fastnetmon.j2
@@ -29,22 +29,22 @@ enable_subnet_counters = off
mirror_afpacket = on
{% endif %}
-process_incoming_traffic = {{ 'on' if direction is vyos_defined and 'in' in direction else 'off '}}
-process_outgoing_traffic = {{ 'on' if direction is vyos_defined and 'out' in direction else 'off '}}
+process_incoming_traffic = {{ 'on' if direction is vyos_defined and 'in' in direction else 'off' }}
+process_outgoing_traffic = {{ 'on' if direction is vyos_defined and 'out' in direction else 'off' }}
{% if threshold is vyos_defined %}
-{% for thr, thr_value in threshold.items() %}
-{% if thr is vyos_defined('fps') %}
+{% for thr, thr_value in threshold.items() %}
+{% if thr is vyos_defined('fps') %}
ban_for_flows = on
threshold_flows = {{ thr_value }}
-{% elif thr is vyos_defined('mbps') %}
+{% elif thr is vyos_defined('mbps') %}
ban_for_bandwidth = on
threshold_mbps = {{ thr_value }}
-{% elif thr is vyos_defined('pps') %}
+{% elif thr is vyos_defined('pps') %}
ban_for_pps = on
threshold_pps = {{ thr_value }}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
{% if listen_interface is vyos_defined %}
diff --git a/data/templates/ids/fastnetmon_networks_list.tmpl b/data/templates/ids/fastnetmon_networks_list.j2
index ab9add22c..1c81180be 100644
--- a/data/templates/ids/fastnetmon_networks_list.tmpl
+++ b/data/templates/ids/fastnetmon_networks_list.j2
@@ -1,7 +1,7 @@
{% if network is vyos_defined(var_type=str) %}
{{ network }}
{% else %}
-{% for net in network %}
+{% for net in network %}
{{ net }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/igmp-proxy/igmpproxy.conf.tmpl b/data/templates/igmp-proxy/igmpproxy.conf.j2
index f32d68e43..ab3c9fd31 100644
--- a/data/templates/igmp-proxy/igmpproxy.conf.tmpl
+++ b/data/templates/igmp-proxy/igmpproxy.conf.j2
@@ -18,23 +18,23 @@
quickleave
{% endif %}
{% if interface is vyos_defined %}
-{% for iface, config in interface.items() %}
+{% for iface, config in interface.items() %}
# Configuration for {{ iface }} ({{ config.role }} interface)
-{% if config.role is vyos_defined('disabled') %}
+{% if config.role is vyos_defined('disabled') %}
phyint {{ iface }} disabled
-{% else %}
+{% else %}
phyint {{ iface }} {{ config.role }} ratelimit 0 threshold {{ config.threshold }}
-{% endif %}
-{% if config.alt_subnet is vyos_defined %}
-{% for subnet in config.alt_subnet %}
+{% endif %}
+{% if config.alt_subnet is vyos_defined %}
+{% for subnet in config.alt_subnet %}
altnet {{ subnet }}
-{% endfor %}
-{% endif %}
-{% if config.whitelist is vyos_defined %}
-{% for subnet in config.whitelist %}
+{% endfor %}
+{% endif %}
+{% if config.whitelist is vyos_defined %}
+{% for subnet in config.whitelist %}
whitelist {{ subnet }}
-{% endfor %}
-{% endif %}
-{% endfor %}
+{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/ipsec/charon.tmpl b/data/templates/ipsec/charon.j2
index 2eac24eaa..388559af8 100644
--- a/data/templates/ipsec/charon.tmpl
+++ b/data/templates/ipsec/charon.j2
@@ -1,6 +1,5 @@
# Options for the charon IKE daemon.
charon {
-
# Accept unencrypted ID and HASH payloads in IKEv1 Main Mode.
# accept_unencrypted_mainmode_messages = no
@@ -23,13 +22,13 @@ charon {
# Cisco FlexVPN
{% if options is vyos_defined %}
cisco_flexvpn = {{ 'yes' if options.flexvpn is vyos_defined else 'no' }}
-{% if options.virtual_ip is vyos_defined %}
+{% if options.virtual_ip is vyos_defined %}
install_virtual_ip = yes
-{% endif %}
-{% if options.interface is vyos_defined %}
+{% endif %}
+{% if options.interface is vyos_defined %}
install_virtual_ip_on = {{ options.interface }}
-{% endif %}
-{% endif %}
+{% endif %}
+{% endif %}
# Close the IKE_SA if setup of the CHILD_SA along with IKE_AUTH failed.
# close_ike_on_child_failure = no
diff --git a/data/templates/ipsec/charon/dhcp.conf.tmpl b/data/templates/ipsec/charon/dhcp.conf.j2
index aaa5613fb..aaa5613fb 100644
--- a/data/templates/ipsec/charon/dhcp.conf.tmpl
+++ b/data/templates/ipsec/charon/dhcp.conf.j2
diff --git a/data/templates/ipsec/charon/eap-radius.conf.tmpl b/data/templates/ipsec/charon/eap-radius.conf.j2
index b58022521..8495011fe 100644
--- a/data/templates/ipsec/charon/eap-radius.conf.tmpl
+++ b/data/templates/ipsec/charon/eap-radius.conf.j2
@@ -94,19 +94,19 @@ eap-radius {
# Section to specify multiple RADIUS servers.
servers {
-{% if remote_access.radius.server is vyos_defined %}
-{% for server, server_options in remote_access.radius.server.items() if server_options.disable is not vyos_defined %}
+{% if remote_access.radius.server is vyos_defined %}
+{% for server, server_options in remote_access.radius.server.items() if server_options.disable is not vyos_defined %}
{{ server | replace('.', '-') }} {
address = {{ server }}
secret = {{ server_options.key }}
auth_port = {{ server_options.port }}
-{% if server_options.disable_accounting is not vyos_defined %}
- acct_port = {{ server_options.port | int +1 }}
-{% endif %}
+{% if server_options.disable_accounting is not vyos_defined %}
+ acct_port = {{ server_options.port | int + 1 }}
+{% endif %}
sockets = 20
}
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
}
# Section to configure multiple XAuth authentication rounds via RADIUS.
diff --git a/data/templates/ipsec/interfaces_use.conf.tmpl b/data/templates/ipsec/interfaces_use.conf.j2
index 55c3ce4f3..c1bf8270d 100644
--- a/data/templates/ipsec/interfaces_use.conf.tmpl
+++ b/data/templates/ipsec/interfaces_use.conf.j2
@@ -1,5 +1,5 @@
-{% if interface is vyos_defined %}
+{% if interface is vyos_defined %}
charon {
interfaces_use = {{ ', '.join(interface) }}
}
-{% endif %} \ No newline at end of file
+{% endif %} \ No newline at end of file
diff --git a/data/templates/ipsec/ios_profile.tmpl b/data/templates/ipsec/ios_profile.j2
index c8e17729a..c8e17729a 100644
--- a/data/templates/ipsec/ios_profile.tmpl
+++ b/data/templates/ipsec/ios_profile.j2
diff --git a/data/templates/ipsec/ipsec.conf.j2 b/data/templates/ipsec/ipsec.conf.j2
new file mode 100644
index 000000000..f63995b38
--- /dev/null
+++ b/data/templates/ipsec/ipsec.conf.j2
@@ -0,0 +1,19 @@
+# Created by VyOS - manual changes will be overwritten
+
+config setup
+{% set charondebug = '' %}
+{% if log.subsystem is vyos_defined %}
+{% set subsystem = log.subsystem %}
+{% if 'any' in log.subsystem %}
+{% set subsystem = ['dmn', 'mgr', 'ike', 'chd','job', 'cfg', 'knl',
+ 'net', 'asn', 'enc', 'lib', 'esp', 'tls', 'tnc',
+ 'imc', 'imv', 'pts'] %}
+{% endif %}
+{% set charondebug = subsystem | join (' ' ~ log.level ~ ', ') ~ ' ' ~ log.level %}
+{% endif %}
+ charondebug = "{{ charondebug }}"
+ uniqueids = {{ "no" if disable_uniqreqids is vyos_defined else "yes" }}
+
+{% if include_ipsec_conf is vyos_defined %}
+include {{ include_ipsec_conf }}
+{% endif %}
diff --git a/data/templates/ipsec/ipsec.conf.tmpl b/data/templates/ipsec/ipsec.conf.tmpl
deleted file mode 100644
index 0f7131dff..000000000
--- a/data/templates/ipsec/ipsec.conf.tmpl
+++ /dev/null
@@ -1,18 +0,0 @@
-# Created by VyOS - manual changes will be overwritten
-
-config setup
-{% set charondebug = '' %}
-{% if log.subsystem is vyos_defined %}
-{% set subsystem = log.subsystem %}
-{% if 'any' in log.subsystem %}
-{% set subsystem = ['dmn', 'mgr', 'ike', 'chd','job', 'cfg', 'knl', 'net', 'asn',
- 'enc', 'lib', 'esp', 'tls', 'tnc', 'imc', 'imv', 'pts'] %}
-{% endif %}
-{% set charondebug = subsystem | join (' ' ~ log.level ~ ', ') ~ ' ' ~ log.level %}
-{% endif %}
- charondebug = "{{ charondebug }}"
- uniqueids = {{ "no" if disable_uniqreqids is vyos_defined else "yes" }}
-
-{% if include_ipsec_conf is vyos_defined %}
-include {{ include_ipsec_conf }}
-{% endif %}
diff --git a/data/templates/ipsec/ipsec.secrets.tmpl b/data/templates/ipsec/ipsec.secrets.j2
index 865c1ab17..a87ac9bc7 100644
--- a/data/templates/ipsec/ipsec.secrets.tmpl
+++ b/data/templates/ipsec/ipsec.secrets.j2
@@ -1,5 +1,5 @@
# Created by VyOS - manual changes will be overwritten
-{% if include_ipsec_secrets is vyos_defined %}
+{% if include_ipsec_secrets is vyos_defined %}
include {{ include_ipsec_secrets }}
-{% endif %}
+{% endif %}
diff --git a/data/templates/ipsec/swanctl.conf.j2 b/data/templates/ipsec/swanctl.conf.j2
new file mode 100644
index 000000000..bf6b8259c
--- /dev/null
+++ b/data/templates/ipsec/swanctl.conf.j2
@@ -0,0 +1,131 @@
+### Autogenerated by vpn_ipsec.py ###
+{% import 'ipsec/swanctl/l2tp.j2' as l2tp_tmpl %}
+{% import 'ipsec/swanctl/profile.j2' as profile_tmpl %}
+{% import 'ipsec/swanctl/peer.j2' as peer_tmpl %}
+{% import 'ipsec/swanctl/remote_access.j2' as remote_access_tmpl %}
+
+connections {
+{% if profile is vyos_defined %}
+{% for name, profile_conf in profile.items() if profile_conf.disable is not vyos_defined and profile_conf.bind.tunnel is vyos_defined %}
+{{ profile_tmpl.conn(name, profile_conf, ike_group, esp_group) }}
+{% endfor %}
+{% endif %}
+{% if site_to_site.peer is vyos_defined %}
+{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not vyos_defined %}
+{{ peer_tmpl.conn(peer, peer_conf, ike_group, esp_group) }}
+{% endfor %}
+{% endif %}
+{% if remote_access.connection is vyos_defined %}
+{% for rw, rw_conf in remote_access.connection.items() if rw_conf.disable is not vyos_defined %}
+{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }}
+{% endfor %}
+{% endif %}
+{% if l2tp %}
+{{ l2tp_tmpl.conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) }}
+{% endif %}
+}
+
+pools {
+{% if remote_access.pool is vyos_defined %}
+{% for pool, pool_config in remote_access.pool.items() %}
+ {{ pool }} {
+{% if pool_config.prefix is vyos_defined %}
+ addrs = {{ pool_config.prefix }}
+{% endif %}
+{% if pool_config.name_server is vyos_defined %}
+ dns = {{ pool_config.name_server | join(',') }}
+{% endif %}
+{% if pool_config.exclude is vyos_defined %}
+ split_exclude = {{ pool_config.exclude | join(',') }}
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+}
+
+secrets {
+{% if profile is vyos_defined %}
+{% for name, profile_conf in profile.items() if profile_conf.disable is not vyos_defined and profile_conf.bind.tunnel is vyos_defined %}
+{% if profile_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
+{% for interface in profile_conf.bind.tunnel %}
+ ike-dmvpn-{{ interface }} {
+ secret = {{ profile_conf.authentication.pre_shared_secret }}
+ }
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if site_to_site.peer is vyos_defined %}
+{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not vyos_defined %}
+{% set peer_name = peer.replace("@", "") | dot_colon_to_dash %}
+{% if peer_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
+ ike_{{ peer_name }} {
+{% if peer_conf.local_address is vyos_defined %}
+ id-local = {{ peer_conf.local_address }} # dhcp:{{ peer_conf.dhcp_interface if 'dhcp_interface' in peer_conf else 'no' }}
+{% endif %}
+ id-remote = {{ peer }}
+{% if peer_conf.authentication.id is vyos_defined %}
+ id-localid = {{ peer_conf.authentication.id }}
+{% endif %}
+{% if peer_conf.authentication.remote_id is vyos_defined %}
+ id-remoteid = {{ peer_conf.authentication.remote_id }}
+{% endif %}
+ secret = "{{ peer_conf.authentication.pre_shared_secret }}"
+ }
+{% elif peer_conf.authentication.mode is vyos_defined('x509') %}
+ private_{{ peer_name }} {
+ file = {{ peer_conf.authentication.x509.certificate }}.pem
+{% if peer_conf.authentication.x509.passphrase is vyos_defined %}
+ secret = "{{ peer_conf.authentication.x509.passphrase }}"
+{% endif %}
+ }
+{% elif peer_conf.authentication.mode is vyos_defined('rsa') %}
+ rsa_{{ peer_name }}_local {
+ file = {{ peer_conf.authentication.rsa.local_key }}.pem
+{% if peer_conf.authentication.rsa.passphrase is vyos_defined %}
+ secret = "{{ peer_conf.authentication.rsa.passphrase }}"
+{% endif %}
+ }
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if remote_access.connection is vyos_defined %}
+{% for ra, ra_conf in remote_access.connection.items() if ra_conf.disable is not vyos_defined %}
+{% if ra_conf.authentication.server_mode is vyos_defined('pre-shared-secret') %}
+ ike_{{ ra }} {
+{% if ra_conf.authentication.id is vyos_defined %}
+ id = "{{ ra_conf.authentication.id }}"
+{% elif ra_conf.local_address is vyos_defined %}
+ id = "{{ ra_conf.local_address }}"
+{% endif %}
+ secret = "{{ ra_conf.authentication.pre_shared_secret }}"
+ }
+{% endif %}
+{% if ra_conf.authentication.client_mode is vyos_defined('eap-mschapv2') and ra_conf.authentication.local_users.username is vyos_defined %}
+{% for user, user_conf in ra_conf.authentication.local_users.username.items() if user_conf.disable is not vyos_defined %}
+ eap-{{ ra }}-{{ user }} {
+ secret = "{{ user_conf.password }}"
+ id-{{ ra }}-{{ user }} = "{{ user }}"
+ }
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if l2tp %}
+{% if l2tp.authentication.mode is vyos_defined('pre-shared-secret') %}
+ ike_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ secret = "{{ l2tp.authentication.pre_shared_secret }}"
+ }
+{% elif l2tp.authentication.mode is vyos_defined('x509') %}
+ private_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ file = {{ l2tp.authentication.x509.certificate }}.pem
+{% if l2tp.authentication.x509.passphrase is vyos_defined %}
+ secret = "{{ l2tp.authentication.x509.passphrase }}"
+{% endif %}
+ }
+{% endif %}
+{% endif %}
+}
+
diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl
deleted file mode 100644
index 6ba93dd1f..000000000
--- a/data/templates/ipsec/swanctl.conf.tmpl
+++ /dev/null
@@ -1,131 +0,0 @@
-### Autogenerated by vpn_ipsec.py ###
-{% import 'ipsec/swanctl/l2tp.tmpl' as l2tp_tmpl %}
-{% import 'ipsec/swanctl/profile.tmpl' as profile_tmpl %}
-{% import 'ipsec/swanctl/peer.tmpl' as peer_tmpl %}
-{% import 'ipsec/swanctl/remote_access.tmpl' as remote_access_tmpl %}
-
-connections {
-{% if profile is vyos_defined %}
-{% for name, profile_conf in profile.items() if profile_conf.disable is not vyos_defined and profile_conf.bind.tunnel is vyos_defined %}
-{{ profile_tmpl.conn(name, profile_conf, ike_group, esp_group) }}
-{% endfor %}
-{% endif %}
-{% if site_to_site.peer is vyos_defined %}
-{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not vyos_defined %}
-{{ peer_tmpl.conn(peer, peer_conf, ike_group, esp_group) }}
-{% endfor %}
-{% endif %}
-{% if remote_access.connection is vyos_defined %}
-{% for rw, rw_conf in remote_access.connection.items() if rw_conf.disable is not vyos_defined %}
-{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }}
-{% endfor %}
-{% endif %}
-{% if l2tp %}
-{{ l2tp_tmpl.conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) }}
-{% endif %}
-}
-
-pools {
-{% if remote_access.pool is vyos_defined %}
-{% for pool, pool_config in remote_access.pool.items() %}
- {{ pool }} {
-{% if pool_config.prefix is vyos_defined %}
- addrs = {{ pool_config.prefix }}
-{% endif %}
-{% if pool_config.name_server is vyos_defined %}
- dns = {{ pool_config.name_server | join(',') }}
-{% endif %}
-{% if pool_config.exclude is vyos_defined %}
- split_exclude = {{ pool_config.exclude | join(',') }}
-{% endif %}
- }
-{% endfor %}
-{% endif %}
-}
-
-secrets {
-{% if profile is vyos_defined %}
-{% for name, profile_conf in profile.items() if profile_conf.disable is not vyos_defined and profile_conf.bind.tunnel is vyos_defined %}
-{% if profile_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
-{% for interface in profile_conf.bind.tunnel %}
- ike-dmvpn-{{ interface }} {
- secret = {{ profile_conf.authentication.pre_shared_secret }}
- }
-{% endfor %}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if site_to_site.peer is vyos_defined %}
-{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not vyos_defined %}
-{% set peer_name = peer.replace("@", "") | dot_colon_to_dash %}
-{% if peer_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
- ike_{{ peer_name }} {
-{% if peer_conf.local_address is vyos_defined %}
- id-local = {{ peer_conf.local_address }} # dhcp:{{ peer_conf.dhcp_interface if 'dhcp_interface' in peer_conf else 'no' }}
-{% endif %}
- id-remote = {{ peer }}
-{% if peer_conf.authentication.id is vyos_defined %}
- id-localid = {{ peer_conf.authentication.id }}
-{% endif %}
-{% if peer_conf.authentication.remote_id is vyos_defined %}
- id-remoteid = {{ peer_conf.authentication.remote_id }}
-{% endif %}
- secret = "{{ peer_conf.authentication.pre_shared_secret }}"
- }
-{% elif peer_conf.authentication.mode is vyos_defined('x509') %}
- private_{{ peer_name }} {
- file = {{ peer_conf.authentication.x509.certificate }}.pem
-{% if peer_conf.authentication.x509.passphrase is vyos_defined %}
- secret = "{{ peer_conf.authentication.x509.passphrase }}"
-{% endif %}
- }
-{% elif peer_conf.authentication.mode is vyos_defined('rsa') %}
- rsa_{{ peer_name }}_local {
- file = {{ peer_conf.authentication.rsa.local_key }}.pem
-{% if peer_conf.authentication.rsa.passphrase is vyos_defined %}
- secret = "{{ peer_conf.authentication.rsa.passphrase }}"
-{% endif %}
- }
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if remote_access.connection is vyos_defined %}
-{% for ra, ra_conf in remote_access.connection.items() if ra_conf.disable is not vyos_defined %}
-{% if ra_conf.authentication.server_mode is vyos_defined('pre-shared-secret') %}
- ike_{{ ra }} {
-{% if ra_conf.authentication.id is vyos_defined %}
- id = "{{ ra_conf.authentication.id }}"
-{% elif ra_conf.local_address is vyos_defined %}
- id = "{{ ra_conf.local_address }}"
-{% endif %}
- secret = "{{ ra_conf.authentication.pre_shared_secret }}"
- }
-{% endif %}
-{% if ra_conf.authentication.client_mode is vyos_defined('eap-mschapv2') and ra_conf.authentication.local_users.username is vyos_defined %}
-{% for user, user_conf in ra_conf.authentication.local_users.username.items() if user_conf.disable is not vyos_defined %}
- eap-{{ ra }}-{{ user }} {
- secret = "{{ user_conf.password }}"
- id-{{ ra }}-{{ user }} = "{{ user }}"
- }
-{% endfor %}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if l2tp %}
-{% if l2tp.authentication.mode is vyos_defined('pre-shared-secret') %}
- ike_l2tp_remote_access {
- id = "{{ l2tp_outside_address }}"
- secret = "{{ l2tp.authentication.pre_shared_secret }}"
- }
-{% elif l2tp.authentication.mode is vyos_defined('x509') %}
- private_l2tp_remote_access {
- id = "{{ l2tp_outside_address }}"
- file = {{ l2tp.authentication.x509.certificate }}.pem
-{% if l2tp.authentication.x509.passphrase is vyos_defined %}
- secret = "{{ l2tp.authentication.x509.passphrase }}"
-{% endif %}
- }
-{% endif %}
-{% endif %}
-}
-
diff --git a/data/templates/ipsec/swanctl/l2tp.tmpl b/data/templates/ipsec/swanctl/l2tp.j2
index c0e81e0aa..7e63865cc 100644
--- a/data/templates/ipsec/swanctl/l2tp.tmpl
+++ b/data/templates/ipsec/swanctl/l2tp.j2
@@ -1,6 +1,6 @@
{% macro conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) %}
-{% set l2tp_ike = ike_group[l2tp.ike_group] if l2tp.ike_group is vyos_defined else None %}
-{% set l2tp_esp = esp_group[l2tp.esp_group] if l2tp.esp_group is vyos_defined else None %}
+{% set l2tp_ike = ike_group[l2tp.ike_group] if l2tp.ike_group is vyos_defined else None %}
+{% set l2tp_esp = esp_group[l2tp.esp_group] if l2tp.esp_group is vyos_defined else None %}
l2tp_remote_access {
proposals = {{ l2tp_ike | get_esp_ike_cipher | join(',') if l2tp_ike else l2tp_ike_default }}
local_addrs = {{ l2tp_outside_address }}
@@ -10,9 +10,9 @@
reauth_time = 0
local {
auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
-{% if l2tp.authentication.mode == 'x509' %}
+{% if l2tp.authentication.mode == 'x509' %}
certs = {{ l2tp.authentication.x509.certificate }}.pem
-{% endif %}
+{% endif %}
}
remote {
auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
diff --git a/data/templates/ipsec/swanctl/peer.tmpl b/data/templates/ipsec/swanctl/peer.j2
index 61af85ed4..90d2c774f 100644
--- a/data/templates/ipsec/swanctl/peer.tmpl
+++ b/data/templates/ipsec/swanctl/peer.j2
@@ -1,78 +1,78 @@
{% macro conn(peer, peer_conf, ike_group, esp_group) %}
-{% set name = peer.replace("@", "") | dot_colon_to_dash %}
-{# peer needs to reference the global IKE configuration for certain values #}
-{% set ike = ike_group[peer_conf.ike_group] %}
+{% set name = peer.replace("@", "") | dot_colon_to_dash %}
+{# peer needs to reference the global IKE configuration for certain values #}
+{% set ike = ike_group[peer_conf.ike_group] %}
peer_{{ name }} {
proposals = {{ ike | get_esp_ike_cipher | join(',') }}
version = {{ ike.key_exchange[4:] if ike.key_exchange is vyos_defined else "0" }}
-{% if peer_conf.virtual_address is vyos_defined %}
+{% if peer_conf.virtual_address is vyos_defined %}
vips = {{ peer_conf.virtual_address | join(', ') }}
-{% endif %}
+{% endif %}
local_addrs = {{ peer_conf.local_address if peer_conf.local_address != 'any' else '0.0.0.0/0' }} # dhcp:{{ peer_conf.dhcp_interface if 'dhcp_interface' in peer_conf else 'no' }}
remote_addrs = {{ peer if peer not in ['any', '0.0.0.0'] and peer[0:1] != '@' else '0.0.0.0/0' }}
-{% if peer_conf.authentication.mode is vyos_defined('x509') %}
+{% if peer_conf.authentication.mode is vyos_defined('x509') %}
send_cert = always
-{% endif %}
-{% if ike.dead_peer_detection is vyos_defined %}
+{% endif %}
+{% if ike.dead_peer_detection is vyos_defined %}
dpd_timeout = {{ ike.dead_peer_detection.timeout }}
dpd_delay = {{ ike.dead_peer_detection.interval }}
-{% endif %}
-{% if ike.key_exchange is vyos_defined('ikev1') and ike.mode is vyos_defined('aggressive') %}
+{% endif %}
+{% if ike.key_exchange is vyos_defined('ikev1') and ike.mode is vyos_defined('aggressive') %}
aggressive = yes
-{% endif %}
+{% endif %}
rekey_time = {{ ike.lifetime }}s
mobike = {{ "yes" if ike.mobike is not defined or ike.mobike == "enable" else "no" }}
-{% if peer[0:1] == '@' %}
+{% if peer[0:1] == '@' %}
keyingtries = 0
reauth_time = 0
-{% elif peer_conf.connection_type is not vyos_defined or peer_conf.connection_type is vyos_defined('initiate') %}
+{% elif peer_conf.connection_type is not vyos_defined or peer_conf.connection_type is vyos_defined('initiate') %}
keyingtries = 0
-{% elif peer_conf.connection_type is vyos_defined('respond') %}
+{% elif peer_conf.connection_type is vyos_defined('respond') %}
keyingtries = 1
-{% endif %}
-{% if peer_conf.force_encapsulation is vyos_defined('enable') %}
+{% endif %}
+{% if peer_conf.force_encapsulation is vyos_defined('enable') %}
encap = yes
-{% endif %}
+{% endif %}
local {
-{% if peer_conf.authentication.id is vyos_defined %}
+{% if peer_conf.authentication.id is vyos_defined %}
id = "{{ peer_conf.authentication.id }}"
-{% endif %}
+{% endif %}
auth = {{ 'psk' if peer_conf.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
-{% if peer_conf.authentication.mode == 'x509' %}
+{% if peer_conf.authentication.mode == 'x509' %}
certs = {{ peer_conf.authentication.x509.certificate }}.pem
-{% elif peer_conf.authentication.mode == 'rsa' %}
+{% elif peer_conf.authentication.mode == 'rsa' %}
pubkeys = {{ peer_conf.authentication.rsa.local_key }}.pem
-{% endif %}
+{% endif %}
}
remote {
-{% if peer_conf.authentication.remote_id is vyos_defined %}
+{% if peer_conf.authentication.remote_id is vyos_defined %}
id = "{{ peer_conf.authentication.remote_id }}"
-{% else %}
+{% else %}
id = "{{ peer }}"
-{% endif %}
+{% endif %}
auth = {{ 'psk' if peer_conf.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
-{% if peer_conf.authentication.mode == 'rsa' %}
+{% if peer_conf.authentication.mode == 'rsa' %}
pubkeys = {{ peer_conf.authentication.rsa.remote_key }}.pem
-{% endif %}
+{% endif %}
}
children {
-{% if peer_conf.vti.bind is vyos_defined and peer_conf.tunnel is not vyos_defined %}
+{% if peer_conf.vti.bind is vyos_defined and peer_conf.tunnel is not vyos_defined %}
{% set vti_esp = esp_group[ peer_conf.vti.esp_group ] if peer_conf.vti.esp_group is vyos_defined else esp_group[ peer_conf.default_esp_group ] %}
peer_{{ name }}_vti {
esp_proposals = {{ vti_esp | get_esp_ike_cipher(ike) | join(',') }}
-{% if vti_esp.life_bytes is vyos_defined %}
+{% if vti_esp.life_bytes is vyos_defined %}
life_bytes = {{ vti_esp.life_bytes }}
-{% endif %}
-{% if vti_esp.life_packets is vyos_defined %}
+{% endif %}
+{% if vti_esp.life_packets is vyos_defined %}
life_packets = {{ vti_esp.life_packets }}
-{% endif %}
+{% endif %}
life_time = {{ vti_esp.lifetime }}s
local_ts = 0.0.0.0/0,::/0
remote_ts = 0.0.0.0/0,::/0
updown = "/etc/ipsec.d/vti-up-down {{ peer_conf.vti.bind }}"
- {# The key defaults to 0 and will match any policies which similarly do not have a lookup key configuration. #}
- {# Thus we simply shift the key by one to also support a vti0 interface #}
-{% set if_id = peer_conf.vti.bind | replace('vti', '') | int +1 %}
+{# The key defaults to 0 and will match any policies which similarly do not have a lookup key configuration. #}
+{# Thus we simply shift the key by one to also support a vti0 interface #}
+{% set if_id = peer_conf.vti.bind | replace('vti', '') | int + 1 %}
if_id_in = {{ if_id }}
if_id_out = {{ if_id }}
ipcomp = {{ 'yes' if vti_esp.compression is vyos_defined('enable') else 'no' }}
@@ -87,80 +87,80 @@
start_action = none
{% endif %}
{% if ike.dead_peer_detection is vyos_defined %}
-{% set dpd_translate = {'clear': 'clear', 'hold': 'trap', 'restart': 'restart'} %}
+{% set dpd_translate = {'clear': 'clear', 'hold': 'trap', 'restart': 'restart'} %}
dpd_action = {{ dpd_translate[ike.dead_peer_detection.action] }}
{% endif %}
close_action = {{ {'none': 'none', 'hold': 'trap', 'restart': 'start'}[ike.close_action] }}
}
-{% elif peer_conf.tunnel is vyos_defined %}
+{% elif peer_conf.tunnel is vyos_defined %}
{% for tunnel_id, tunnel_conf in peer_conf.tunnel.items() if tunnel_conf.disable is not defined %}
-{% set tunnel_esp_name = tunnel_conf.esp_group if tunnel_conf.esp_group is vyos_defined else peer_conf.default_esp_group %}
-{% set tunnel_esp = esp_group[tunnel_esp_name] %}
-{% set proto = tunnel_conf.protocol if tunnel_conf.protocol is vyos_defined else '' %}
-{% set local_port = tunnel_conf.local.port if tunnel_conf.local.port is vyos_defined else '' %}
-{% set local_suffix = '[{0}/{1}]'.format(proto, local_port) if proto or local_port else '' %}
-{% set remote_port = tunnel_conf.remote.port if tunnel_conf.remote.port is vyos_defined else '' %}
-{% set remote_suffix = '[{0}/{1}]'.format(proto, remote_port) if proto or remote_port else '' %}
+{% set tunnel_esp_name = tunnel_conf.esp_group if tunnel_conf.esp_group is vyos_defined else peer_conf.default_esp_group %}
+{% set tunnel_esp = esp_group[tunnel_esp_name] %}
+{% set proto = tunnel_conf.protocol if tunnel_conf.protocol is vyos_defined else '' %}
+{% set local_port = tunnel_conf.local.port if tunnel_conf.local.port is vyos_defined else '' %}
+{% set local_suffix = '[{0}/{1}]'.format(proto, local_port) if proto or local_port else '' %}
+{% set remote_port = tunnel_conf.remote.port if tunnel_conf.remote.port is vyos_defined else '' %}
+{% set remote_suffix = '[{0}/{1}]'.format(proto, remote_port) if proto or remote_port else '' %}
peer_{{ name }}_tunnel_{{ tunnel_id }} {
esp_proposals = {{ tunnel_esp | get_esp_ike_cipher(ike) | join(',') }}
-{% if tunnel_esp.life_bytes is vyos_defined %}
+{% if tunnel_esp.life_bytes is vyos_defined %}
life_bytes = {{ tunnel_esp.life_bytes }}
-{% endif %}
-{% if tunnel_esp.life_packets is vyos_defined %}
+{% endif %}
+{% if tunnel_esp.life_packets is vyos_defined %}
life_packets = {{ tunnel_esp.life_packets }}
-{% endif %}
+{% endif %}
life_time = {{ tunnel_esp.lifetime }}s
-{% if tunnel_esp.mode is not defined or tunnel_esp.mode == 'tunnel' %}
-{% if tunnel_conf.local.prefix is vyos_defined %}
-{% set local_prefix = tunnel_conf.local.prefix if 'any' not in tunnel_conf.local.prefix else ['0.0.0.0/0', '::/0'] %}
+{% if tunnel_esp.mode is not defined or tunnel_esp.mode == 'tunnel' %}
+{% if tunnel_conf.local.prefix is vyos_defined %}
+{% set local_prefix = tunnel_conf.local.prefix if 'any' not in tunnel_conf.local.prefix else ['0.0.0.0/0', '::/0'] %}
local_ts = {{ local_prefix | join(local_suffix + ",") }}{{ local_suffix }}
-{% endif %}
-{% if tunnel_conf.remote.prefix is vyos_defined %}
-{% set remote_prefix = tunnel_conf.remote.prefix if 'any' not in tunnel_conf.remote.prefix else ['0.0.0.0/0', '::/0'] %}
+{% endif %}
+{% if tunnel_conf.remote.prefix is vyos_defined %}
+{% set remote_prefix = tunnel_conf.remote.prefix if 'any' not in tunnel_conf.remote.prefix else ['0.0.0.0/0', '::/0'] %}
remote_ts = {{ remote_prefix | join(remote_suffix + ",") }}{{ remote_suffix }}
-{% endif %}
-{% if tunnel_conf.priority is vyos_defined %}
+{% endif %}
+{% if tunnel_conf.priority is vyos_defined %}
priority = {{ tunnel_conf.priority }}
-{% endif %}
-{% elif tunnel_esp.mode == 'transport' %}
+{% endif %}
+{% elif tunnel_esp.mode == 'transport' %}
local_ts = {{ peer_conf.local_address }}{{ local_suffix }}
remote_ts = {{ peer }}{{ remote_suffix }}
-{% endif %}
+{% endif %}
ipcomp = {{ 'yes' if tunnel_esp.compression is vyos_defined('enable') else 'no' }}
mode = {{ tunnel_esp.mode }}
-{% if peer[0:1] == '@' %}
+{% if peer[0:1] == '@' %}
start_action = none
-{% elif peer_conf.connection_type is not vyos_defined or peer_conf.connection_type is vyos_defined('initiate') %}
+{% elif peer_conf.connection_type is not vyos_defined or peer_conf.connection_type is vyos_defined('initiate') %}
start_action = start
-{% elif peer_conf.connection_type is vyos_defined('respond') %}
+{% elif peer_conf.connection_type is vyos_defined('respond') %}
start_action = trap
-{% elif peer_conf.connection_type is vyos_defined('none') %}
+{% elif peer_conf.connection_type is vyos_defined('none') %}
start_action = none
-{% endif %}
-{% if ike.dead_peer_detection is vyos_defined %}
-{% set dpd_translate = {'clear': 'clear', 'hold': 'trap', 'restart': 'restart'} %}
+{% endif %}
+{% if ike.dead_peer_detection is vyos_defined %}
+{% set dpd_translate = {'clear': 'clear', 'hold': 'trap', 'restart': 'restart'} %}
dpd_action = {{ dpd_translate[ike.dead_peer_detection.action] }}
-{% endif %}
+{% endif %}
close_action = {{ {'none': 'none', 'hold': 'trap', 'restart': 'start'}[ike.close_action] }}
-{% if peer_conf.vti.bind is vyos_defined %}
+{% if peer_conf.vti.bind is vyos_defined %}
+{# The key defaults to 0 and will match any policies which similarly do not have a lookup key configuration. #}
+{# Thus we simply shift the key by one to also support a vti0 interface #}
+{% set if_id = peer_conf.vti.bind | replace('vti', '') | int + 1 %}
updown = "/etc/ipsec.d/vti-up-down {{ peer_conf.vti.bind }}"
- {# The key defaults to 0 and will match any policies which similarly do not have a lookup key configuration. #}
- {# Thus we simply shift the key by one to also support a vti0 interface #}
-{% set if_id = peer_conf.vti.bind | replace('vti', '') | int +1 %}
if_id_in = {{ if_id }}
if_id_out = {{ if_id }}
-{% endif %}
+{% endif %}
}
-{% if tunnel_conf.passthrough is vyos_defined %}
+{% if tunnel_conf.passthrough is vyos_defined %}
peer_{{ name }}_tunnel_{{ tunnel_id }}_passthrough {
local_ts = {{ tunnel_conf.passthrough | join(",") }}
remote_ts = {{ tunnel_conf.passthrough | join(",") }}
start_action = trap
mode = pass
}
-{% endif %}
+{% endif %}
{% endfor %}
-{% endif %}
+{% endif %}
}
}
{% endmacro %}
diff --git a/data/templates/ipsec/swanctl/profile.tmpl b/data/templates/ipsec/swanctl/profile.j2
index 0f1c2fda2..d4f417378 100644
--- a/data/templates/ipsec/swanctl/profile.tmpl
+++ b/data/templates/ipsec/swanctl/profile.j2
@@ -1,39 +1,39 @@
{% macro conn(name, profile_conf, ike_group, esp_group) %}
-{# peer needs to reference the global IKE configuration for certain values #}
-{% set ike = ike_group[profile_conf.ike_group] %}
-{% set esp = esp_group[profile_conf.esp_group] %}
-{% if profile_conf.bind.tunnel is vyos_defined %}
+{# peer needs to reference the global IKE configuration for certain values #}
+{% set ike = ike_group[profile_conf.ike_group] %}
+{% set esp = esp_group[profile_conf.esp_group] %}
+{% if profile_conf.bind.tunnel is vyos_defined %}
{% for interface in profile_conf.bind.tunnel %}
dmvpn-{{ name }}-{{ interface }} {
proposals = {{ ike_group[profile_conf.ike_group] | get_esp_ike_cipher | join(',') }}
version = {{ ike.key_exchange[4:] if ike.key_exchange is vyos_defined else "0" }}
rekey_time = {{ ike.lifetime }}s
keyingtries = 0
-{% if profile_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
+{% if profile_conf.authentication.mode is vyos_defined('pre-shared-secret') %}
local {
auth = psk
}
remote {
auth = psk
}
-{% endif %}
+{% endif %}
children {
dmvpn {
- esp_proposals = {{ esp | get_esp_ike_cipher(ike) | join(',') }}
+ esp_proposals = {{ esp | get_esp_ike_cipher(ike) | join(',') }}
rekey_time = {{ esp.lifetime }}s
rand_time = 540s
local_ts = dynamic[gre]
remote_ts = dynamic[gre]
mode = {{ esp.mode }}
-{% if ike.dead_peer_detection.action is vyos_defined %}
+{% if ike.dead_peer_detection.action is vyos_defined %}
dpd_action = {{ ike.dead_peer_detection.action }}
-{% endif %}
-{% if esp.compression is vyos_defined('enable') %}
+{% endif %}
+{% if esp.compression is vyos_defined('enable') %}
ipcomp = yes
-{% endif %}
+{% endif %}
}
}
}
{% endfor %}
-{% endif %}
+{% endif %}
{% endmacro %}
diff --git a/data/templates/ipsec/swanctl/remote_access.tmpl b/data/templates/ipsec/swanctl/remote_access.j2
index 059984139..d2760ec1f 100644
--- a/data/templates/ipsec/swanctl/remote_access.tmpl
+++ b/data/templates/ipsec/swanctl/remote_access.j2
@@ -1,7 +1,7 @@
{% macro conn(name, rw_conf, ike_group, esp_group) %}
-{# peer needs to reference the global IKE configuration for certain values #}
-{% set ike = ike_group[rw_conf.ike_group] %}
-{% set esp = esp_group[rw_conf.esp_group] %}
+{# peer needs to reference the global IKE configuration for certain values #}
+{% set ike = ike_group[rw_conf.ike_group] %}
+{% set esp = esp_group[rw_conf.esp_group] %}
ra-{{ name }} {
remote_addrs = %any
local_addrs = {{ rw_conf.local_address if rw_conf.local_address is vyos_defined else '%any' }}
@@ -10,28 +10,29 @@
send_certreq = no
rekey_time = {{ ike.lifetime }}s
keyingtries = 0
-{% if rw_conf.unique is vyos_defined %}
+{% if rw_conf.unique is vyos_defined %}
unique = {{ rw_conf.unique }}
-{% endif %}
-{% if rw_conf.pool is vyos_defined %}
+{% endif %}
+{% if rw_conf.pool is vyos_defined %}
pools = {{ rw_conf.pool | join(',') }}
-{% endif %}
+{% endif %}
local {
-{% if rw_conf.authentication.id is vyos_defined and rw_conf.authentication.use_x509_id is not vyos_defined %}
- id = '{{ rw_conf.authentication.id }}'
-{% endif %}
-{% if rw_conf.authentication.server_mode == 'x509' %}
+{% if rw_conf.authentication.id is vyos_defined and rw_conf.authentication.use_x509_id is not vyos_defined %}
+{# please use " quotes - else Apple iOS goes crazy #}
+ id = "{{ rw_conf.authentication.id }}"
+{% endif %}
+{% if rw_conf.authentication.server_mode == 'x509' %}
auth = pubkey
certs = {{ rw_conf.authentication.x509.certificate }}.pem
-{% elif rw_conf.authentication.server_mode == 'pre-shared-secret' %}
+{% elif rw_conf.authentication.server_mode == 'pre-shared-secret' %}
auth = psk
-{% endif %}
+{% endif %}
}
remote {
auth = {{ rw_conf.authentication.client_mode }}
-{% if rw_conf.authentication.client_mode.startswith("eap") %}
+{% if rw_conf.authentication.client_mode.startswith("eap") %}
eap_id = %any
-{% endif %}
+{% endif %}
}
children {
ikev2-vpn {
@@ -40,9 +41,9 @@
rand_time = 540s
dpd_action = clear
inactivity = {{ rw_conf.timeout }}
-{% set local_prefix = rw_conf.local.prefix if rw_conf.local.prefix is vyos_defined else ['0.0.0.0/0', '::/0'] %}
-{% set local_port = rw_conf.local.port if rw_conf.local.port is vyos_defined else '' %}
-{% set local_suffix = '[%any/{1}]'.format(local_port) if local_port else '' %}
+{% set local_prefix = rw_conf.local.prefix if rw_conf.local.prefix is vyos_defined else ['0.0.0.0/0', '::/0'] %}
+{% set local_port = rw_conf.local.port if rw_conf.local.port is vyos_defined else '' %}
+{% set local_suffix = '[%any/{1}]'.format(local_port) if local_port else '' %}
local_ts = {{ local_prefix | join(local_suffix + ",") }}{{ local_suffix }}
}
}
diff --git a/data/templates/ipsec/windows_profile.tmpl b/data/templates/ipsec/windows_profile.j2
index 8c26944be..8c26944be 100644
--- a/data/templates/ipsec/windows_profile.tmpl
+++ b/data/templates/ipsec/windows_profile.j2
diff --git a/data/templates/lcd/LCDd.conf.tmpl b/data/templates/lcd/LCDd.conf.j2
index 2c8c6602d..3631add1d 100644
--- a/data/templates/lcd/LCDd.conf.tmpl
+++ b/data/templates/lcd/LCDd.conf.j2
@@ -49,13 +49,13 @@ DriverPath=/usr/lib/x86_64-linux-gnu/lcdproc/
# text, tyan, ula200, vlsys_m428, xosd, yard2LCD
{% if model is vyos_defined %}
-{% if model.startswith('cfa-') %}
+{% if model.startswith('cfa-') %}
Driver=CFontzPacket
-{% elif model == 'sdec' %}
+{% elif model == 'sdec' %}
Driver=sdeclcd
-{% elif model == 'hd44780' %}
+{% elif model == 'hd44780' %}
Driver=hd44780
-{% endif %}
+{% endif %}
{% endif %}
# Tells the driver to bind to the given interface. [default: 127.0.0.1]
@@ -116,7 +116,7 @@ Heartbeat=off
TitleSpeed=10
{% if model is vyos_defined %}
-{% if model.startswith('cfa-') %}
+{% if model.startswith('cfa-') %}
## CrystalFontz packet driver (for CFA533, CFA631, CFA633 & CFA635) ##
[CFontzPacket]
Model={{ model.split('-')[1] }}
@@ -126,14 +126,14 @@ Brightness=500
OffBrightness=50
Reboot=yes
USB=yes
-{% elif model == 'sdec' %}
+{% elif model == 'sdec' %}
## SDEC driver for Lanner, Watchguard, Sophos sppliances ##
[sdeclcd]
# No options
-{% elif model == 'hd44780' %}
+{% elif model == 'hd44780' %}
[hd44780]
ConnectionType=ezio
Device={{ device }}
Size=16x2
-{% endif %}
+{% endif %}
{% endif %}
diff --git a/data/templates/lcd/lcdproc.conf.tmpl b/data/templates/lcd/lcdproc.conf.j2
index c79f3cd0d..c79f3cd0d 100644
--- a/data/templates/lcd/lcdproc.conf.tmpl
+++ b/data/templates/lcd/lcdproc.conf.j2
diff --git a/data/templates/lldp/lldpd.j2 b/data/templates/lldp/lldpd.j2
new file mode 100644
index 000000000..3c499197d
--- /dev/null
+++ b/data/templates/lldp/lldpd.j2
@@ -0,0 +1,2 @@
+### Autogenerated by lldp.py ###
+DAEMON_ARGS="-M 4 {{ '-x' if snmp.enable is vyos_defined }} {{ '-c' if legacy_protocols.cdp is vyos_defined }} {{ '-e' if legacy_protocols.edp is vyos_defined }} {{ '-f' if legacy_protocols.fdp is vyos_defined }} {{ '-s' if legacy_protocols.sonmp is vyos_defined }}"
diff --git a/data/templates/lldp/lldpd.tmpl b/data/templates/lldp/lldpd.tmpl
deleted file mode 100644
index 9ab1e4367..000000000
--- a/data/templates/lldp/lldpd.tmpl
+++ /dev/null
@@ -1,2 +0,0 @@
-### Autogenerated by lldp.py ###
-DAEMON_ARGS="-M 4{% if snmp.enable is vyos_defined %} -x{% endif %}{% if legacy_protocols.cdp is vyos_defined %} -c{% endif %}{% if legacy_protocols.edp is vyos_defined %} -e{% endif %}{% if legacy_protocols.fdp is vyos_defined %} -f{% endif %}{% if legacy_protocols.sonmp is vyos_defined %} -s{% endif %}"
diff --git a/data/templates/lldp/vyos.conf.tmpl b/data/templates/lldp/vyos.conf.j2
index c34a851aa..ec84231d8 100644
--- a/data/templates/lldp/vyos.conf.tmpl
+++ b/data/templates/lldp/vyos.conf.j2
@@ -3,21 +3,21 @@
configure system platform VyOS
configure system description "VyOS {{ version }}"
{% if interface is vyos_defined %}
-{% set tmp = [] %}
-{% for iface, iface_options in interface.items() if not iface_options.disable %}
-{% if iface == 'all' %}
-{% set iface = '*' %}
-{% endif %}
-{% set _ = tmp.append(iface) %}
-{% if iface_options.location is vyos_defined %}
-{% if iface_options.location.elin is vyos_defined %}
+{% set tmp = [] %}
+{% for iface, iface_options in interface.items() if not iface_options.disable %}
+{% if iface == 'all' %}
+{% set iface = '*' %}
+{% endif %}
+{% set _ = tmp.append(iface) %}
+{% if iface_options.location is vyos_defined %}
+{% if iface_options.location.elin is vyos_defined %}
configure ports {{ iface }} med location elin "{{ iface_options.location.elin }}"
-{% endif %}
-{% if iface_options.location.coordinate_based is vyos_defined %}
+{% endif %}
+{% if iface_options.location.coordinate_based is vyos_defined %}
configure ports {{ iface }} med location coordinate latitude "{{ iface_options.location.coordinate_based.latitude }}" longitude "{{ iface_options.location.coordinate_based.longitude }}" altitude "{{ iface_options.location.coordinate_based.altitude }}m" datum "{{ iface_options.location.coordinate_based.datum }}"
-{% endif %}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
configure system interface pattern "{{ tmp | join(",") }}"
{% endif %}
{% if management_address is vyos_defined %}
diff --git a/data/templates/login/authorized_keys.tmpl b/data/templates/login/authorized_keys.j2
index 9402c8719..aabca47cf 100644
--- a/data/templates/login/authorized_keys.tmpl
+++ b/data/templates/login/authorized_keys.j2
@@ -1,9 +1,9 @@
### Automatically generated by system-login.py ###
{% if authentication.public_keys is vyos_defined %}
-{% for key, key_options in authentication.public_keys.items() %}
+{% for key, key_options in authentication.public_keys.items() %}
{# The whitespace after options is wisely chosen #}
{{ key_options.options ~ ' ' if key_options.options is vyos_defined }}{{ key_options.type }} {{ key_options.key }} {{ key }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/login/pam_radius_auth.conf.j2 b/data/templates/login/pam_radius_auth.conf.j2
new file mode 100644
index 000000000..1105b60e5
--- /dev/null
+++ b/data/templates/login/pam_radius_auth.conf.j2
@@ -0,0 +1,36 @@
+# Automatically generated by system-login.py
+# RADIUS configuration file
+
+{% if radius is vyos_defined %}
+{# RADIUS IPv6 source address must be specified in [] notation #}
+{% set source_address = namespace() %}
+{% if radius.source_address is vyos_defined %}
+{% for address in radius.source_address %}
+{% if address | is_ipv4 %}
+{% set source_address.ipv4 = address %}
+{% elif address | is_ipv6 %}
+{% set source_address.ipv6 = "[" + address + "]" %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if radius.server is vyos_defined %}
+# server[:port] shared_secret timeout source_ip
+{# .items() returns a tuple of two elements: key and value. 1 relates to the 2nd element i.e. the value and .priority relates to the key from the internal dict #}
+{% for server, options in radius.server.items() | sort(attribute='1.priority') if not options.disabled %}
+{# RADIUS IPv6 servers must be specified in [] notation #}
+{% if server | is_ipv4 %}
+{{ server }}:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv4 if source_address.ipv4 is vyos_defined }}
+{% else %}
+[{{ server }}]:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv6 if source_address.ipv6 is vyos_defined }}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+priv-lvl 15
+mapped_priv_user radius_priv_user
+
+{% if radius.vrf is vyos_defined %}
+vrf-name {{ radius.vrf }}
+{% endif %}
+{% endif %}
+
diff --git a/data/templates/login/pam_radius_auth.conf.tmpl b/data/templates/login/pam_radius_auth.conf.tmpl
deleted file mode 100644
index 4e34ade41..000000000
--- a/data/templates/login/pam_radius_auth.conf.tmpl
+++ /dev/null
@@ -1,36 +0,0 @@
-# Automatically generated by system-login.py
-# RADIUS configuration file
-
-{% if radius is vyos_defined %}
-{# RADIUS IPv6 source address must be specified in [] notation #}
-{% set source_address = namespace() %}
-{% if radius.source_address is vyos_defined %}
-{% for address in radius.source_address %}
-{% if address | is_ipv4 %}
-{% set source_address.ipv4 = address %}
-{% elif address | is_ipv6 %}
-{% set source_address.ipv6 = "[" + address + "]" %}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if radius.server is vyos_defined %}
-# server[:port] shared_secret timeout source_ip
-{# .items() returns a tuple of two elements: key and value. 1 relates to the 2nd element i.e. the value and .priority relates to the key from the internal dict #}
-{% for server, options in radius.server.items() | sort(attribute='1.priority') if not options.disabled %}
-{# RADIUS IPv6 servers must be specified in [] notation #}
-{% if server | is_ipv4 %}
-{{ server }}:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv4 if source_address.ipv4 is vyos_defined }}
-{% else %}
-[{{ server }}]:{{ options.port }} {{ "%-25s" | format(options.key) }} {{ "%-10s" | format(options.timeout) }} {{ source_address.ipv6 if source_address.ipv6 is vyos_defined }}
-{% endif %}
-{% endfor %}
-{% endif %}
-
-priv-lvl 15
-mapped_priv_user radius_priv_user
-
-{% if radius.vrf is vyos_defined %}
-vrf-name {{ radius.vrf }}
-{% endif %}
-{% endif %}
-
diff --git a/data/templates/logs/logrotate/vyos-atop.tmpl b/data/templates/logs/logrotate/vyos-atop.j2
index 2d078f379..2d078f379 100644
--- a/data/templates/logs/logrotate/vyos-atop.tmpl
+++ b/data/templates/logs/logrotate/vyos-atop.j2
diff --git a/data/templates/logs/logrotate/vyos-rsyslog.tmpl b/data/templates/logs/logrotate/vyos-rsyslog.j2
index f2e4d2ab2..f2e4d2ab2 100644
--- a/data/templates/logs/logrotate/vyos-rsyslog.tmpl
+++ b/data/templates/logs/logrotate/vyos-rsyslog.j2
diff --git a/data/templates/mdns-repeater/avahi-daemon.tmpl b/data/templates/mdns-repeater/avahi-daemon.j2
index 65bb5a306..65bb5a306 100644
--- a/data/templates/mdns-repeater/avahi-daemon.tmpl
+++ b/data/templates/mdns-repeater/avahi-daemon.j2
diff --git a/data/templates/monitoring/override.conf.tmpl b/data/templates/monitoring/override.conf.j2
index f8f150791..f8f150791 100644
--- a/data/templates/monitoring/override.conf.tmpl
+++ b/data/templates/monitoring/override.conf.j2
diff --git a/data/templates/monitoring/syslog_telegraf.tmpl b/data/templates/monitoring/syslog_telegraf.j2
index cdcbd92a4..cdcbd92a4 100644
--- a/data/templates/monitoring/syslog_telegraf.tmpl
+++ b/data/templates/monitoring/syslog_telegraf.j2
diff --git a/data/templates/monitoring/systemd_vyos_telegraf_service.tmpl b/data/templates/monitoring/systemd_vyos_telegraf_service.j2
index 234ef5586..234ef5586 100644
--- a/data/templates/monitoring/systemd_vyos_telegraf_service.tmpl
+++ b/data/templates/monitoring/systemd_vyos_telegraf_service.j2
diff --git a/data/templates/monitoring/telegraf.j2 b/data/templates/monitoring/telegraf.j2
new file mode 100644
index 000000000..a732fb5de
--- /dev/null
+++ b/data/templates/monitoring/telegraf.j2
@@ -0,0 +1,122 @@
+# Generated by /usr/libexec/vyos/conf_mode/service_monitoring_telegraf.py
+
+[agent]
+ interval = "15s"
+ round_interval = true
+ metric_batch_size = 1000
+ metric_buffer_limit = 10000
+ collection_jitter = "5s"
+ flush_interval = "15s"
+ flush_jitter = "0s"
+ precision = ""
+ debug = false
+ quiet = false
+ logfile = ""
+ hostname = ""
+ omit_hostname = false
+{% if azure_data_explorer is vyos_defined %}
+### Azure Data Explorer ###
+[[outputs.azure_data_explorer]]
+ ## The URI property of the Azure Data Explorer resource on Azure
+ endpoint_url = "{{ azure_data_explorer.url }}"
+
+ ## The Azure Data Explorer database that the metrics will be ingested into.
+ ## The plugin will NOT generate this database automatically, it's expected that this database already exists before ingestion.
+ database = "{{ azure_data_explorer.database }}"
+ metrics_grouping_type = "{{ azure_data_explorer.group_metrics }}"
+
+ ## Name of the single table to store all the metrics (Only needed if metrics_grouping_type is "SingleTable").
+{% if azure_data_explorer.table is vyos_defined and azure_data_explorer.group_metrics == 'SingleTable' %}
+ table_name = "{{ azure_data_explorer.table }}"
+{% endif %}
+### End Azure Data Explorer ###
+{% endif %}
+{% if influxdb_configured is vyos_defined %}
+### InfluxDB2 ###
+[[outputs.influxdb_v2]]
+ urls = ["{{ url }}:{{ port }}"]
+ insecure_skip_verify = true
+ token = "$INFLUX_TOKEN"
+ organization = "{{ authentication.organization }}"
+ bucket = "{{ bucket }}"
+### End InfluxDB2 ###
+{% endif %}
+{% if prometheus_client is vyos_defined %}
+### Prometheus ###
+[[outputs.prometheus_client]]
+ ## Address to listen on
+ listen = "{{ prometheus_client.listen_address if prometheus_client.listen_address is vyos_defined else '' }}:{{ prometheus_client.port }}"
+ metric_version = {{ prometheus_client.metric_version }}
+{% if prometheus_client.authentication.username is vyos_defined and prometheus_client.authentication.password is vyos_defined %}
+ ## Use HTTP Basic Authentication
+ basic_username = "{{ prometheus_client.authentication.username }}"
+ basic_password = "{{ prometheus_client.authentication.password }}"
+{% endif %}
+{% if prometheus_client.allow_from is vyos_defined %}
+ ip_range = {{ prometheus_client.allow_from }}
+{% endif %}
+### End Prometheus ###
+{% endif %}
+{% if splunk is vyos_defined %}
+### Splunk ###
+[[outputs.http]]
+ ## URL is the address to send metrics to
+ url = "{{ splunk.url }}"
+ ## Timeout for HTTP message
+ # timeout = "5s"
+ ## Use TLS but skip chain & host verification
+{% if splunk.authentication.insecure is vyos_defined %}
+ insecure_skip_verify = true
+{% endif %}
+ ## Data format to output
+ data_format = "splunkmetric"
+ ## Provides time, index, source overrides for the HEC
+ splunkmetric_hec_routing = true
+ ## Additional HTTP headers
+ [outputs.http.headers]
+ # Should be set manually to "application/json" for json data_format
+ Content-Type = "application/json"
+ Authorization = "Splunk {{ splunk.authentication.token }}"
+ X-Splunk-Request-Channel = "{{ splunk.authentication.token }}"
+### End Splunk ###
+{% endif %}
+[[inputs.cpu]]
+ percpu = true
+ totalcpu = true
+ collect_cpu_time = false
+ report_active = false
+[[inputs.disk]]
+ ignore_fs = ["devtmpfs", "devfs"]
+[[inputs.diskio]]
+[[inputs.mem]]
+[[inputs.net]]
+[[inputs.system]]
+[[inputs.netstat]]
+[[inputs.processes]]
+[[inputs.kernel]]
+[[inputs.interrupts]]
+[[inputs.linux_sysctl_fs]]
+[[inputs.systemd_units]]
+[[inputs.conntrack]]
+ files = ["ip_conntrack_count","ip_conntrack_max","nf_conntrack_count","nf_conntrack_max"]
+ dirs = ["/proc/sys/net/ipv4/netfilter","/proc/sys/net/netfilter"]
+[[inputs.ethtool]]
+ interface_include = {{ interfaces_ethernet }}
+[[inputs.ntpq]]
+ dns_lookup = true
+[[inputs.internal]]
+[[inputs.nstat]]
+[[inputs.syslog]]
+ server = "unixgram:///run/telegraf/telegraf_syslog.sock"
+ best_effort = true
+ syslog_standard = "RFC3164"
+{% if influxdb_configured is vyos_defined %}
+[[inputs.exec]]
+ commands = [
+ "{{ custom_scripts_dir }}/show_firewall_input_filter.py",
+ "{{ custom_scripts_dir }}/show_interfaces_input_filter.py",
+ "{{ custom_scripts_dir }}/vyos_services_input_filter.py"
+ ]
+ timeout = "10s"
+ data_format = "influx"
+{% endif %}
diff --git a/data/templates/monitoring/telegraf.tmpl b/data/templates/monitoring/telegraf.tmpl
deleted file mode 100644
index cf33eec4e..000000000
--- a/data/templates/monitoring/telegraf.tmpl
+++ /dev/null
@@ -1,60 +0,0 @@
-# Generated by /usr/libexec/vyos/conf_mode/service_monitoring_telegraf.py
-
-[agent]
- interval = "15s"
- round_interval = true
- metric_batch_size = 1000
- metric_buffer_limit = 10000
- collection_jitter = "5s"
- flush_interval = "15s"
- flush_jitter = "0s"
- precision = ""
- debug = false
- quiet = false
- logfile = ""
- hostname = ""
- omit_hostname = false
-[[outputs.influxdb_v2]]
- urls = ["{{ url }}:{{ port }}"]
- insecure_skip_verify = true
- token = "$INFLUX_TOKEN"
- organization = "{{ authentication.organization }}"
- bucket = "{{ bucket }}"
-[[inputs.cpu]]
- percpu = true
- totalcpu = true
- collect_cpu_time = false
- report_active = false
-[[inputs.disk]]
- ignore_fs = ["devtmpfs", "devfs"]
-[[inputs.diskio]]
-[[inputs.mem]]
-[[inputs.net]]
-[[inputs.system]]
-[[inputs.netstat]]
-[[inputs.processes]]
-[[inputs.kernel]]
-[[inputs.interrupts]]
-[[inputs.linux_sysctl_fs]]
-[[inputs.systemd_units]]
-[[inputs.conntrack]]
- files = ["ip_conntrack_count","ip_conntrack_max","nf_conntrack_count","nf_conntrack_max"]
- dirs = ["/proc/sys/net/ipv4/netfilter","/proc/sys/net/netfilter"]
-[[inputs.ethtool]]
- interface_include = {{ interfaces_ethernet }}
-[[inputs.ntpq]]
- dns_lookup = true
-[[inputs.internal]]
-[[inputs.nstat]]
-[[inputs.syslog]]
- server = "unixgram:///run/telegraf/telegraf_syslog.sock"
- best_effort = true
- syslog_standard = "RFC3164"
-[[inputs.exec]]
- commands = [
- "{{ custom_scripts_dir }}/show_firewall_input_filter.py",
- "{{ custom_scripts_dir }}/show_interfaces_input_filter.py",
- "{{ custom_scripts_dir }}/vyos_services_input_filter.py"
- ]
- timeout = "10s"
- data_format = "influx"
diff --git a/data/templates/ndppd/ndppd.conf.j2 b/data/templates/ndppd/ndppd.conf.j2
new file mode 100644
index 000000000..120fa0a64
--- /dev/null
+++ b/data/templates/ndppd/ndppd.conf.j2
@@ -0,0 +1,44 @@
+########################################################
+#
+# autogenerated by nat66.py
+#
+# The configuration file must define one upstream
+# interface.
+#
+# For some services, such as nat66, because it runs
+# stateless, it needs to rely on NDP Proxy to respond
+# to NDP requests.
+#
+# When using nat66 source rules, NDP Proxy needs
+# to be enabled
+#
+########################################################
+
+{% set global = namespace(ndppd_interfaces = [],ndppd_prefixs = []) %}
+{% if source.rule is vyos_defined %}
+{% for rule, config in source.rule.items() if config.disable is not defined %}
+{% if config.outbound_interface is vyos_defined %}
+{% if config.outbound_interface not in global.ndppd_interfaces %}
+{% set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface] %}
+{% endif %}
+{% if config.translation.address is vyos_defined and config.translation.address | is_ip_network %}
+{% set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface,'rule':config.translation.address}] %}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{% for interface in global.ndppd_interfaces %}
+proxy {{ interface }} {
+ router yes
+ timeout 500
+ ttl 30000
+{% for map in global.ndppd_prefixs %}
+{% if map.interface == interface %}
+ rule {{ map.rule }} {
+ static
+ }
+{% endif %}
+{% endfor %}
+}
+{% endfor %}
diff --git a/data/templates/ndppd/ndppd.conf.tmpl b/data/templates/ndppd/ndppd.conf.tmpl
deleted file mode 100644
index c41392cc7..000000000
--- a/data/templates/ndppd/ndppd.conf.tmpl
+++ /dev/null
@@ -1,44 +0,0 @@
-########################################################
-#
-# autogenerated by nat66.py
-#
-# The configuration file must define one upstream
-# interface.
-#
-# For some services, such as nat66, because it runs
-# stateless, it needs to rely on NDP Proxy to respond
-# to NDP requests.
-#
-# When using nat66 source rules, NDP Proxy needs
-# to be enabled
-#
-########################################################
-
-{% set global = namespace(ndppd_interfaces = [],ndppd_prefixs = []) %}
-{% if source.rule is vyos_defined %}
-{% for rule, config in source.rule.items() if config.disable is not defined %}
-{% if config.outbound_interface is vyos_defined %}
-{% if config.outbound_interface not in global.ndppd_interfaces %}
-{% set global.ndppd_interfaces = global.ndppd_interfaces + [config.outbound_interface] %}
-{% endif %}
-{% if config.translation.address is vyos_defined and config.translation.address | is_ip_network %}
-{% set global.ndppd_prefixs = global.ndppd_prefixs + [{'interface':config.outbound_interface,'rule':config.translation.address}] %}
-{% endif %}
-{% endif %}
-{% endfor %}
-{% endif %}
-
-{% for interface in global.ndppd_interfaces %}
-proxy {{ interface }} {
- router yes
- timeout 500
- ttl 30000
-{% for map in global.ndppd_prefixs %}
-{% if map.interface == interface %}
- rule {{ map.rule }} {
- static
- }
-{% endif %}
-{% endfor %}
-}
-{% endfor %}
diff --git a/data/templates/nhrp/opennhrp.conf.j2 b/data/templates/nhrp/opennhrp.conf.j2
new file mode 100644
index 000000000..c040a8f14
--- /dev/null
+++ b/data/templates/nhrp/opennhrp.conf.j2
@@ -0,0 +1,42 @@
+{# j2lint: disable=jinja-variable-format #}
+# Created by VyOS - manual changes will be overwritten
+
+{% if tunnel is vyos_defined %}
+{% for name, tunnel_conf in tunnel.items() %}
+{% set type = 'spoke' if tunnel_conf.map is vyos_defined or tunnel_conf.dynamic_map is vyos_defined else 'hub' %}
+{% set profile_name = profile_map[name] if profile_map is vyos_defined and name in profile_map else '' %}
+interface {{ name }} #{{ type }} {{ profile_name }}
+{% if tunnel_conf.map is vyos_defined %}
+{% for map, map_conf in tunnel_conf.map.items() %}
+{% set cisco = ' cisco' if map_conf.cisco is vyos_defined else '' %}
+{% set register = ' register' if map_conf.register is vyos_defined else '' %}
+ map {{ map }} {{ map_conf.nbma_address }}{{ register }}{{ cisco }}
+{% endfor %}
+{% endif %}
+{% if tunnel_conf.dynamic_map is vyos_defined %}
+{% for map, map_conf in tunnel_conf.dynamic_map.items() %}
+ dynamic-map {{ map }} {{ map_conf.nbma_domain_name }}
+{% endfor %}
+{% endif %}
+{% if tunnel_conf.cisco_authentication is vyos_defined %}
+ cisco-authentication {{ tunnel_conf.cisco_authentication }}
+{% endif %}
+{% if tunnel_conf.holding_time is vyos_defined %}
+ holding-time {{ tunnel_conf.holding_time }}
+{% endif %}
+{% if tunnel_conf.multicast is vyos_defined %}
+ multicast {{ tunnel_conf.multicast }}
+{% endif %}
+{% for key in ['non_caching', 'redirect', 'shortcut', 'shortcut_destination'] %}
+{% if key in tunnel_conf %}
+ {{ key | replace("_", "-") }}
+{% endif %}
+{% endfor %}
+{% if tunnel_conf.shortcut_target is vyos_defined %}
+{% for target, shortcut_conf in tunnel_conf.shortcut_target.items() %}
+ shortcut-target {{ target }}{{ ' holding-time ' + shortcut_conf.holding_time if shortcut_conf.holding_time is vyos_defined }}
+{% endfor %}
+{% endif %}
+
+{% endfor %}
+{% endif %}
diff --git a/data/templates/nhrp/opennhrp.conf.tmpl b/data/templates/nhrp/opennhrp.conf.tmpl
deleted file mode 100644
index 721d41e49..000000000
--- a/data/templates/nhrp/opennhrp.conf.tmpl
+++ /dev/null
@@ -1,41 +0,0 @@
-# Created by VyOS - manual changes will be overwritten
-
-{% if tunnel is vyos_defined %}
-{% for name, tunnel_conf in tunnel.items() %}
-{% set type = 'spoke' if tunnel_conf.map is vyos_defined or tunnel_conf.dynamic_map is vyos_defined else 'hub' %}
-{% set profile_name = profile_map[name] if profile_map is vyos_defined and name in profile_map else '' %}
-interface {{ name }} #{{ type }} {{ profile_name }}
-{% if tunnel_conf.map is vyos_defined %}
-{% for map, map_conf in tunnel_conf.map.items() %}
-{% set cisco = ' cisco' if map_conf.cisco is vyos_defined else '' %}
-{% set register = ' register' if map_conf.register is vyos_defined else '' %}
- map {{ map }} {{ map_conf.nbma_address }}{{ register }}{{ cisco }}
-{% endfor %}
-{% endif %}
-{% if tunnel_conf.dynamic_map is vyos_defined %}
-{% for map, map_conf in tunnel_conf.dynamic_map.items() %}
- dynamic-map {{ map }} {{ map_conf.nbma_domain_name }}
-{% endfor %}
-{% endif %}
-{% if tunnel_conf.cisco_authentication is vyos_defined %}
- cisco-authentication {{ tunnel_conf.cisco_authentication }}
-{% endif %}
-{% if tunnel_conf.holding_time is vyos_defined %}
- holding-time {{ tunnel_conf.holding_time }}
-{% endif %}
-{% if tunnel_conf.multicast is vyos_defined %}
- multicast {{ tunnel_conf.multicast }}
-{% endif %}
-{% for key in ['non_caching', 'redirect', 'shortcut', 'shortcut_destination'] %}
-{% if key in tunnel_conf %}
- {{ key | replace("_", "-") }}
-{% endif %}
-{% endfor %}
-{% if tunnel_conf.shortcut_target is vyos_defined %}
-{% for target, shortcut_conf in tunnel_conf.shortcut_target.items() %}
- shortcut-target {{ target }}{{ ' holding-time ' + shortcut_conf.holding_time if shortcut_conf.holding_time is vyos_defined }}
-{% endfor %}
-{% endif %}
-
-{% endfor %}
-{% endif %}
diff --git a/data/templates/ocserv/ocserv_config.tmpl b/data/templates/ocserv/ocserv_config.j2
index 05b85a610..8418a2185 100644
--- a/data/templates/ocserv/ocserv_config.tmpl
+++ b/data/templates/ocserv/ocserv_config.j2
@@ -9,13 +9,13 @@ run-as-group = daemon
{% if "radius" in authentication.mode %}
auth = "radius [config=/run/ocserv/radiusclient.conf]"
{% elif "local" in authentication.mode %}
-{% if authentication.mode.local == "password-otp" %}
+{% if authentication.mode.local == "password-otp" %}
auth = "plain[passwd=/run/ocserv/ocpasswd,otp=/run/ocserv/users.oath]"
-{% elif authentication.mode.local == "otp" %}
+{% elif authentication.mode.local == "otp" %}
auth = "plain[otp=/run/ocserv/users.oath]"
-{% else %}
+{% else %}
auth = "plain[/run/ocserv/ocpasswd]"
-{% endif %}
+{% endif %}
{% else %}
auth = "plain[/run/ocserv/ocpasswd]"
{% endif %}
@@ -23,9 +23,9 @@ auth = "plain[/run/ocserv/ocpasswd]"
{% if ssl.certificate is vyos_defined %}
server-cert = /run/ocserv/cert.pem
server-key = /run/ocserv/cert.key
-{% if ssl.passphrase is vyos_defined %}
+{% if ssl.passphrase is vyos_defined %}
key-pin = {{ ssl.passphrase }}
-{% endif %}
+{% endif %}
{% endif %}
{% if ssl.ca_certificate is vyos_defined %}
@@ -59,33 +59,33 @@ device = sslvpn
# An alternative way of specifying the network:
{% if network_settings %}
# DNS settings
-{% if network_settings.name_server is string %}
+{% if network_settings.name_server is string %}
dns = {{ network_settings.name_server }}
-{% else %}
-{% for dns in network_settings.name_server %}
+{% else %}
+{% for dns in network_settings.name_server %}
dns = {{ dns }}
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
# IPv4 network pool
-{% if network_settings.client_ip_settings %}
-{% if network_settings.client_ip_settings.subnet %}
+{% if network_settings.client_ip_settings %}
+{% if network_settings.client_ip_settings.subnet %}
ipv4-network = {{ network_settings.client_ip_settings.subnet }}
+{% endif %}
{% endif %}
-{% endif %}
# IPv6 network pool
-{% if network_settings.client_ipv6_pool %}
-{% if network_settings.client_ipv6_pool.prefix %}
+{% if network_settings.client_ipv6_pool %}
+{% if network_settings.client_ipv6_pool.prefix %}
ipv6-network = {{ network_settings.client_ipv6_pool.prefix }}
ipv6-subnet-prefix = {{ network_settings.client_ipv6_pool.mask }}
+{% endif %}
{% endif %}
-{% endif %}
{% endif %}
{% if network_settings.push_route is string %}
route = {{ network_settings.push_route }}
{% else %}
-{% for route in network_settings.push_route %}
+{% for route in network_settings.push_route %}
route = {{ route }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/ocserv/ocserv_otp_usr.tmpl b/data/templates/ocserv/ocserv_otp_usr.j2
index 18de5fec6..b2511ed94 100644
--- a/data/templates/ocserv/ocserv_otp_usr.tmpl
+++ b/data/templates/ocserv/ocserv_otp_usr.j2
@@ -1,8 +1,8 @@
#<token_type> <username> <pin> <secret_hex_key> <counter> <lastpass> <time>
{% if username is vyos_defined %}
-{% for user, user_config in username.items() %}
-{% if user_config.disable is not vyos_defined and user_config.otp is vyos_defined %}
+{% for user, user_config in username.items() %}
+{% if user_config.disable is not vyos_defined and user_config.otp is vyos_defined %}
{{ user_config.otp.token_tmpl }} {{ user }} {{ user_config.otp.pin | default("-", true) }} {{ user_config.otp.key }}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/ocserv/ocserv_passwd.tmpl b/data/templates/ocserv/ocserv_passwd.j2
index 30c79d66a..30c79d66a 100644
--- a/data/templates/ocserv/ocserv_passwd.tmpl
+++ b/data/templates/ocserv/ocserv_passwd.j2
diff --git a/data/templates/ocserv/radius_conf.tmpl b/data/templates/ocserv/radius_conf.j2
index 1712d83ef..b6612fee5 100644
--- a/data/templates/ocserv/radius_conf.tmpl
+++ b/data/templates/ocserv/radius_conf.j2
@@ -1,13 +1,13 @@
### generated by vpn_openconnect.py ###
nas-identifier VyOS
{% for srv in server %}
-{% if not "disable" in server[srv] %}
-{% if "port" in server[srv] %}
-authserver {{ srv }}:{{server[srv]["port"]}}
-{% else %}
+{% if not "disable" in server[srv] %}
+{% if "port" in server[srv] %}
+authserver {{ srv }}:{{ server[srv]["port"] }}
+{% else %}
authserver {{ srv }}
+{% endif %}
{% endif %}
-{% endif %}
{% endfor %}
radius_timeout {{ timeout }}
{% if source_address %}
@@ -15,7 +15,7 @@ bindaddr {{ source_address }}
{% else %}
bindaddr *
{% endif %}
-servers /run/ocserv/radius_servers
+servers /run/ocserv/radius_servers
dictionary /etc/radcli/dictionary
default_realm
radius_retries 3
diff --git a/data/templates/ocserv/radius_servers.j2 b/data/templates/ocserv/radius_servers.j2
new file mode 100644
index 000000000..302e91600
--- /dev/null
+++ b/data/templates/ocserv/radius_servers.j2
@@ -0,0 +1,7 @@
+### generated by vpn_openconnect.py ###
+# server key
+{% for srv in server %}
+{% if not "disable" in server[srv] %}
+{{ srv }} {{ server[srv].key }}
+{% endif %}
+{% endfor %}
diff --git a/data/templates/ocserv/radius_servers.tmpl b/data/templates/ocserv/radius_servers.tmpl
deleted file mode 100644
index 7bacac992..000000000
--- a/data/templates/ocserv/radius_servers.tmpl
+++ /dev/null
@@ -1,7 +0,0 @@
-### generated by vpn_openconnect.py ###
-# server key
-{% for srv in server %}
-{% if not "disable" in server[srv] %}
-{{ srv }} {{ server[srv].key }}
-{% endif %}
-{% endfor %}
diff --git a/data/templates/pmacct/override.conf.tmpl b/data/templates/pmacct/override.conf.j2
index 213569ddc..213569ddc 100644
--- a/data/templates/pmacct/override.conf.tmpl
+++ b/data/templates/pmacct/override.conf.j2
diff --git a/data/templates/pmacct/uacctd.conf.j2 b/data/templates/pmacct/uacctd.conf.j2
new file mode 100644
index 000000000..a5016691f
--- /dev/null
+++ b/data/templates/pmacct/uacctd.conf.j2
@@ -0,0 +1,80 @@
+# Genereated from VyOS configuration
+daemonize: true
+promisc: false
+pidfile: /run/pmacct/uacctd.pid
+uacctd_group: 2
+uacctd_nl_size: 2097152
+snaplen: {{ packet_length }}
+aggregate: in_iface{{ ',out_iface' if enable_egress is vyos_defined }},src_mac,dst_mac,vlan,src_host,dst_host,src_port,dst_port,proto,tos,flows
+{% set pipe_size = buffer_size | int *1024 *1024 %}
+plugin_pipe_size: {{ pipe_size }}
+{# We need an integer division (//) without any remainder or fraction #}
+plugin_buffer_size: {{ pipe_size // 1000 }}
+{% if syslog_facility is vyos_defined %}
+syslog: {{ syslog_facility }}
+{% endif %}
+{% if disable_imt is not defined %}
+imt_path: /tmp/uacctd.pipe
+imt_mem_pools_number: 169
+{% endif %}
+
+{% set plugin = [] %}
+{% if netflow.server is vyos_defined %}
+{% for server in netflow.server %}
+{% set nf_server_key = 'nf_' ~ server | replace(':', '.') %}
+{% set _ = plugin.append('nfprobe['~ nf_server_key ~ ']') %}
+{% endfor %}
+{% endif %}
+{% if sflow.server is vyos_defined %}
+{% for server in sflow.server %}
+{% set sf_server_key = 'sf_' ~ server | replace(':', '.') %}
+{% set _ = plugin.append('sfprobe[' ~ sf_server_key ~ ']') %}
+{% endfor %}
+{% endif %}
+{% if disable_imt is not defined %}
+{% set _ = plugin.append('memory') %}
+{% endif %}
+plugins: {{ plugin | join(',') }}
+
+{% if netflow.server is vyos_defined %}
+# NetFlow servers
+{% for server, server_config in netflow.server.items() %}
+{# # prevent pmacct syntax error when using IPv6 flow collectors #}
+{% set nf_server_key = 'nf_' ~ server | replace(':', '.') %}
+nfprobe_receiver[{{ nf_server_key }}]: {{ server | bracketize_ipv6 }}:{{ server_config.port }}
+nfprobe_version[{{ nf_server_key }}]: {{ netflow.version }}
+{% if netflow.engine_id is vyos_defined %}
+nfprobe_engine[{{ nf_server_key }}]: {{ netflow.engine_id }}
+{% endif %}
+{% if netflow.max_flows is vyos_defined %}
+nfprobe_maxflows[{{ nf_server_key }}]: {{ netflow.max_flows }}
+{% endif %}
+{% if netflow.sampling_rate is vyos_defined %}
+sampling_rate[{{ nf_server_key }}]: {{ netflow.sampling_rate }}
+{% endif %}
+{% if netflow.source_address is vyos_defined %}
+nfprobe_source_ip[{{ nf_server_key }}]: {{ netflow.source_address }}
+{% endif %}
+{% if netflow.timeout is vyos_defined %}
+nfprobe_timeouts[{{ nf_server_key }}]: expint={{ netflow.timeout.expiry_interval }}:general={{ netflow.timeout.flow_generic }}:icmp={{ netflow.timeout.icmp }}:maxlife={{ netflow.timeout.max_active_life }}:tcp.fin={{ netflow.timeout.tcp_fin }}:tcp={{ netflow.timeout.tcp_generic }}:tcp.rst={{ netflow.timeout.tcp_rst }}:udp={{ netflow.timeout.udp }}
+{% endif %}
+
+{% endfor %}
+{% endif %}
+
+{% if sflow.server is vyos_defined %}
+# sFlow servers
+{% for server, server_config in sflow.server.items() %}
+{# # prevent pmacct syntax error when using IPv6 flow collectors #}
+{% set sf_server_key = 'sf_' ~ server | replace(':', '.') %}
+sfprobe_receiver[{{ sf_server_key }}]: {{ server | bracketize_ipv6 }}:{{ server_config.port }}
+sfprobe_agentip[{{ sf_server_key }}]: {{ sflow.agent_address }}
+{% if sflow.sampling_rate is vyos_defined %}
+sampling_rate[{{ sf_server_key }}]: {{ sflow.sampling_rate }}
+{% endif %}
+{% if sflow.source_address is vyos_defined %}
+sfprobe_source_ip[{{ sf_server_key }}]: {{ sflow.source_address }}
+{% endif %}
+
+{% endfor %}
+{% endif %}
diff --git a/data/templates/pmacct/uacctd.conf.tmpl b/data/templates/pmacct/uacctd.conf.tmpl
deleted file mode 100644
index 7e4f80e95..000000000
--- a/data/templates/pmacct/uacctd.conf.tmpl
+++ /dev/null
@@ -1,74 +0,0 @@
-# Genereated from VyOS configuration
-daemonize: true
-promisc: false
-pidfile: /run/pmacct/uacctd.pid
-uacctd_group: 2
-uacctd_nl_size: 2097152
-snaplen: {{ packet_length }}
-aggregate: in_iface{{ ',out_iface' if enable_egress is vyos_defined }},src_mac,dst_mac,vlan,src_host,dst_host,src_port,dst_port,proto,tos,flows
-{% set pipe_size = buffer_size | int *1024 *1024 %}
-plugin_pipe_size: {{ pipe_size }}
-{# We need an integer division (//) without any remainder or fraction #}
-plugin_buffer_size: {{ pipe_size // 1000 }}
-{% if syslog_facility is vyos_defined %}
-syslog: {{ syslog_facility }}
-{% endif %}
-{% if disable_imt is not defined %}
-imt_path: /tmp/uacctd.pipe
-imt_mem_pools_number: 169
-{% endif %}
-
-{% set plugin = [] %}
-{% if netflow.server is vyos_defined %}
-{% for server in netflow.server %}
-{% set _ = plugin.append('nfprobe[nf_' ~ server ~ ']') %}
-{% endfor %}
-{% endif %}
-{% if sflow.server is vyos_defined %}
-{% for server in sflow.server %}
-{% set _ = plugin.append('sfprobe[sf_' ~ server ~ ']') %}
-{% endfor %}
-{% endif %}
-{% if disable_imt is not defined %}
-{% set _ = plugin.append('memory') %}
-{% endif %}
-plugins: {{ plugin | join(',') }}
-
-{% if netflow.server is vyos_defined %}
-# NetFlow servers
-{% for server, server_config in netflow.server.items() %}
-nfprobe_receiver[nf_{{ server }}]: {{ server }}:{{ server_config.port }}
-nfprobe_version[nf_{{ server }}]: {{ netflow.version }}
-{% if netflow.engine_id is vyos_defined %}
-nfprobe_engine[nf_{{ server }}]: {{ netflow.engine_id }}
-{% endif %}
-{% if netflow.max_flows is vyos_defined %}
-nfprobe_maxflows[nf_{{ server }}]: {{ netflow.max_flows }}
-{% endif %}
-{% if netflow.sampling_rate is vyos_defined %}
-sampling_rate[nf_{{ server }}]: {{ netflow.sampling_rate }}
-{% endif %}
-{% if netflow.source_address is vyos_defined %}
-nfprobe_source_ip[nf_{{ server }}]: {{ netflow.source_address }}
-{% endif %}
-{% if netflow.timeout is vyos_defined %}
-nfprobe_timeouts[nf_{{ server }}]: expint={{ netflow.timeout.expiry_interval }}:general={{ netflow.timeout.flow_generic }}:icmp={{ netflow.timeout.icmp }}:maxlife={{ netflow.timeout.max_active_life }}:tcp.fin={{ netflow.timeout.tcp_fin }}:tcp={{ netflow.timeout.tcp_generic }}:tcp.rst={{ netflow.timeout.tcp_rst }}:udp={{ netflow.timeout.udp }}
-{% endif %}
-
-{% endfor %}
-{% endif %}
-
-{% if sflow.server is vyos_defined %}
-# sFlow servers
-{% for server, server_config in sflow.server.items() %}
-sfprobe_receiver[sf_{{ server }}]: {{ server }}:{{ server_config.port }}
-sfprobe_agentip[sf_{{ server }}]: {{ sflow.agent_address }}
-{% if sflow.sampling_rate is vyos_defined %}
-sampling_rate[sf_{{ server }}]: {{ sflow.sampling_rate }}
-{% endif %}
-{% if sflow.source_address is vyos_defined %}
-sfprobe_source_ip[sf_{{ server }}]: {{ sflow.source_address }}
-{% endif %}
-
-{% endfor %}
-{% endif %}
diff --git a/data/templates/pppoe/ip-down.script.tmpl b/data/templates/pppoe/ip-down.script.tmpl
deleted file mode 100644
index 0be7b03c8..000000000
--- a/data/templates/pppoe/ip-down.script.tmpl
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-if [ "$6" != "{{ ifname }}" ]; then
- exit
-fi
-
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ ifname }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-
-{% if connect_on_demand is not defined %}
-# See https://phabricator.vyos.net/T2248. Determine if we are enslaved to a
-# VRF, this is needed to properly insert the default route.
-VRF_NAME=""
-if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then
- # Determine upper (VRF) interface
- VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))
- # Remove upper_ prefix from result string
- VRF=${VRF#"upper_"}
- # Populate variable to run in VR context
- VRF_NAME="vrf ${VRF_NAME}"
-fi
-
-{% if default_route != 'none' %}
-# Always delete default route when interface goes down if we installed it
-vtysh -c "conf t" ${VRF_NAME} -c "no ip route 0.0.0.0/0 {{ ifname }} ${VRF_NAME}"
-{% if ipv6.address.autoconf is vyos_defined %}
-vtysh -c "conf t" ${VRF_NAME} -c "no ipv6 route ::/0 {{ ifname }} ${VRF_NAME}"
-{% endif %}
-{% endif %}
-{% endif %}
-
-{% if dhcpv6_options.pd is vyos_defined %}
-# Stop wide dhcpv6 client
-systemctl stop dhcp6c@{{ ifname }}.service
-{% endif %}
diff --git a/data/templates/pppoe/ip-pre-up.script.tmpl b/data/templates/pppoe/ip-pre-up.script.tmpl
deleted file mode 100644
index a54e4e9bd..000000000
--- a/data/templates/pppoe/ip-pre-up.script.tmpl
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-if [ "$6" != "{{ ifname }}" ]; then
- exit
-fi
-
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ ifname }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-
-echo "{{ description }}" > /sys/class/net/{{ ifname }}/ifalias
-
-{% if vrf %}
-logger -t pppd[$DIALER_PID] "configuring dialer interface $6 for VRF {{ vrf }}"
-ip link set dev {{ ifname }} master {{ vrf }}
-{% endif %}
diff --git a/data/templates/pppoe/ip-up.script.tmpl b/data/templates/pppoe/ip-up.script.tmpl
deleted file mode 100644
index 302756960..000000000
--- a/data/templates/pppoe/ip-up.script.tmpl
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-if [ "$6" != "{{ ifname }}" ]; then
- exit
-fi
-
-{% if connect_on_demand is not defined %}
-# add some info to syslog
-DIALER_PID=$(cat /var/run/{{ ifname }}.pid)
-logger -t pppd[$DIALER_PID] "executing $0"
-
-{% if default_route != 'none' %}
-# See https://phabricator.vyos.net/T2248 & T2220. Determine if we are enslaved
-# to a VRF, this is needed to properly insert the default route.
-
-SED_OPT="^ip route"
-VRF_NAME=""
-if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then
- # Determine upper (VRF) interface
- VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))
- # Remove upper_ prefix from result string
- VRF=${VRF#"upper_"}
- # generate new SED command
- SED_OPT="vrf ${VRF}"
- # generate vtysh option
- VRF_NAME="vrf ${VRF}"
-fi
-
-{% if default_route == 'auto' %}
-# Only insert a new default route if there is no default route configured
-routes=$(vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep 0.0.0.0/0 | wc -l)
-if [ "$routes" -ne 0 ]; then
- exit 1
-fi
-
-{% elif default_route == 'force' %}
-# Retrieve current static default routes and remove it from the routing table
-vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep 0.0.0.0/0 | while read route ; do
- vtysh -c "conf t" ${VTY_OPT} -c "no ${route} ${VRF_NAME}"
-done
-{% endif %}
-
-# Add default route to default or VRF routing table
-vtysh -c "conf t" ${VTY_OPT} -c "ip route 0.0.0.0/0 {{ ifname }} ${VRF_NAME}"
-logger -t pppd[$DIALER_PID] "added default route via {{ ifname }} ${VRF_NAME}"
-{% endif %}
-{% endif %}
diff --git a/data/templates/pppoe/ipv6-up.script.tmpl b/data/templates/pppoe/ipv6-up.script.tmpl
deleted file mode 100644
index da73cb4d5..000000000
--- a/data/templates/pppoe/ipv6-up.script.tmpl
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-# As PPPoE is an "on demand" interface we need to re-configure it when it
-# becomes up
-
-if [ "$6" != "{{ ifname }}" ]; then
- exit
-fi
-
-
-{% if default_route != 'none' %}
-# See https://phabricator.vyos.net/T2248 & T2220. Determine if we are enslaved
-# to a VRF, this is needed to properly insert the default route.
-
-SED_OPT="^ipv6 route"
-VRF_NAME=""
-if [ -d /sys/class/net/{{ ifname }}/upper_* ]; then
- # Determine upper (VRF) interface
- VRF=$(basename $(ls -d /sys/class/net/{{ ifname }}/upper_*))
- # Remove upper_ prefix from result string
- VRF=${VRF#"upper_"}
- # generate new SED command
- SED_OPT="vrf ${VRF}"
- # generate vtysh option
- VRF_NAME="vrf ${VRF}"
-fi
-
-{% if default_route == 'auto' %}
-# Only insert a new default route if there is no default route configured
-routes=$(vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep ::/0 | wc -l)
-if [ "$routes" -ne 0 ]; then
- exit 1
-fi
-
-{% elif default_route == 'force' %}
-# Retrieve current static default routes and remove it from the routing table
-vtysh -c "show running-config" | sed -n "/${SED_OPT}/,/!/p" | grep ::/0 | while read route ; do
- vtysh -c "conf t" ${VTY_OPT} -c "no ${route} ${VRF_NAME}"
-done
-{% endif %}
-
-# Add default route to default or VRF routing table
-vtysh -c "conf t" ${VTY_OPT} -c "ipv6 route ::/0 {{ ifname }} ${VRF_NAME}"
-logger -t pppd[$DIALER_PID] "added default route via {{ ifname }} ${VRF_NAME}"
-{% endif %}
-
diff --git a/data/templates/pppoe/peer.tmpl b/data/templates/pppoe/peer.j2
index d6d63debf..6221abb9b 100644
--- a/data/templates/pppoe/peer.tmpl
+++ b/data/templates/pppoe/peer.j2
@@ -67,14 +67,14 @@ demand
# See T2249. PPP default route options should only be set when in on-demand
# mode. As soon as we are not in on-demand mode the default-route handling is
# passed to the ip-up.d/ip-down.s scripts which is required for VRF support.
-{% if 'auto' in default_route %}
+{% if 'auto' in default_route %}
defaultroute
{{ 'defaultroute6' if ipv6 is vyos_defined }}
-{% elif 'force' in default_route %}
+{% elif 'force' in default_route %}
defaultroute
replacedefaultroute
{{ 'defaultroute6' if ipv6 is vyos_defined }}
-{% endif %}
+{% endif %}
{% else %}
nodefaultroute
noreplacedefaultroute
diff --git a/data/templates/router-advert/radvd.conf.tmpl b/data/templates/router-advert/radvd.conf.j2
index b40ba1ee0..6902dc05a 100644
--- a/data/templates/router-advert/radvd.conf.tmpl
+++ b/data/templates/router-advert/radvd.conf.j2
@@ -1,66 +1,66 @@
### Autogenerated by service_router-advert.py ###
{% if interface is vyos_defined %}
-{% for iface, iface_config in interface.items() %}
+{% for iface, iface_config in interface.items() %}
interface {{ iface }} {
IgnoreIfMissing on;
-{% if iface_config.default_preference is vyos_defined %}
+{% if iface_config.default_preference is vyos_defined %}
AdvDefaultPreference {{ iface_config.default_preference }};
-{% endif %}
-{% if iface_config.managed_flag is vyos_defined %}
+{% endif %}
+{% if iface_config.managed_flag is vyos_defined %}
AdvManagedFlag {{ 'on' if iface_config.managed_flag is vyos_defined else 'off' }};
-{% endif %}
-{% if iface_config.interval.max is vyos_defined %}
+{% endif %}
+{% if iface_config.interval.max is vyos_defined %}
MaxRtrAdvInterval {{ iface_config.interval.max }};
-{% endif %}
-{% if iface_config.interval.min is vyos_defined %}
+{% endif %}
+{% if iface_config.interval.min is vyos_defined %}
MinRtrAdvInterval {{ iface_config.interval.min }};
-{% endif %}
-{% if iface_config.reachable_time is vyos_defined %}
+{% endif %}
+{% if iface_config.reachable_time is vyos_defined %}
AdvReachableTime {{ iface_config.reachable_time }};
-{% endif %}
+{% endif %}
AdvIntervalOpt {{ 'off' if iface_config.no_send_advert is vyos_defined else 'on' }};
AdvSendAdvert {{ 'off' if iface_config.no_send_advert is vyos_defined else 'on' }};
-{% if iface_config.default_lifetime is vyos_defined %}
+{% if iface_config.default_lifetime is vyos_defined %}
AdvDefaultLifetime {{ iface_config.default_lifetime }};
-{% endif %}
-{% if iface_config.link_mtu is vyos_defined %}
+{% endif %}
+{% if iface_config.link_mtu is vyos_defined %}
AdvLinkMTU {{ iface_config.link_mtu }};
-{% endif %}
+{% endif %}
AdvOtherConfigFlag {{ 'on' if iface_config.other_config_flag is vyos_defined else 'off' }};
AdvRetransTimer {{ iface_config.retrans_timer }};
AdvCurHopLimit {{ iface_config.hop_limit }};
-{% if iface_config.route is vyos_defined %}
-{% for route, route_options in iface_config.route.items() %}
+{% if iface_config.route is vyos_defined %}
+{% for route, route_options in iface_config.route.items() %}
route {{ route }} {
-{% if route_options.valid_lifetime is vyos_defined %}
+{% if route_options.valid_lifetime is vyos_defined %}
AdvRouteLifetime {{ route_options.valid_lifetime }};
-{% endif %}
-{% if route_options.route_preference is vyos_defined %}
+{% endif %}
+{% if route_options.route_preference is vyos_defined %}
AdvRoutePreference {{ route_options.route_preference }};
-{% endif %}
+{% endif %}
RemoveRoute {{ 'off' if route_options.no_remove_route is vyos_defined else 'on' }};
};
-{% endfor %}
-{% endif %}
-{% if iface_config.prefix is vyos_defined %}
-{% for prefix, prefix_options in iface_config.prefix.items() %}
+{% endfor %}
+{% endif %}
+{% if iface_config.prefix is vyos_defined %}
+{% for prefix, prefix_options in iface_config.prefix.items() %}
prefix {{ prefix }} {
AdvAutonomous {{ 'off' if prefix_options.no_autonomous_flag is vyos_defined else 'on' }};
AdvValidLifetime {{ prefix_options.valid_lifetime }};
AdvOnLink {{ 'off' if prefix_options.no_on_link_flag is vyos_defined else 'on' }};
AdvPreferredLifetime {{ prefix_options.preferred_lifetime }};
};
-{% endfor %}
-{% endif %}
-{% if iface_config.name_server is vyos_defined %}
+{% endfor %}
+{% endif %}
+{% if iface_config.name_server is vyos_defined %}
RDNSS {{ iface_config.name_server | join(" ") }} {
};
-{% endif %}
-{% if iface_config.dnssl is vyos_defined %}
+{% endif %}
+{% if iface_config.dnssl is vyos_defined %}
DNSSL {{ iface_config.dnssl | join(" ") }} {
};
-{% endif %}
+{% endif %}
};
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/snmp/etc.snmp.conf.tmpl b/data/templates/snmp/etc.snmp.conf.j2
index 8012cf6bb..8012cf6bb 100644
--- a/data/templates/snmp/etc.snmp.conf.tmpl
+++ b/data/templates/snmp/etc.snmp.conf.j2
diff --git a/data/templates/snmp/etc.snmpd.conf.j2 b/data/templates/snmp/etc.snmpd.conf.j2
new file mode 100644
index 000000000..d7dc0ba5d
--- /dev/null
+++ b/data/templates/snmp/etc.snmpd.conf.j2
@@ -0,0 +1,182 @@
+### Autogenerated by snmp.py ###
+
+# non configurable defaults
+sysObjectID 1.3.6.1.4.1.44641
+sysServices 14
+master agentx
+agentXPerms 0777 0777
+pass .1.3.6.1.2.1.31.1.1.1.18 /opt/vyatta/sbin/if-mib-alias
+smuxpeer .1.3.6.1.2.1.83
+smuxpeer .1.3.6.1.2.1.157
+smuxsocket localhost
+
+# linkUp/Down configure the Event MIB tables to monitor
+# the ifTable for network interfaces being taken up or down
+# for making internal queries to retrieve any necessary information
+iquerySecName {{ vyos_user }}
+
+# Modified from the default linkUpDownNotification
+# to include more OIDs and poll more frequently
+notificationEvent linkUpTrap linkUp ifIndex ifDescr ifType ifAdminStatus ifOperStatus
+notificationEvent linkDownTrap linkDown ifIndex ifDescr ifType ifAdminStatus ifOperStatus
+monitor -r 10 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
+monitor -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2
+
+# Remove all old ifTable entries with the same ifName as newly appeared
+# interface (with different ifIndex) - this is the case on e.g. ppp interfaces
+interface_replace_old yes
+
+########################
+# configurable section #
+########################
+
+# Default system description is VyOS version
+sysDescr VyOS {{ version }}
+
+{% if description is vyos_defined %}
+# Description
+SysDescr {{ description }}
+{% endif %}
+
+# Listen
+{% set options = [] %}
+{% if listen_address is vyos_defined %}
+{% for address, address_options in listen_address.items() %}
+{% if address | is_ipv6 %}
+{% set protocol = protocol ~ '6' %}
+{% endif %}
+{% set _ = options.append(protocol ~ ':' ~ address | bracketize_ipv6 ~ ':' ~ address_options.port) %}
+{% endfor %}
+{% else %}
+{% set _ = options.append(protocol ~ ':161') %}
+{% set _ = options.append(protocol ~ '6:161') %}
+{% endif %}
+agentaddress unix:/run/snmpd.socket{{ ',' ~ options | join(',') if options is vyos_defined }}
+
+# SNMP communities
+{% if community is vyos_defined %}
+{% for comm, comm_config in community.items() %}
+{% if comm_config.client is vyos_defined %}
+{% for client in comm_config.client %}
+{% if client | is_ipv4 %}
+{{ comm_config.authorization }}community {{ comm }} {{ client }}
+{% elif client | is_ipv6 %}
+{{ comm_config.authorization }}community6 {{ comm }} {{ client }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if comm_config.network is vyos_defined %}
+{% for network in comm_config.network %}
+{% if network | is_ipv4 %}
+{{ comm_config.authorization }}community {{ comm }} {{ network }}
+{% elif client | is_ipv6 %}
+{{ comm_config.authorization }}community6 {{ comm }} {{ network }}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if comm_config.client is not vyos_defined and comm_config.network is not vyos_defined %}
+{{ comm_config.authorization }}community {{ comm }}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{% if contact is vyos_defined %}
+# system contact information
+SysContact {{ contact }}
+{% endif %}
+
+{% if location is vyos_defined %}
+# system location information
+SysLocation {{ location }}
+{% endif %}
+
+{% if smux_peer is vyos_defined %}
+# additional smux peers
+{% for peer in smux_peer %}
+smuxpeer {{ peer }}
+{% endfor %}
+{% endif %}
+
+{% if trap_target is vyos_defined %}
+# if there is a problem - tell someone!
+{% for trap, trap_config in trap_target.items() %}
+trap2sink {{ trap }}:{{ trap_config.port }} {{ trap_config.community }}
+{% endfor %}
+{% endif %}
+
+{% if v3 is vyos_defined %}
+#
+# SNMPv3 stuff goes here
+#
+{% if v3.view is vyos_defined %}
+# views
+{% for view, view_config in v3.view.items() %}
+{% if view_config.oid is vyos_defined %}
+{% for oid in view_config.oid %}
+view {{ view }} included .{{ oid }}
+{% endfor %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+# access
+{% if v3.group is vyos_defined %}
+# context sec.model sec.level match read write notif
+{% for group, group_config in v3.group.items() %}
+access {{ group }} "" usm {{ group_config.seclevel }} exact {{ group_config.view }} {{ 'none' if group_config.mode == 'ro' else group_config.view }} none
+{% endfor %}
+{% endif %}
+
+# trap-target
+{% if v3.trap_target is vyos_defined %}
+{% for trap, trap_config in v3.trap_target.items() %}
+{% set options = '' %}
+{% if trap_config.type == 'inform' %}
+{% set options = options ~ ' -Ci' %}
+{% endif %}
+{% if v3.engineid is vyos_defined %}
+{% set options = options ~ ' -e "' ~ v3.engineid ~ '"' %}
+{% endif %}
+{% if trap_config.user is vyos_defined %}
+{% set options = options ~ ' -u ' ~ trap_config.user %}
+{% endif %}
+{% if trap_config.auth.plaintext_password is vyos_defined or trap_config.auth.encrypted_password is vyos_defined %}
+{% set options = options ~ ' -a ' ~ trap_config.auth.type %}
+{% if trap_config.auth.plaintext_password is vyos_defined %}
+{% set options = options ~ ' -A ' ~ trap_config.auth.plaintext_password %}
+{% elif trap_config.auth.encrypted_password is vyos_defined %}
+{% set options = options ~ ' -3m ' ~ trap_config.auth.encrypted_password %}
+{% endif %}
+{% if trap_config.privacy.plaintext_password is vyos_defined or trap_config.privacy.encrypted_password is vyos_defined %}
+{% set options = options ~ ' -x ' ~ trap_config.privacy.type %}
+{% if trap_config.privacy.plaintext_password is vyos_defined %}
+{% set options = options ~ ' -X ' ~ trap_config.privacy.plaintext_password %}
+{% elif trap_config.privacy.encrypted_password is vyos_defined %}
+{% set options = options ~ ' -3M ' ~ trap_config.privacy.encrypted_password %}
+{% endif %}
+{% set options = options ~ ' -l authPriv' %}
+{% else %}
+{% set options = options ~ ' -l authNoPriv' %}
+{% endif %}
+{% else %}
+{% set options = options ~ ' -l noAuthNoPriv' %}
+{% endif %}
+trapsess -v 3 {{ options }} {{ trap }}:{{ trap_config.protocol }}:{{ trap_config.port }}
+{% endfor %}
+{% endif %}
+
+# group
+{% if v3.user is vyos_defined %}
+{% for user, user_config in v3.user.items() %}
+group {{ user_config.group }} usm {{ user }}
+{% endfor %}
+{% endif %}
+{# SNMPv3 end #}
+{% endif %}
+
+{% if script_extensions.extension_name is vyos_defined %}
+# extension scripts
+{% for script, script_config in script_extensions.extension_name.items() | sort(attribute=script) %}
+extend {{ script }} {{ script_config.script }}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/snmp/etc.snmpd.conf.tmpl b/data/templates/snmp/etc.snmpd.conf.tmpl
deleted file mode 100644
index 510b35097..000000000
--- a/data/templates/snmp/etc.snmpd.conf.tmpl
+++ /dev/null
@@ -1,182 +0,0 @@
-### Autogenerated by snmp.py ###
-
-# non configurable defaults
-sysObjectID 1.3.6.1.4.1.44641
-sysServices 14
-master agentx
-agentXPerms 0777 0777
-pass .1.3.6.1.2.1.31.1.1.1.18 /opt/vyatta/sbin/if-mib-alias
-smuxpeer .1.3.6.1.2.1.83
-smuxpeer .1.3.6.1.2.1.157
-smuxsocket localhost
-
-# linkUp/Down configure the Event MIB tables to monitor
-# the ifTable for network interfaces being taken up or down
-# for making internal queries to retrieve any necessary information
-iquerySecName {{ vyos_user }}
-
-# Modified from the default linkUpDownNotification
-# to include more OIDs and poll more frequently
-notificationEvent linkUpTrap linkUp ifIndex ifDescr ifType ifAdminStatus ifOperStatus
-notificationEvent linkDownTrap linkDown ifIndex ifDescr ifType ifAdminStatus ifOperStatus
-monitor -r 10 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
-monitor -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2
-
-# Remove all old ifTable entries with the same ifName as newly appeared
-# interface (with different ifIndex) - this is the case on e.g. ppp interfaces
-interface_replace_old yes
-
-########################
-# configurable section #
-########################
-
-# Default system description is VyOS version
-sysDescr VyOS {{ version }}
-
-{% if description is vyos_defined %}
-# Description
-SysDescr {{ description }}
-{% endif %}
-
-# Listen
-{% set options = [] %}
-{% if listen_address is vyos_defined %}
-{% for address, address_options in listen_address.items() %}
-{% if address | is_ipv6 %}
-{% set protocol = protocol ~ '6' %}
-{% endif %}
-{% set _ = options.append(protocol ~ ':' ~ address | bracketize_ipv6 ~ ':' ~ address_options.port) %}
-{% endfor %}
-{% else %}
-{% set _ = options.append(protocol ~ ':161') %}
-{% set _ = options.append(protocol ~ '6:161') %}
-{% endif %}
-agentaddress unix:/run/snmpd.socket{{ ',' ~ options | join(',') if options is vyos_defined }}
-
-# SNMP communities
-{% if community is vyos_defined %}
-{% for comm, comm_config in community.items() %}
-{% if comm_config.client is vyos_defined %}
-{% for client in comm_config.client %}
-{% if client | is_ipv4 %}
-{{ comm_config.authorization }}community {{ comm }} {{ client }}
-{% elif client | is_ipv6 %}
-{{ comm_config.authorization }}community6 {{ comm }} {{ client }}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if comm_config.network is vyos_defined %}
-{% for network in comm_config.network %}
-{% if network | is_ipv4 %}
-{{ comm_config.authorization }}community {{ comm }} {{ network }}
-{% elif client | is_ipv6 %}
-{{ comm_config.authorization }}community6 {{ comm }} {{ network }}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if comm_config.client is not vyos_defined and comm_config.network is not vyos_defined %}
-{{ comm_config.authorization }}community {{ comm }}
-{% endif %}
-{% endfor %}
-{% endif %}
-
-{% if contact is vyos_defined %}
-# system contact information
-SysContact {{ contact }}
-{% endif %}
-
-{% if location is vyos_defined %}
-# system location information
-SysLocation {{ location }}
-{% endif %}
-
-{% if smux_peer is vyos_defined %}
-# additional smux peers
-{% for peer in smux_peer %}
-smuxpeer {{ peer }}
-{% endfor %}
-{% endif %}
-
-{% if trap_target is vyos_defined %}
-# if there is a problem - tell someone!
-{% for trap, trap_config in trap_target.items() %}
-trap2sink {{ trap }}:{{ trap_config.port }} {{ trap_config.community }}
-{% endfor %}
-{% endif %}
-
-{% if v3 is vyos_defined %}
-#
-# SNMPv3 stuff goes here
-#
-{% if v3.view is vyos_defined %}
-# views
-{% for view, view_config in v3.view.items() %}
-{% if view_config.oid is vyos_defined %}
-{% for oid in view_config.oid %}
-view {{ view }} included .{{ oid }}
-{% endfor %}
-{% endif %}
-{% endfor %}
-{% endif %}
-
-# access
-{% if v3.group is vyos_defined %}
-# context sec.model sec.level match read write notif
-{% for group, group_config in v3.group.items() %}
-access {{ group }} "" usm {{ group_config.seclevel }} exact {{ group_config.view }} {% if group_config.mode == 'ro' %}none{% else %}{{ group_config.view }}{% endif %} none
-{% endfor %}
-{% endif %}
-
-# trap-target
-{% if v3.trap_target is vyos_defined %}
-{% for trap, trap_config in v3.trap_target.items() %}
-{% set options = '' %}
-{% if trap_config.type == 'inform' %}
-{% set options = options ~ ' -Ci' %}
-{% endif %}
-{% if v3.engineid is vyos_defined %}
-{% set options = options ~ ' -e "' ~ v3.engineid ~ '"' %}
-{% endif %}
-{% if trap_config.user is vyos_defined %}
-{% set options = options ~ ' -u ' ~ trap_config.user %}
-{% endif %}
-{% if trap_config.auth.plaintext_password is vyos_defined or trap_config.auth.encrypted_password is vyos_defined %}
-{% set options = options ~ ' -a ' ~ trap_config.auth.type %}
-{% if trap_config.auth.plaintext_password is vyos_defined %}
-{% set options = options ~ ' -A ' ~ trap_config.auth.plaintext_password %}
-{% elif trap_config.auth.encrypted_password is vyos_defined %}
-{% set options = options ~ ' -3m ' ~ trap_config.auth.encrypted_password %}
-{% endif %}
-{% if trap_config.privacy.plaintext_password is vyos_defined or trap_config.privacy.encrypted_password is vyos_defined %}
-{% set options = options ~ ' -x ' ~ trap_config.privacy.type %}
-{% if trap_config.privacy.plaintext_password is vyos_defined %}
-{% set options = options ~ ' -X ' ~ trap_config.privacy.plaintext_password %}
-{% elif trap_config.privacy.encrypted_password is vyos_defined %}
-{% set options = options ~ ' -3M ' ~ trap_config.privacy.encrypted_password %}
-{% endif %}
-{% set options = options ~ ' -l authPriv' %}
-{% else %}
-{% set options = options ~ ' -l authNoPriv' %}
-{% endif %}
-{% else %}
-{% set options = options ~ ' -l noAuthNoPriv' %}
-{% endif %}
-trapsess -v 3 {{ options }} {{ trap }}:{{ trap_config.protocol }}:{{ trap_config.port }}
-{% endfor %}
-{% endif %}
-
-# group
-{% if v3.user is vyos_defined %}
-{% for user, user_config in v3.user.items() %}
-group {{ user_config.group }} usm {{ user }}
-{% endfor %}
-{% endif %}
-{# SNMPv3 end #}
-{% endif %}
-
-{% if script_extensions.extension_name is vyos_defined %}
-# extension scripts
-{% for script, script_config in script_extensions.extension_name.items() | sort(attribute=script) %}
-extend {{ script }} {{ script_config.script }}
-{% endfor %}
-{% endif %}
diff --git a/data/templates/snmp/override.conf.tmpl b/data/templates/snmp/override.conf.j2
index 5d787de86..5d787de86 100644
--- a/data/templates/snmp/override.conf.tmpl
+++ b/data/templates/snmp/override.conf.j2
diff --git a/data/templates/snmp/usr.snmpd.conf.tmpl b/data/templates/snmp/usr.snmpd.conf.j2
index a46b3997f..a713c1cec 100644
--- a/data/templates/snmp/usr.snmpd.conf.tmpl
+++ b/data/templates/snmp/usr.snmpd.conf.j2
@@ -1,8 +1,8 @@
### Autogenerated by snmp.py ###
-{% if v3.user is vyos_defined %}
+{% if v3.user is vyos_defined %}
{% for user, user_config in v3.user.items() %}
{{ user_config.mode }}user {{ user }}
{% endfor %}
-{% endif %}
+{% endif %}
rwuser {{ vyos_user }}
diff --git a/data/templates/snmp/var.snmpd.conf.tmpl b/data/templates/snmp/var.snmpd.conf.j2
index 16d39db89..012f33aeb 100644
--- a/data/templates/snmp/var.snmpd.conf.tmpl
+++ b/data/templates/snmp/var.snmpd.conf.j2
@@ -1,16 +1,16 @@
### Autogenerated by snmp.py ###
# user
{% if v3 is vyos_defined %}
-{% if v3.user is vyos_defined %}
-{% for user, user_config in v3.user.items() %}
+{% if v3.user is vyos_defined %}
+{% for user, user_config in v3.user.items() %}
usmUser 1 3 0x{{ v3.engineid }} "{{ user }}" "{{ user }}" NULL {{ user_config.auth.type | snmp_auth_oid }} 0x{{ user_config.auth.encrypted_password }} {{ user_config.privacy.type | snmp_auth_oid }} 0x{{ user_config.privacy.encrypted_password }} 0x
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
# VyOS default user
createUser {{ vyos_user }} MD5 "{{ vyos_user_pass }}" DES
-{% if v3.engineid is vyos_defined %}
+{% if v3.engineid is vyos_defined %}
oldEngineID 0x{{ v3.engineid }}
-{% endif %}
+{% endif %}
{% endif %}
diff --git a/data/templates/squid/sg_acl.conf.tmpl b/data/templates/squid/sg_acl.conf.j2
index ce72b173a..ce72b173a 100644
--- a/data/templates/squid/sg_acl.conf.tmpl
+++ b/data/templates/squid/sg_acl.conf.j2
diff --git a/data/templates/squid/squid.conf.tmpl b/data/templates/squid/squid.conf.j2
index e8627b022..a0fdeb20e 100644
--- a/data/templates/squid/squid.conf.tmpl
+++ b/data/templates/squid/squid.conf.j2
@@ -16,23 +16,23 @@ acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
{% if authentication is vyos_defined %}
-{% if authentication.children is vyos_defined %}
+{% if authentication.children is vyos_defined %}
auth_param basic children {{ authentication.children }}
-{% endif %}
-{% if authentication.credentials_ttl is vyos_defined %}
+{% endif %}
+{% if authentication.credentials_ttl is vyos_defined %}
auth_param basic credentialsttl {{ authentication.credentials_ttl }} minute
-{% endif %}
-{% if authentication.realm is vyos_defined %}
+{% endif %}
+{% if authentication.realm is vyos_defined %}
auth_param basic realm "{{ authentication.realm }}"
-{% endif %}
+{% endif %}
{# LDAP based Authentication #}
-{% if authentication.method is vyos_defined %}
-{% if authentication.ldap is vyos_defined and authentication.method is vyos_defined('ldap') %}
+{% if authentication.method is vyos_defined %}
+{% if authentication.ldap is vyos_defined and authentication.method is vyos_defined('ldap') %}
auth_param basic program /usr/lib/squid/basic_ldap_auth -v {{ authentication.ldap.version }} -b "{{ authentication.ldap.base_dn }}" {{ '-D "' ~ authentication.ldap.bind_dn ~ '"' if authentication.ldap.bind_dn is vyos_defined }} {{ '-w "' ~ authentication.ldap.password ~ '"' if authentication.ldap.password is vyos_defined }} {{ '-f "' ~ authentication.ldap.filter_expression ~ '"' if authentication.ldap.filter_expression is vyos_defined }} {{ '-u "' ~ authentication.ldap.username_attribute ~ '"' if authentication.ldap.username_attribute is vyos_defined }} -p {{ authentication.ldap.port }} {{ '-ZZ' if authentication.ldap.use_ssl is vyos_defined }} -R -h "{{ authentication.ldap.server }}"
-{% endif %}
+{% endif %}
acl auth proxy_auth REQUIRED
http_access allow auth
-{% endif %}
+{% endif %}
{% endif %}
http_access allow manager localhost
@@ -44,18 +44,18 @@ http_access allow net
http_access deny all
{% if reply_block_mime is vyos_defined %}
-{% for mime_type in reply_block_mime %}
+{% for mime_type in reply_block_mime %}
acl BLOCK_MIME rep_mime_type {{ mime_type }}
-{% endfor %}
+{% endfor %}
http_reply_access deny BLOCK_MIME
{% endif %}
{% if cache_size is vyos_defined %}
-{% if cache_size | int > 0 %}
+{% if cache_size | int > 0 %}
cache_dir ufs /var/spool/squid {{ cache_size }} 16 256
-{% else %}
+{% else %}
# disabling disk cache
-{% endif %}
+{% endif %}
{% endif %}
{% if mem_cache_size is vyos_defined %}
cache_mem {{ mem_cache_size }} MB
@@ -87,9 +87,9 @@ tcp_outgoing_address {{ outgoing_address }}
{% if listen_address is vyos_defined %}
-{% for address, config in listen_address.items() %}
+{% for address, config in listen_address.items() %}
http_port {{ address | bracketize_ipv6 }}:{{ config.port if config.port is vyos_defined else default_port }} {{ 'intercept' if config.disable_transparent is not vyos_defined }}
-{% endfor %}
+{% endfor %}
{% endif %}
http_port 127.0.0.1:{{ default_port }}
@@ -104,8 +104,8 @@ url_rewrite_bypass on
{% endif %}
{% if cache_peer is vyos_defined %}
-{% for peer, config in cache_peer.items() %}
+{% for peer, config in cache_peer.items() %}
cache_peer {{ config.address }} {{ config.type }} {{ config.http_port }} {{ config.icp_port }} {{ config.options }}
-{% endfor %}
+{% endfor %}
never_direct allow all
{% endif %}
diff --git a/data/templates/squid/squidGuard.conf.j2 b/data/templates/squid/squidGuard.conf.j2
new file mode 100644
index 000000000..1bc4c984f
--- /dev/null
+++ b/data/templates/squid/squidGuard.conf.j2
@@ -0,0 +1,124 @@
+### generated by service_webproxy.py ###
+
+{% macro sg_rule(category, log, db_dir) %}
+{% set expressions = db_dir + '/' + category + '/expressions' %}
+dest {{ category }}-default {
+ domainlist {{ category }}/domains
+ urllist {{ category }}/urls
+{% if expressions | is_file %}
+ expressionlist {{ category }}/expressions
+{% endif %}
+{% if log is vyos_defined %}
+ log blacklist.log
+{% endif %}
+}
+{% endmacro %}
+
+{% if url_filtering is vyos_defined and url_filtering.disable is not vyos_defined %}
+{% if url_filtering.squidguard is vyos_defined %}
+{% set sg_config = url_filtering.squidguard %}
+{% set acl = namespace(value='local-ok-default') %}
+{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %}
+dbhome {{ squidguard_db_dir }}
+logdir /var/log/squid
+
+rewrite safesearch {
+ s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i
+ s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i
+ s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i
+ s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i
+ s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i
+ s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i
+ log rewrite.log
+}
+
+{% if sg_config.local_ok is vyos_defined %}
+{% set acl.value = acl.value + ' local-ok-default' %}
+dest local-ok-default {
+ domainlist local-ok-default/domains
+}
+{% endif %}
+{% if sg_config.local_ok_url is vyos_defined %}
+{% set acl.value = acl.value + ' local-ok-url-default' %}
+dest local-ok-url-default {
+ urllist local-ok-url-default/urls
+}
+{% endif %}
+{% if sg_config.local_block is vyos_defined %}
+{% set acl.value = acl.value + ' !local-block-default' %}
+dest local-block-default {
+ domainlist local-block-default/domains
+}
+{% endif %}
+{% if sg_config.local_block_url is vyos_defined %}
+{% set acl.value = acl.value + ' !local-block-url-default' %}
+dest local-block-url-default {
+ urllist local-block-url-default/urls
+}
+{% endif %}
+{% if sg_config.local_block_keyword is vyos_defined %}
+{% set acl.value = acl.value + ' !local-block-keyword-default' %}
+dest local-block-keyword-default {
+ expressionlist local-block-keyword-default/expressions
+}
+{% endif %}
+
+{% if sg_config.block_category is vyos_defined %}
+{% for category in sg_config.block_category %}
+{{ sg_rule(category, sg_config.log, squidguard_db_dir) }}
+{% set acl.value = acl.value + ' !' + category + '-default' %}
+{% endfor %}
+{% endif %}
+{% if sg_config.allow_category is vyos_defined %}
+{% for category in sg_config.allow_category %}
+{{ sg_rule(category, False, squidguard_db_dir) }}
+{% set acl.value = acl.value + ' ' + category + '-default' %}
+{% endfor %}
+{% endif %}
+{% if sg_config.source_group is vyos_defined %}
+{% for sgroup, sg_config in sg_config.source_group.items() %}
+{% if sg_config.address is vyos_defined %}
+src {{ sgroup }} {
+{% for address in sg_config.address %}
+ ip {{ address }}
+{% endfor %}
+}
+
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if sg_config.rule is vyos_defined %}
+{% for rule, rule_config in sg_config.rule.items() %}
+{% for b_category in rule_config.block_category %}
+dest {{ b_category }} {
+ domainlist {{ b_category }}/domains
+ urllist {{ b_category }}/urls
+}
+{% endfor %}
+
+{% endfor %}
+{% endif %}
+acl {
+{% if sg_config.rule is vyos_defined %}
+{% for rule, rule_config in sg_config.rule.items() %}
+ {{ rule_config.source_group }} {
+{% for b_category in rule_config.block_category %}
+ pass local-ok-1 !in-addr !{{ b_category }} all
+{% endfor %}
+ }
+{% endfor %}
+{% endif %}
+
+ default {
+{% if sg_config.enable_safe_search is vyos_defined %}
+ rewrite safesearch
+{% endif %}
+ pass {{ acl.value }} {{ 'none' if sg_config.default_action is vyos_defined('block') else 'allow' }}
+ redirect 302:http://{{ sg_config.redirect_url }}
+{% if sg_config.log is vyos_defined %}
+ log blacklist.log
+{% endif %}
+ }
+}
+{% endif %}
+{% endif %}
diff --git a/data/templates/squid/squidGuard.conf.tmpl b/data/templates/squid/squidGuard.conf.tmpl
deleted file mode 100644
index 5e877f01f..000000000
--- a/data/templates/squid/squidGuard.conf.tmpl
+++ /dev/null
@@ -1,124 +0,0 @@
-### generated by service_webproxy.py ###
-
-{% macro sg_rule(category, log, db_dir) %}
-{% set expressions = db_dir + '/' + category + '/expressions' %}
-dest {{ category }}-default {
- domainlist {{ category }}/domains
- urllist {{ category }}/urls
-{% if expressions | is_file %}
- expressionlist {{ category }}/expressions
-{% endif %}
-{% if log is vyos_defined %}
- log blacklist.log
-{% endif %}
-}
-{% endmacro %}
-
-{% if url_filtering is vyos_defined and url_filtering.disable is not vyos_defined %}
-{% if url_filtering.squidguard is vyos_defined %}
-{% set sg_config = url_filtering.squidguard %}
-{% set acl = namespace(value='local-ok-default') %}
-{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %}
-dbhome {{ squidguard_db_dir }}
-logdir /var/log/squid
-
-rewrite safesearch {
- s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i
- s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i
- s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i
- s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i
- s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i
- s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i
- log rewrite.log
-}
-
-{% if sg_config.local_ok is vyos_defined %}
-{% set acl.value = acl.value + ' local-ok-default' %}
-dest local-ok-default {
- domainlist local-ok-default/domains
-}
-{% endif %}
-{% if sg_config.local_ok_url is vyos_defined %}
-{% set acl.value = acl.value + ' local-ok-url-default' %}
-dest local-ok-url-default {
- urllist local-ok-url-default/urls
-}
-{% endif %}
-{% if sg_config.local_block is vyos_defined %}
-{% set acl.value = acl.value + ' !local-block-default' %}
-dest local-block-default {
- domainlist local-block-default/domains
-}
-{% endif %}
-{% if sg_config.local_block_url is vyos_defined %}
-{% set acl.value = acl.value + ' !local-block-url-default' %}
-dest local-block-url-default {
- urllist local-block-url-default/urls
-}
-{% endif %}
-{% if sg_config.local_block_keyword is vyos_defined %}
-{% set acl.value = acl.value + ' !local-block-keyword-default' %}
-dest local-block-keyword-default {
- expressionlist local-block-keyword-default/expressions
-}
-{% endif %}
-
-{% if sg_config.block_category is vyos_defined %}
-{% for category in sg_config.block_category %}
-{{ sg_rule(category, sg_config.log, squidguard_db_dir) }}
-{% set acl.value = acl.value + ' !' + category + '-default' %}
-{% endfor %}
-{% endif %}
-{% if sg_config.allow_category is vyos_defined %}
-{% for category in sg_config.allow_category %}
-{{ sg_rule(category, False, squidguard_db_dir) }}
-{% set acl.value = acl.value + ' ' + category + '-default' %}
-{% endfor %}
-{% endif %}
-{% if sg_config.source_group is vyos_defined %}
-{% for sgroup, sg_config in sg_config.source_group.items() %}
-{% if sg_config.address is vyos_defined %}
-src {{ sgroup }} {
-{% for address in sg_config.address %}
- ip {{ address }}
-{% endfor %}
-}
-
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if sg_config.rule is vyos_defined %}
-{% for rule, rule_config in sg_config.rule.items() %}
-{% for b_category in rule_config.block_category%}
-dest {{ b_category }} {
- domainlist {{ b_category }}/domains
- urllist {{ b_category }}/urls
-}
-{% endfor %}
-
-{% endfor %}
-{% endif %}
-acl {
-{% if sg_config.rule is vyos_defined %}
-{% for rule, rule_config in sg_config.rule.items() %}
- {{ rule_config.source_group }} {
-{% for b_category in rule_config.block_category%}
- pass local-ok-1 !in-addr !{{ b_category }} all
-{% endfor %}
- }
-{% endfor %}
-{% endif %}
-
- default {
-{% if sg_config.enable_safe_search is vyos_defined %}
- rewrite safesearch
-{% endif %}
- pass {{ acl.value }} {{ 'none' if sg_config.default_action is vyos_defined('block') else 'allow' }}
- redirect 302:http://{{ sg_config.redirect_url }}
-{% if sg_config.log is vyos_defined %}
- log blacklist.log
-{% endif %}
- }
-}
-{% endif %}
-{% endif %}
diff --git a/data/templates/ssh/sshguard_config.j2 b/data/templates/ssh/sshguard_config.j2
new file mode 100644
index 000000000..58c6ad48d
--- /dev/null
+++ b/data/templates/ssh/sshguard_config.j2
@@ -0,0 +1,27 @@
+### Autogenerated by ssh.py ###
+
+{% if dynamic_protection is vyos_defined %}
+# Full path to backend executable (required, no default)
+BACKEND="/usr/libexec/sshguard/sshg-fw-nft-sets"
+
+# Shell command that provides logs on standard output. (optional, no default)
+# Example 1: ssh and sendmail from systemd journal:
+LOGREADER="LANG=C journalctl -afb -p info -n1 -t sshd -o cat"
+
+#### OPTIONS ####
+# Block attackers when their cumulative attack score exceeds THRESHOLD.
+# Most attacks have a score of 10. (optional, default 30)
+THRESHOLD={{ dynamic_protection.threshold }}
+
+# Block attackers for initially BLOCK_TIME seconds after exceeding THRESHOLD.
+# Subsequent blocks increase by a factor of 1.5. (optional, default 120)
+BLOCK_TIME={{ dynamic_protection.block_time }}
+
+# Remember potential attackers for up to DETECTION_TIME seconds before
+# resetting their score. (optional, default 1800)
+DETECTION_TIME={{ dynamic_protection.detect_time }}
+
+# IP addresses listed in the WHITELIST_FILE are considered to be
+# friendlies and will never be blocked.
+WHITELIST_FILE=/etc/sshguard/whitelist
+{% endif %}
diff --git a/data/templates/ssh/sshguard_whitelist.j2 b/data/templates/ssh/sshguard_whitelist.j2
new file mode 100644
index 000000000..47a950a2b
--- /dev/null
+++ b/data/templates/ssh/sshguard_whitelist.j2
@@ -0,0 +1,7 @@
+### Autogenerated by ssh.py ###
+
+{% if dynamic_protection.allow_from is vyos_defined %}
+{% for address in dynamic_protection.allow_from %}
+{{ address }}
+{% endfor %}
+{% endif %}
diff --git a/data/templates/syslog/logrotate.tmpl b/data/templates/syslog/logrotate.j2
index c1b951e8b..c1b951e8b 100644
--- a/data/templates/syslog/logrotate.tmpl
+++ b/data/templates/syslog/logrotate.j2
diff --git a/data/templates/syslog/rsyslog.conf.tmpl b/data/templates/syslog/rsyslog.conf.j2
index 2fb621760..4445d568b 100644
--- a/data/templates/syslog/rsyslog.conf.tmpl
+++ b/data/templates/syslog/rsyslog.conf.j2
@@ -2,9 +2,9 @@
## file based logging
{% if files['global']['marker'] %}
$ModLoad immark
-{% if files['global']['marker-interval'] %}
-$MarkMessagePeriod {{files['global']['marker-interval']}}
-{% endif %}
+{% if files['global']['marker-interval'] %}
+$MarkMessagePeriod {{ files['global']['marker-interval'] }}
+{% endif %}
{% endif %}
{% if files['global']['preserver_fqdn'] %}
$PreserveFQDN on
@@ -15,40 +15,40 @@ $outchannel {{ file }},{{ file_options['log-file'] }},{{ file_options['max-size'
{% endfor %}
{% if console is defined and console is not none %}
## console logging
-{% for con, con_options in console.items() %}
+{% for con, con_options in console.items() %}
{{ con_options['selectors'] }} /dev/console
-{% endfor %}
+{% endfor %}
{% endif %}
{% if hosts is defined and hosts is not none %}
## remote logging
-{% for host, host_options in hosts.items() %}
-{% if host_options.proto == 'tcp' %}
-{% if host_options.port is defined %}
-{% if host_options.oct_count is defined %}
+{% for host, host_options in hosts.items() %}
+{% if host_options.proto == 'tcp' %}
+{% if host_options.port is defined %}
+{% if host_options.oct_count is defined %}
{{ host_options.selectors }} @@(o){{ host | bracketize_ipv6 }}:{{ host_options.port }};RSYSLOG_SyslogProtocol23Format
-{% else %}
+{% else %}
{{ host_options.selectors }} @@{{ host | bracketize_ipv6 }}:{{ host_options.port }}
-{% endif %}
-{% else %}
+{% endif %}
+{% else %}
{{ host_options.selectors }} @@{{ host | bracketize_ipv6 }}
-{% endif %}
-{% elif host_options.proto == 'udp' %}
-{% if host_options.port is defined %}
+{% endif %}
+{% elif host_options.proto == 'udp' %}
+{% if host_options.port is defined %}
{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}:{{ host_options.port }}{{ ';RSYSLOG_SyslogProtocol23Format' if host_options.oct_count is sameas true }}
-{% else %}
+{% else %}
{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}
-{% endif %}
-{% else %}
-{% if host_options['port'] %}
+{% endif %}
+{% else %}
+{% if host_options['port'] %}
{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}:{{ host_options.port }}
-{% else %}
+{% else %}
{{ host_options.selectors }} @{{ host | bracketize_ipv6 }}
-{% endif %}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
{% endif %}
{% if user is defined and user is not none %}
-{% for username, user_options in user.items() %}
+{% for username, user_options in user.items() %}
{{ user_options.selectors }} :omusrmsg:{{ username }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/system/curlrc.tmpl b/data/templates/system/curlrc.j2
index be4efe8ba..be4efe8ba 100644
--- a/data/templates/system/curlrc.tmpl
+++ b/data/templates/system/curlrc.j2
diff --git a/data/templates/system/ssh_config.tmpl b/data/templates/system/ssh_config.j2
index 1449f95b1..1449f95b1 100644
--- a/data/templates/system/ssh_config.tmpl
+++ b/data/templates/system/ssh_config.j2
diff --git a/data/templates/system/sysctl.conf.tmpl b/data/templates/system/sysctl.conf.j2
index 3aa857647..59a19e157 100644
--- a/data/templates/system/sysctl.conf.tmpl
+++ b/data/templates/system/sysctl.conf.j2
@@ -1,7 +1,7 @@
# autogenerated by system_sysctl.py
{% if parameter is vyos_defined %}
-{% for k, v in parameter.items() %}
+{% for k, v in parameter.items() %}
{{ k }} = {{ v.value }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/tftp-server/default.tmpl b/data/templates/tftp-server/default.j2
index 56784d467..b2676e0aa 100644
--- a/data/templates/tftp-server/default.tmpl
+++ b/data/templates/tftp-server/default.j2
@@ -1,3 +1,4 @@
+{# j2lint: disable=jinja-variable-format #}
### Autogenerated by tftp_server.py ###
DAEMON_ARGS="--listen --user tftp --address {{ listen_address }} {{ "--create --umask 000" if allow_upload is vyos_defined }} --secure {{ directory }}"
{% if vrf is vyos_defined %}
diff --git a/data/templates/vrf/vrf.conf.tmpl b/data/templates/vrf/vrf.conf.j2
index a51e11ddf..d31d23574 100644
--- a/data/templates/vrf/vrf.conf.tmpl
+++ b/data/templates/vrf/vrf.conf.j2
@@ -3,7 +3,7 @@
# Routing table ID to name mapping reference
# id vrf name comment
{% if name is vyos_defined %}
-{% for vrf, vrf_config in name.items() %}
+{% for vrf, vrf_config in name.items() %}
{{ "%-10s" | format(vrf_config.table) }} {{ "%-16s" | format(vrf) }} {{ '# ' ~ vrf_config.description if vrf_config.description is vyos_defined }}
-{% endfor %}
+{% endfor %}
{% endif %}
diff --git a/data/templates/zone_policy/nftables.tmpl b/data/templates/zone_policy/nftables.j2
index 9e532b79e..e4c4dd7da 100644
--- a/data/templates/zone_policy/nftables.tmpl
+++ b/data/templates/zone_policy/nftables.j2
@@ -1,113 +1,113 @@
#!/usr/sbin/nft -f
{% if cleanup_commands is vyos_defined %}
-{% for command in cleanup_commands %}
+{% for command in cleanup_commands %}
{{ command }}
-{% endfor %}
+{% endfor %}
{% endif %}
{% if zone is vyos_defined %}
table ip filter {
-{% for zone_name, zone_conf in zone.items() if zone_conf.ipv4 %}
-{% if zone_conf.local_zone is vyos_defined %}
+{% for zone_name, zone_conf in zone.items() if zone_conf.ipv4 %}
+{% if zone_conf.local_zone is vyos_defined %}
chain VZONE_{{ zone_name }}_IN {
iifname lo counter return
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.name is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.name is vyos_defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME_{{ from_conf.firewall.name }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
chain VZONE_{{ zone_name }}_OUT {
oifname lo counter return
-{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.name is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.name is vyos_defined %}
oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME_{{ from_conf.firewall.name }}
oifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
-{% else %}
+{% else %}
chain VZONE_{{ zone_name }} {
iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=False) }}
-{% if zone_conf.intra_zone_filtering is vyos_defined %}
+{% if zone_conf.intra_zone_filtering is vyos_defined %}
iifname { {{ zone_conf.interface | join(",") }} } counter return
-{% endif %}
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.name is vyos_defined %}
-{% if zone[from_zone].local_zone is not defined %}
+{% endif %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.name is vyos_defined %}
+{% if zone[from_zone].local_zone is not defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME_{{ from_conf.firewall.name }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
}
table ip6 filter {
-{% for zone_name, zone_conf in zone.items() if zone_conf.ipv6 %}
-{% if zone_conf.local_zone is vyos_defined %}
+{% for zone_name, zone_conf in zone.items() if zone_conf.ipv6 %}
+{% if zone_conf.local_zone is vyos_defined %}
chain VZONE6_{{ zone_name }}_IN {
iifname lo counter return
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
chain VZONE6_{{ zone_name }}_OUT {
oifname lo counter return
-{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall.ipv6_name is vyos_defined %}
oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
oifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endfor %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
-{% else %}
+{% else %}
chain VZONE6_{{ zone_name }} {
iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6=True) }}
-{% if zone_conf.intra_zone_filtering is vyos_defined %}
+{% if zone_conf.intra_zone_filtering is vyos_defined %}
iifname { {{ zone_conf.interface | join(",") }} } counter return
-{% endif %}
-{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
-{% if zone[from_zone].local_zone is not defined %}
+{% endif %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall.ipv6_name is vyos_defined %}
+{% if zone[from_zone].local_zone is not defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME6_{{ from_conf.firewall.ipv6_name }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
counter {{ zone_conf.default_action }}
}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endfor %}
}
-{% for zone_name, zone_conf in zone.items() %}
-{% if zone_conf.ipv4 %}
-{% if 'local_zone' in zone_conf %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.ipv4 %}
+{% if 'local_zone' in zone_conf %}
insert rule ip filter VYOS_FW_LOCAL counter jump VZONE_{{ zone_name }}_IN
insert rule ip filter VYOS_FW_OUTPUT counter jump VZONE_{{ zone_name }}_OUT
-{% else %}
+{% else %}
insert rule ip filter VYOS_FW_FORWARD oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
-{% endif %}
-{% endif %}
-{% if zone_conf.ipv6 %}
-{% if 'local_zone' in zone_conf %}
+{% endif %}
+{% endif %}
+{% if zone_conf.ipv6 %}
+{% if 'local_zone' in zone_conf %}
insert rule ip6 filter VYOS_FW6_LOCAL counter jump VZONE6_{{ zone_name }}_IN
insert rule ip6 filter VYOS_FW6_OUTPUT counter jump VZONE6_{{ zone_name }}_OUT
-{% else %}
+{% else %}
insert rule ip6 filter VYOS_FW6_FORWARD oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE6_{{ zone_name }}
-{% endif %}
-{% endif %}
-{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
{# Ensure that state-policy rule is first in the chain #}
-{% if firewall.state_policy is vyos_defined %}
-{% for chain in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL'] %}
+{% if firewall.state_policy is vyos_defined %}
+{% for chain in ['VYOS_FW_FORWARD', 'VYOS_FW_OUTPUT', 'VYOS_FW_LOCAL'] %}
insert rule ip filter {{ chain }} jump VYOS_STATE_POLICY
-{% endfor %}
-{% for chain in ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL'] %}
+{% endfor %}
+{% for chain in ['VYOS_FW6_FORWARD', 'VYOS_FW6_OUTPUT', 'VYOS_FW6_LOCAL'] %}
insert rule ip6 filter {{ chain }} jump VYOS_STATE_POLICY6
-{% endfor %}
-{% endif %}
+{% endfor %}
+{% endif %}
{% endif %}
diff --git a/debian/control b/debian/control
index c53e4d3b8..bcd5acfdd 100644
--- a/debian/control
+++ b/debian/control
@@ -147,6 +147,7 @@ Depends:
squid,
squidclient,
squidguard,
+ sshguard,
ssl-cert,
strongswan (>= 5.9),
strongswan-swanctl (>= 5.9),
diff --git a/interface-definitions/containers.xml.in b/interface-definitions/container.xml.in
index 85231b50c..51171d881 100644
--- a/interface-definitions/containers.xml.in
+++ b/interface-definitions/container.xml.in
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<interfaceDefinition>
- <node name="container" owner="${vyos_conf_scripts_dir}/containers.py">
+ <node name="container" owner="${vyos_conf_scripts_dir}/container.py">
<properties>
<help>Container applications</help>
<priority>1280</priority>
diff --git a/interface-definitions/flow-accounting-conf.xml.in b/interface-definitions/flow-accounting-conf.xml.in
index fc59f8ab3..878566b3f 100644
--- a/interface-definitions/flow-accounting-conf.xml.in
+++ b/interface-definitions/flow-accounting-conf.xml.in
@@ -220,7 +220,7 @@
</leafNode>
<tagNode name="server">
<properties>
- <help>Server to export NetFlow [REQUIRED]</help>
+ <help>NetFlow destination server</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 server to export NetFlow</description>
@@ -398,7 +398,7 @@
</leafNode>
<tagNode name="server">
<properties>
- <help>Server to export sFlow [REQUIRED]</help>
+ <help>sFlow destination server</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 server to export sFlow</description>
diff --git a/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i b/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i
index be49fce5a..f44920c3f 100644
--- a/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i
+++ b/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i
@@ -21,6 +21,20 @@
<valueless />
</properties>
</leafNode>
+ <leafNode name="multiplier">
+ <properties>
+ <help>Shaper multiplier</help>
+ <valueHelp>
+ <format>&lt;0.001-1000&gt;</format>
+ <description>Shaper multiplier</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0.001-1000 --float"/>
+ </constraint>
+ <constraintErrorMessage>Multiplier needs to be between 0.001 and 1000</constraintErrorMessage>
+ </properties>
+ <defaultValue>1</defaultValue>
+ </leafNode>
</children>
</node>
<!-- include end -->
diff --git a/interface-definitions/include/auth-local-users.xml.i b/interface-definitions/include/auth-local-users.xml.i
index cb456eecf..9fb507474 100644
--- a/interface-definitions/include/auth-local-users.xml.i
+++ b/interface-definitions/include/auth-local-users.xml.i
@@ -19,74 +19,6 @@
<help>Password used for authentication</help>
</properties>
</leafNode>
- <node name="otp">
- <properties>
- <help>2FA OTP authentication parameters</help>
- </properties>
- <children>
- <leafNode name="key">
- <properties>
- <help>Token Key Secret key for the token algorithm (see RFC 4226)</help>
- <valueHelp>
- <format>txt</format>
- <description>OTP key in hex-encoded format</description>
- </valueHelp>
- <constraint>
- <regex>[a-fA-F0-9]{20,10000}</regex>
- </constraint>
- <constraintErrorMessage>Key name must only include hex characters and be at least 20 characters long</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="otp-length">
- <properties>
- <help>Number of digits in OTP code</help>
- <valueHelp>
- <format>u32:6-8</format>
- <description>Number of digits in OTP code</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 6-8"/>
- </constraint>
- <constraintErrorMessage>Number of digits in OTP code must be between 6 and 8</constraintErrorMessage>
- </properties>
- <defaultValue>6</defaultValue>
- </leafNode>
- <leafNode name="interval">
- <properties>
- <help>Time tokens interval in seconds</help>
- <valueHelp>
- <format>u32:5-86400</format>
- <description>Time tokens interval in seconds.</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 5-86400"/>
- </constraint>
- <constraintErrorMessage>Time token interval must be between 5 and 86400 seconds</constraintErrorMessage>
- </properties>
- <defaultValue>30</defaultValue>
- </leafNode>
- <leafNode name="token-type">
- <properties>
- <help>Token type</help>
- <valueHelp>
- <format>hotp-time</format>
- <description>Time-based OTP algorithm</description>
- </valueHelp>
- <valueHelp>
- <format>hotp-event</format>
- <description>Event-based OTP algorithm</description>
- </valueHelp>
- <constraint>
- <regex>(hotp-time|hotp-event)</regex>
- </constraint>
- <completionHelp>
- <list>hotp-time hotp-event</list>
- </completionHelp>
- </properties>
- <defaultValue>hotp-time</defaultValue>
- </leafNode>
- </children>
- </node>
</children>
</tagNode>
</children>
diff --git a/interface-definitions/include/firewall/common-rule.xml.i b/interface-definitions/include/firewall/common-rule.xml.i
index cbdfa9dc2..2a5137dbf 100644
--- a/interface-definitions/include/firewall/common-rule.xml.i
+++ b/interface-definitions/include/firewall/common-rule.xml.i
@@ -95,6 +95,32 @@
</constraint>
</properties>
</leafNode>
+<node name="connection-status">
+ <properties>
+ <help>Connection status</help>
+ </properties>
+ <children>
+ <leafNode name="nat">
+ <properties>
+ <help>NAT connection status</help>
+ <completionHelp>
+ <list>destination source</list>
+ </completionHelp>
+ <valueHelp>
+ <format>destination</format>
+ <description>Match connections that are subject to destination NAT</description>
+ </valueHelp>
+ <valueHelp>
+ <format>source</format>
+ <description>Match connections that are subject to source NAT</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(destination|source)$</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
<leafNode name="protocol">
<properties>
<help>Protocol to match (protocol name, number, or "all")</help>
diff --git a/interface-definitions/include/ipsec/local-address.xml.i b/interface-definitions/include/ipsec/local-address.xml.i
index dc5653ce7..9d267f3f7 100644
--- a/interface-definitions/include/ipsec/local-address.xml.i
+++ b/interface-definitions/include/ipsec/local-address.xml.i
@@ -4,6 +4,7 @@
<help>IPv4 or IPv6 address of a local interface to use for VPN</help>
<completionHelp>
<list>any</list>
+ <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
</completionHelp>
<valueHelp>
<format>ipv4</format>
diff --git a/interface-definitions/include/monitoring/url.xml.i b/interface-definitions/include/monitoring/url.xml.i
new file mode 100644
index 000000000..32c81122d
--- /dev/null
+++ b/interface-definitions/include/monitoring/url.xml.i
@@ -0,0 +1,15 @@
+<!-- include start from monitoring/url.xml.i -->
+<leafNode name="url">
+ <properties>
+ <help>Remote URL [REQUIRED]</help>
+ <valueHelp>
+ <format>url</format>
+ <description>Remote URL</description>
+ </valueHelp>
+ <constraint>
+ <regex>(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}?(\/.*)?</regex>
+ </constraint>
+ <constraintErrorMessage>Incorrect URL format</constraintErrorMessage>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/version/quagga-version.xml.i b/interface-definitions/include/version/quagga-version.xml.i
index bb8ad7f82..f9944acce 100644
--- a/interface-definitions/include/version/quagga-version.xml.i
+++ b/interface-definitions/include/version/quagga-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/quagga-version.xml.i -->
-<syntaxVersion component='quagga' version='9'></syntaxVersion>
+<syntaxVersion component='quagga' version='10'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/policy-local-route.xml.in b/interface-definitions/policy-local-route.xml.in
index 573a7963f..d969613b1 100644
--- a/interface-definitions/policy-local-route.xml.in
+++ b/interface-definitions/policy-local-route.xml.in
@@ -146,11 +146,11 @@
<properties>
<help>Source address or prefix</help>
<valueHelp>
- <format>ipv4</format>
+ <format>ipv6</format>
<description>Address to match against</description>
</valueHelp>
<valueHelp>
- <format>ipv4net</format>
+ <format>ipv6net</format>
<description>Prefix to match against</description>
</valueHelp>
<constraint>
diff --git a/interface-definitions/policy.xml.in b/interface-definitions/policy.xml.in
index ddb0159d5..50b7cbc84 100644
--- a/interface-definitions/policy.xml.in
+++ b/interface-definitions/policy.xml.in
@@ -948,24 +948,49 @@
</leafNode>
</children>
</node>
- <leafNode name="as-path-exclude">
+ <node name="as-path">
<properties>
- <help>Remove ASN(s) from a Border Gateway Protocol (BGP) AS-path attribute</help>
- <valueHelp>
- <format>txt</format>
- <description>BGP AS path exclude string (ex: "456 64500 45001")</description>
- </valueHelp>
- </properties>
- </leafNode>
- <leafNode name="as-path-prepend">
- <properties>
- <help>Prepend string for a Border Gateway Protocol (BGP) AS-path attribute</help>
- <valueHelp>
- <format>txt</format>
- <description>BGP AS path prepend string (ex: "64501 64501")</description>
- </valueHelp>
+ <help>Transform BGP AS_PATH attribute</help>
</properties>
- </leafNode>
+ <children>
+ <leafNode name="exclude">
+ <properties>
+ <help>Remove/exclude from the as-path attribute</help>
+ <valueHelp>
+ <format>u32</format>
+ <description>AS number</description>
+ </valueHelp>
+ <constraint>
+ <validator name="as-number-list"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="prepend">
+ <properties>
+ <help>Prepend to the as-path</help>
+ <valueHelp>
+ <format>u32</format>
+ <description>AS number</description>
+ </valueHelp>
+ <constraint>
+ <validator name="as-number-list"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="prepend-last-as">
+ <properties>
+ <help>Use the last AS-number in the as-path</help>
+ <valueHelp>
+ <format>u32:1-10</format>
+ <description>Number of times to insert</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-10"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<leafNode name="atomic-aggregate">
<properties>
<help>BGP atomic aggregate attribute</help>
@@ -1045,6 +1070,44 @@
</constraint>
</properties>
</leafNode>
+ <node name="evpn">
+ <properties>
+ <help>Ethernet Virtual Private Network</help>
+ </properties>
+ <children>
+ <node name="gateway">
+ <properties>
+ <help>Set gateway IP for prefix advertisement route</help>
+ </properties>
+ <children>
+ <leafNode name="ipv4">
+ <properties>
+ <help>Set gateway IPv4 address</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>Gateway IPv4 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="ipv6">
+ <properties>
+ <help>Set gateway IPv6 address</help>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>Gateway IPv6 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
<node name="extcommunity">
<properties>
<help>BGP extended community attribute</help>
diff --git a/interface-definitions/protocols-nhrp.xml.in b/interface-definitions/protocols-nhrp.xml.in
index 7de3704ce..1e08c6873 100644
--- a/interface-definitions/protocols-nhrp.xml.in
+++ b/interface-definitions/protocols-nhrp.xml.in
@@ -4,7 +4,7 @@
<children>
<node name="nhrp" owner="${vyos_conf_scripts_dir}/protocols_nhrp.py">
<properties>
- <help>NHRP parameters</help>
+ <help>Next Hop Resolution Protocol (NHRP) parameters</help>
<priority>680</priority>
</properties>
<children>
diff --git a/interface-definitions/service_conntrack-sync.xml.in b/interface-definitions/service_conntrack-sync.xml.in
index 32efa7323..6fa6fc5f9 100644
--- a/interface-definitions/service_conntrack-sync.xml.in
+++ b/interface-definitions/service_conntrack-sync.xml.in
@@ -5,7 +5,8 @@
<node name="conntrack-sync" owner="${vyos_conf_scripts_dir}/conntrack_sync.py">
<properties>
<help>Connection tracking synchronization</help>
- <priority>995</priority>
+ <!-- before VRRP / HA -->
+ <priority>799</priority>
</properties>
<children>
<leafNode name="accept-protocol">
diff --git a/interface-definitions/service_monitoring_telegraf.xml.in b/interface-definitions/service_monitoring_telegraf.xml.in
index 01bc16fc9..bd528ea33 100644
--- a/interface-definitions/service_monitoring_telegraf.xml.in
+++ b/interface-definitions/service_monitoring_telegraf.xml.in
@@ -42,6 +42,94 @@
</leafNode>
</children>
</node>
+ <node name="azure-data-explorer">
+ <properties>
+ <help>Output plugin Azure Data Explorer</help>
+ </properties>
+ <children>
+ <node name="authentication">
+ <properties>
+ <help>Authentication parameters</help>
+ </properties>
+ <children>
+ <leafNode name="client-id">
+ <properties>
+ <help>Application client id</help>
+ <constraint>
+ <regex>[-_a-zA-Z0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>Client-id is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="client-secret">
+ <properties>
+ <help>Application client secret</help>
+ <constraint>
+ <regex>[-_a-zA-Z0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>Client-secret is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="tenant-id">
+ <properties>
+ <help>Set tenant id</help>
+ <constraint>
+ <regex>[-_a-zA-Z0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>Tenant-id is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="database">
+ <properties>
+ <help>Remote database name [REQUIRED]</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Remote database name</description>
+ </valueHelp>
+ <constraint>
+ <regex>[-_a-zA-Z0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>Database is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="group-metrics">
+ <properties>
+ <help>Type of metrics grouping when push to Azure Data Explorer</help>
+ <completionHelp>
+ <list>single-table table-per-metric</list>
+ </completionHelp>
+ <valueHelp>
+ <format>single-table</format>
+ <description>Metrics stores in one table</description>
+ </valueHelp>
+ <valueHelp>
+ <format>table-per-metric</format>
+ <description>One table per gorups of metric by the metric name</description>
+ </valueHelp>
+ <constraint>
+ <regex>(single-table|table-per-metric)</regex>
+ </constraint>
+ </properties>
+ <defaultValue>table-per-metric</defaultValue>
+ </leafNode>
+ <leafNode name="table">
+ <properties>
+ <help>Name of the single table [Only if set group-metrics single-table]</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Table name</description>
+ </valueHelp>
+ <constraint>
+ <regex>[-_a-zA-Z0-9]+</regex>
+ </constraint>
+ <constraintErrorMessage>Table is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ #include <include/monitoring/url.xml.i>
+ </children>
+ </node>
<leafNode name="bucket">
<properties>
<help>Remote bucket</help>
@@ -85,19 +173,128 @@
</properties>
<defaultValue>all</defaultValue>
</leafNode>
- <leafNode name="url">
+ <node name="prometheus-client">
<properties>
- <help>Remote URL [REQUIRED]</help>
- <valueHelp>
- <format>url</format>
- <description>Remote URL to InfluxDB v2</description>
- </valueHelp>
- <constraint>
- <regex>(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}?(\/.*)?</regex>
- </constraint>
- <constraintErrorMessage>Incorrect URL format.</constraintErrorMessage>
+ <help>Output plugin Prometheus client</help>
</properties>
- </leafNode>
+ <children>
+ <node name="authentication">
+ <properties>
+ <help>HTTP basic authentication parameters</help>
+ </properties>
+ <children>
+ <leafNode name="username">
+ <properties>
+ <help>Authentication username</help>
+ </properties>
+ </leafNode>
+ <leafNode name="password">
+ <properties>
+ <help>Authentication password</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Authentication password</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="allow-from">
+ <properties>
+ <help>Networks allowed to query this server</help>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IP address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <multi/>
+ <constraint>
+ <validator name="ip-prefix"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="listen-address">
+ <properties>
+ <help>Local IP addresses to listen on</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 address to listen for incoming connections</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address to listen for incoming connections</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4-address"/>
+ <validator name="ipv6-address"/>
+ <validator name="ipv6-link-local"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="metric-version">
+ <properties>
+ <help>Metric version control mapping from Telegraf to Prometheus format</help>
+ <valueHelp>
+ <format>u32:1-2</format>
+ <description>Metric version (default: 2)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-2"/>
+ </constraint>
+ </properties>
+ <defaultValue>2</defaultValue>
+ </leafNode>
+ #include <include/port-number.xml.i>
+ <leafNode name="port">
+ <defaultValue>9273</defaultValue>
+ </leafNode>
+ </children>
+ </node>
+ <node name="splunk">
+ <properties>
+ <help>Output plugin Splunk</help>
+ </properties>
+ <children>
+ <node name="authentication">
+ <properties>
+ <help>HTTP basic authentication parameters</help>
+ </properties>
+ <children>
+ <leafNode name="token">
+ <properties>
+ <help>Authorization token</help>
+ </properties>
+ </leafNode>
+ <leafNode name="insecure">
+ <properties>
+ <help>Use TLS but skip host validation</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <leafNode name="url">
+ <properties>
+ <help>Remote URL [REQUIRED]</help>
+ <valueHelp>
+ <format>url</format>
+ <description>Remote URL to Splunk collector</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(http(s?):\/\/.*):(\d*)\/?(.*)</regex>
+ </constraint>
+ <constraintErrorMessage>Incorrect URL format</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ #include <include/monitoring/url.xml.i>
#include <include/port-number.xml.i>
<leafNode name="port">
<defaultValue>8086</defaultValue>
diff --git a/interface-definitions/ssh.xml.in b/interface-definitions/ssh.xml.in
index 8edbad110..126183162 100644
--- a/interface-definitions/ssh.xml.in
+++ b/interface-definitions/ssh.xml.in
@@ -61,6 +61,78 @@
<valueless/>
</properties>
</leafNode>
+ <node name="dynamic-protection">
+ <properties>
+ <help>Allow dynamic protection</help>
+ </properties>
+ <children>
+ <leafNode name="block-time">
+ <properties>
+ <help>Block source IP in seconds. Subsequent blocks increase by a factor of 1.5</help>
+ <valueHelp>
+ <format>u32:1-65535</format>
+ <description>Time interval in seconds for blocking</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-65535"/>
+ </constraint>
+ </properties>
+ <defaultValue>120</defaultValue>
+ </leafNode>
+ <leafNode name="detect-time">
+ <properties>
+ <help>Remember source IP in seconds before reset their score</help>
+ <valueHelp>
+ <format>u32:1-65535</format>
+ <description>Time interval in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-65535"/>
+ </constraint>
+ </properties>
+ <defaultValue>1800</defaultValue>
+ </leafNode>
+ <leafNode name="threshold">
+ <properties>
+ <help>Block source IP when their cumulative attack score exceeds threshold</help>
+ <valueHelp>
+ <format>u32:1-65535</format>
+ <description>Threshold score</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-65535"/>
+ </constraint>
+ </properties>
+ <defaultValue>30</defaultValue>
+ </leafNode>
+ <leafNode name="allow-from">
+ <properties>
+ <help>Always allow inbound connections from these systems</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>Address to match against</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv4net</format>
+ <description>IPv4 address and prefix length</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address to match against</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-address"/>
+ <validator name="ip-prefix"/>
+ </constraint>
+ <multi/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<leafNode name="key-exchange">
<properties>
<help>Allowed key exchange (KEX) algorithms</help>
diff --git a/interface-definitions/system-frr.xml.in b/interface-definitions/system-frr.xml.in
new file mode 100644
index 000000000..9fe23ed75
--- /dev/null
+++ b/interface-definitions/system-frr.xml.in
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interfaceDefinition>
+ <node name="system">
+ <children>
+ <node name="frr" owner="${vyos_conf_scripts_dir}/system_frr.py">
+ <properties>
+ <help>Configure FRR parameters</help>
+ <!-- Before components that use FRR -->
+ <priority>150</priority>
+ </properties>
+ <children>
+ <leafNode name="bmp">
+ <properties>
+ <help>Enable BGP Monitoring Protocol support</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="irdp">
+ <properties>
+ <help>Enable ICMP Router Discovery Protocol support</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <node name="snmp">
+ <properties>
+ <help>Enable SNMP integration for next daemons</help>
+ </properties>
+ <children>
+ <leafNode name="bgpd">
+ <properties>
+ <help>BGP</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="isisd">
+ <properties>
+ <help>IS-IS</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="ldpd">
+ <properties>
+ <help>LDP</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="ospf6d">
+ <properties>
+ <help>OSPFv3</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="ospfd">
+ <properties>
+ <help>OSPFv2</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="ripd">
+ <properties>
+ <help>RIP</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="zebra">
+ <properties>
+ <help>Zebra (IP routing manager)</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/interface-definitions/vpn_openconnect.xml.in b/interface-definitions/vpn_openconnect.xml.in
index 7981c3fa2..21b47125d 100644
--- a/interface-definitions/vpn_openconnect.xml.in
+++ b/interface-definitions/vpn_openconnect.xml.in
@@ -51,6 +51,82 @@
</children>
</node>
#include <include/auth-local-users.xml.i>
+ <node name="local-users">
+ <children>
+ <tagNode name="username">
+ <children>
+ <node name="otp">
+ <properties>
+ <help>2FA OTP authentication parameters</help>
+ </properties>
+ <children>
+ <leafNode name="key">
+ <properties>
+ <help>Token Key Secret key for the token algorithm (see RFC 4226)</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>OTP key in hex-encoded format</description>
+ </valueHelp>
+ <constraint>
+ <regex>[a-fA-F0-9]{20,10000}</regex>
+ </constraint>
+ <constraintErrorMessage>Key name must only include hex characters and be at least 20 characters long</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ <leafNode name="otp-length">
+ <properties>
+ <help>Number of digits in OTP code</help>
+ <valueHelp>
+ <format>u32:6-8</format>
+ <description>Number of digits in OTP code</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 6-8"/>
+ </constraint>
+ <constraintErrorMessage>Number of digits in OTP code must be between 6 and 8</constraintErrorMessage>
+ </properties>
+ <defaultValue>6</defaultValue>
+ </leafNode>
+ <leafNode name="interval">
+ <properties>
+ <help>Time tokens interval in seconds</help>
+ <valueHelp>
+ <format>u32:5-86400</format>
+ <description>Time tokens interval in seconds.</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 5-86400"/>
+ </constraint>
+ <constraintErrorMessage>Time token interval must be between 5 and 86400 seconds</constraintErrorMessage>
+ </properties>
+ <defaultValue>30</defaultValue>
+ </leafNode>
+ <leafNode name="token-type">
+ <properties>
+ <help>Token type</help>
+ <valueHelp>
+ <format>hotp-time</format>
+ <description>Time-based OTP algorithm</description>
+ </valueHelp>
+ <valueHelp>
+ <format>hotp-event</format>
+ <description>Event-based OTP algorithm</description>
+ </valueHelp>
+ <constraint>
+ <regex>(hotp-time|hotp-event)</regex>
+ </constraint>
+ <completionHelp>
+ <list>hotp-time hotp-event</list>
+ </completionHelp>
+ </properties>
+ <defaultValue>hotp-time</defaultValue>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </tagNode>
+ </children>
+ </node>
#include <include/radius-server-ipv4.xml.i>
<node name="radius">
<children>
diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in
index 14c31fa8a..25a573887 100644
--- a/interface-definitions/vrf.xml.in
+++ b/interface-definitions/vrf.xml.in
@@ -28,6 +28,22 @@
<children>
#include <include/interface/description.xml.i>
#include <include/interface/disable.xml.i>
+ <node name="ip">
+ <properties>
+ <help>IPv4 routing parameters</help>
+ </properties>
+ <children>
+ #include <include/interface/disable-forwarding.xml.i>
+ </children>
+ </node>
+ <node name="ipv6">
+ <properties>
+ <help>IPv6 routing parameters</help>
+ </properties>
+ <children>
+ #include <include/interface/disable-forwarding.xml.i>
+ </children>
+ </node>
<node name="protocols">
<properties>
<help>Routing protocol parameters</help>
diff --git a/op-mode-definitions/containers.xml.in b/op-mode-definitions/container.xml.in
index 48501bd84..fa66402dc 100644
--- a/op-mode-definitions/containers.xml.in
+++ b/op-mode-definitions/container.xml.in
@@ -11,7 +11,7 @@
<properties>
<help>Pull a new image for container</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --pull "${4}"</command>
+ <command>sudo podman image pull "${4}"</command>
</tagNode>
</children>
</node>
@@ -44,7 +44,7 @@
<script>sudo podman image ls -q</script>
</completionHelp>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --remove "${4}"</command>
+ <command>sudo podman image rm --force "${4}"</command>
</tagNode>
</children>
</node>
@@ -100,13 +100,13 @@
<properties>
<help>Show containers</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --all</command>
+ <command>sudo podman ps --all</command>
<children>
<leafNode name="image">
<properties>
<help>Show container image</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --image</command>
+ <command>sudo podman image ls</command>
</leafNode>
<tagNode name="log">
<properties>
@@ -121,7 +121,7 @@
<properties>
<help>Show available container networks</help>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --networks</command>
+ <command>sudo podman network ls</command>
</leafNode>
</children>
</node>
@@ -167,7 +167,7 @@
<path>container name</path>
</completionHelp>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/containers_op.py --update "${4}"</command>
+ <command>if cli-shell-api existsActive container name "$4"; then sudo podman pull $(cli-shell-api returnActiveValue container name "$4" image); else echo "Container $4 does not exist"; fi</command>
</tagNode>
</children>
</node>
diff --git a/op-mode-definitions/monitor-log.xml.in b/op-mode-definitions/monitor-log.xml.in
index 6f82ce611..7ecce4f78 100644
--- a/op-mode-definitions/monitor-log.xml.in
+++ b/op-mode-definitions/monitor-log.xml.in
@@ -16,18 +16,18 @@
</node>
<node name="dhcp">
<properties>
- <help>Show log for Dynamic Host Control Protocol (DHCP)</help>
+ <help>Monitor last lines of Dynamic Host Control Protocol (DHCP)</help>
</properties>
<children>
<node name="server">
<properties>
- <help>Show log for DHCP server</help>
+ <help>Monitor last lines of DHCP server</help>
</properties>
<command>journalctl --no-hostname --follow --boot --unit isc-dhcp-server.service</command>
</node>
<node name="client">
<properties>
- <help>Show DHCP client logs</help>
+ <help>Monitor last lines of DHCP client</help>
</properties>
<command>journalctl --no-hostname --follow --boot --unit "dhclient@*.service"</command>
<children>
@@ -46,18 +46,18 @@
</node>
<node name="dhcpv6">
<properties>
- <help>Show log for Dynamic Host Control Protocol IPv6 (DHCPv6)</help>
+ <help>Monitor last lines of Dynamic Host Control Protocol IPv6 (DHCPv6)</help>
</properties>
<children>
<node name="server">
<properties>
- <help>Show log for DHCPv6 server</help>
+ <help>Monitor last lines of DHCPv6 server</help>
</properties>
<command>journalctl --no-hostname --follow --boot --unit isc-dhcp-server6.service</command>
</node>
<node name="client">
<properties>
- <help>Show DHCPv6 client logs</help>
+ <help>Monitor last lines of DHCPv6 client</help>
</properties>
<command>journalctl --no-hostname --follow --boot --unit "dhcp6c@*.service"</command>
<children>
@@ -74,12 +74,24 @@
</node>
</children>
</node>
+ <leafNode name="flow-accounting">
+ <properties>
+ <help>Monitor last lines of flow-accounting log</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --follow --unit uacctd.service</command>
+ </leafNode>
<leafNode name="kernel">
<properties>
<help>Monitor last lines of Linux Kernel log</help>
</properties>
<command>journalctl --no-hostname --boot --follow --dmesg</command>
</leafNode>
+ <leafNode name="nhrp">
+ <properties>
+ <help>Monitor last lines of NHRP log</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --unit opennhrp.service</command>
+ </leafNode>
<node name="pppoe">
<properties>
<help>Monitor last lines of PPPoE log</help>
diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in
index 954369712..76879e5d6 100644
--- a/op-mode-definitions/show-log.xml.in
+++ b/op-mode-definitions/show-log.xml.in
@@ -139,6 +139,12 @@
</tagNode>
</children>
</node>
+ <leafNode name="flow-accounting">
+ <properties>
+ <help>Show log for flow-accounting</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --unit uacctd.service</command>
+ </leafNode>
<leafNode name="https">
<properties>
<help>Show log for HTTPs</help>
@@ -195,6 +201,12 @@
</properties>
<command>egrep -i "kernel:.*\[NAT-[A-Z]{3,}-[0-9]+(-MASQ)?\]" $(find /var/log -maxdepth 1 -type f -name messages\* | sort -t. -k2nr)</command>
</leafNode>
+ <leafNode name="nhrp">
+ <properties>
+ <help>Show log for NHRP</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --unit opennhrp.service</command>
+ </leafNode>
<node name="openvpn">
<properties>
<help>Show log for OpenVPN</help>
diff --git a/op-mode-definitions/show-system.xml.in b/op-mode-definitions/show-system.xml.in
index 0f852164e..68b473bc1 100644
--- a/op-mode-definitions/show-system.xml.in
+++ b/op-mode-definitions/show-system.xml.in
@@ -166,9 +166,9 @@
</leafNode>
<leafNode name="uptime">
<properties>
- <help>Show how long the system has been up</help>
+ <help>Show system uptime and load averages</help>
</properties>
- <command>uptime</command>
+ <command>${vyos_op_scripts_dir}/show_uptime.py</command>
</leafNode>
</children>
</node>
diff --git a/op-mode-definitions/traceroute.xml.in b/op-mode-definitions/traceroute.xml.in
index e3217235c..aba0f45e3 100644
--- a/op-mode-definitions/traceroute.xml.in
+++ b/op-mode-definitions/traceroute.xml.in
@@ -2,226 +2,22 @@
<interfaceDefinition>
<tagNode name="traceroute">
<properties>
- <help>Track network path to node</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>/usr/bin/traceroute "$2"</command>
- </tagNode>
- <node name="traceroute">
- <properties>
- <help>Track network path to node</help>
+ <help>Trace network path to node</help>
<completionHelp>
<list>&lt;hostname&gt; &lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
</completionHelp>
</properties>
+ <command>${vyos_op_scripts_dir}/traceroute.py ${@:2}</command>
<children>
- <tagNode name="ipv4">
+ <leafNode name="node.tag">
<properties>
- <help>Explicitly use IPv4 when tracing the path</help>
+ <help>Traceroute options</help>
<completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt;</list>
+ <script>${vyos_op_scripts_dir}/traceroute.py --get-options "${COMP_WORDS[@]}"</script>
</completionHelp>
</properties>
- <command>/usr/bin/traceroute -4 "$3"</command>
- <children>
- <node name="tcp">
- <properties>
- <help>Route tracing and port detection using TCP</help>
- </properties>
- <command>sudo /usr/bin/tcptraceroute "$3" </command>
- <children>
- <tagNode name="port">
- <properties>
- <help>TCP port to connect to for path tracing</help>
- <completionHelp>
- <list>0-65535</list>
- </completionHelp>
- </properties>
- <command>sudo /usr/bin/tcptraceroute "$3" $6</command>
- </tagNode>
- </children>
- </node>
- </children>
- </tagNode>
- <tagNode name="ipv6">
- <properties>
- <help>Explicitly use IPv6 when tracing the path</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>/usr/bin/traceroute -6 "$3"</command>
- <children>
- <node name="tcp">
- <properties>
- <help>Use TCP/IPv6 packets to perform a traceroute</help>
- </properties>
- <command>sudo /usr/bin/tcptraceroute6 "$3" </command>
- <children>
- <tagNode name="port">
- <properties>
- <help>TCP port to connect to for path tracing</help>
- <completionHelp>
- <list>0-65535</list>
- </completionHelp>
- </properties>
- <command>sudo /usr/bin/tcptraceroute6 "$3" $6</command>
- </tagNode>
- </children>
- </node>
- </children>
- </tagNode>
- <tagNode name="vrf">
- <properties>
- <help>Track network path to specified node via given VRF</help>
- <completionHelp>
- <path>vrf name</path>
- </completionHelp>
- </properties>
- <children>
- <!-- we need an empty tagNode to pass in a plain fqdn/ip address and
- let traceroute decide how to handle this parameter -->
- <tagNode name="">
- <properties>
- <help>Track network path to specified node via given VRF</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/traceroute "$4"</command>
- </tagNode>
- <tagNode name="ipv4">
- <properties>
- <help>Explicitly use IPv4 when tracing the path via given VRF</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/traceroute -4 "$5"</command>
- <children>
- <node name="tcp">
- <properties>
- <help>Route tracing and port detection using TCP</help>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/tcptraceroute "$5" </command>
- <children>
- <tagNode name="port">
- <properties>
- <help>TCP port to connect to for path tracing</help>
- <completionHelp>
- <list>0-65535</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/tcptraceroute "$5" $8</command>
- </tagNode>
- </children>
- </node>
- </children>
- </tagNode>
- <tagNode name="ipv6">
- <properties>
- <help>Explicitly use IPv6 when tracing the path via given VRF</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/traceroute -6 "$5"</command>
- <children>
- <node name="tcp">
- <properties>
- <help>Use TCP/IPv6 packets to perform a traceroute</help>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/tcptraceroute6 "$5" </command>
- <children>
- <tagNode name="port">
- <properties>
- <help>TCP port to connect to for path tracing</help>
- <completionHelp>
- <list>0-65535</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$3" /usr/bin/tcptraceroute6 "$5" $8</command>
- </tagNode>
- </children>
- </node>
- </children>
- </tagNode>
- </children>
- </tagNode>
- </children>
- </node>
- <node name="monitor">
- <children>
- <tagNode name="traceroute">
- <properties>
- <help>Monitor path to destination in realtime</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>/usr/bin/mtr "$3"</command>
- </tagNode>
- <node name="traceroute">
- <children>
- <tagNode name="ipv4">
- <properties>
- <help>IPv4 fully qualified domain name (FQDN)</help>
- <completionHelp>
- <list>&lt;fqdn&gt;</list>
- </completionHelp>
- </properties>
- <command>/usr/bin/mtr -4 "$4"</command>
- </tagNode>
- <tagNode name="ipv6">
- <properties>
- <help>IPv6 fully qualified domain name (FQDN)</help>
- <completionHelp>
- <list>&lt;fqdn&gt;</list>
- </completionHelp>
- </properties>
- <command>/usr/bin/mtr -6 "$4"</command>
- </tagNode>
- <tagNode name="vrf">
- <properties>
- <help>Monitor path to destination in realtime via given VRF</help>
- <completionHelp>
- <path>vrf name</path>
- </completionHelp>
- </properties>
- <children>
- <tagNode name="ipv4">
- <properties>
- <help>IPv4 fully qualified domain name (FQDN)</help>
- <completionHelp>
- <list>&lt;fqdn&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$4" /usr/bin/mtr -4 "$6"</command>
- </tagNode>
- <tagNode name="ipv6">
- <properties>
- <help>IPv6 fully qualified domain name (FQDN)</help>
- <completionHelp>
- <list>&lt;fqdn&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$4" /usr/bin/mtr -6 "$6"</command>
- </tagNode>
- <tagNode name="">
- <properties>
- <help>Track network path to specified node via given VRF</help>
- <completionHelp>
- <list>&lt;hostname&gt; &lt;x.x.x.x&gt; &lt;h:h:h:h:h:h:h:h&gt;</list>
- </completionHelp>
- </properties>
- <command>sudo ip vrf exec "$4" /usr/bin/mtr "$5"</command>
- </tagNode>
- </children>
- </tagNode>
- </children>
- </node>
+ <command>${vyos_op_scripts_dir}/traceroute.py ${@:2}</command>
+ </leafNode>
</children>
- </node>
+ </tagNode>
</interfaceDefinition>
diff --git a/python/vyos/cpu.py b/python/vyos/cpu.py
new file mode 100644
index 000000000..a0ef864be
--- /dev/null
+++ b/python/vyos/cpu.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Retrieves (or at least attempts to retrieve) the total number of real CPU cores
+installed in a Linux system.
+
+The issue of core count is complicated by existence of SMT, e.g. Intel's Hyper Threading.
+GNU nproc returns the number of LOGICAL cores,
+which is 2x of the real cores if SMT is enabled.
+
+The idea is to find all physical CPUs and add up their core counts.
+It has special cases for x86_64 and MAY work correctly on other architectures,
+but nothing is certain.
+"""
+
+import re
+
+
+def _read_cpuinfo():
+ with open('/proc/cpuinfo', 'r') as f:
+ return f.readlines()
+
+def _split_line(l):
+ l = l.strip()
+ parts = re.split(r'\s*:\s*', l)
+ return (parts[0], ":".join(parts[1:]))
+
+def _find_cpus(cpuinfo_lines):
+ # Make a dict because it's more convenient to work with later,
+ # when we need to find physicall distinct CPUs there.
+ cpus = {}
+
+ cpu_number = 0
+
+ for l in cpuinfo_lines:
+ key, value = _split_line(l)
+ if key == 'processor':
+ cpu_number = value
+ cpus[cpu_number] = {}
+ else:
+ cpus[cpu_number][key] = value
+
+ return cpus
+
+def _find_physical_cpus():
+ cpus = _find_cpus(_read_cpuinfo())
+
+ phys_cpus = {}
+
+ for num in cpus:
+ if 'physical id' in cpus[num]:
+ # On at least some architectures, CPUs in different sockets
+ # have different 'physical id' field, e.g. on x86_64.
+ phys_id = cpus[num]['physical id']
+ if phys_id not in phys_cpus:
+ phys_cpus[phys_id] = cpus[num]
+ else:
+ # On other architectures, e.g. on ARM, there's no such field.
+ # We just assume they are different CPUs,
+ # whether single core ones or cores of physical CPUs.
+ phys_cpus[num] = cpu[num]
+
+ return phys_cpus
+
+def get_cpus():
+ """ Returns a list of /proc/cpuinfo entries that belong to different CPUs.
+ """
+ cpus_dict = _find_physical_cpus()
+ return list(cpus_dict.values())
+
+def get_core_count():
+ """ Returns the total number of physical CPU cores
+ (even if Hyper-Threading or another SMT is enabled and has inflated
+ the number of cores in /proc/cpuinfo)
+ """
+ physical_cpus = _find_physical_cpus()
+
+ core_count = 0
+
+ for num in physical_cpus:
+ # Some architectures, e.g. x86_64, include a field for core count.
+ # Since we found unique physical CPU entries, we can sum their core counts.
+ if 'cpu cores' in physical_cpus[num]:
+ core_count += int(physical_cpus[num]['cpu cores'])
+ else:
+ core_count += 1
+
+ return core_count
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index ff8623592..04fd44173 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -49,6 +49,15 @@ def parse_rule(rule_conf, fw_name, rule_id, ip_name):
if states:
output.append(f'ct state {{{states}}}')
+ if 'connection_status' in rule_conf and rule_conf['connection_status']:
+ status = rule_conf['connection_status']
+ if status['nat'] == 'destination':
+ nat_status = '{dnat}'
+ output.append(f'ct status {nat_status}')
+ if status['nat'] == 'source':
+ nat_status = '{snat}'
+ output.append(f'ct status {nat_status}')
+
if 'protocol' in rule_conf and rule_conf['protocol'] != 'all':
proto = rule_conf['protocol']
operator = ''
diff --git a/smoketest/configs/firewall-big b/smoketest/configs.no-load/firewall-big
index 94b0c6dd5..94b0c6dd5 100644
--- a/smoketest/configs/firewall-big
+++ b/smoketest/configs.no-load/firewall-big
diff --git a/smoketest/configs/bgp-big-as-cloud b/smoketest/configs/bgp-big-as-cloud
index 10660ec87..65819256e 100644
--- a/smoketest/configs/bgp-big-as-cloud
+++ b/smoketest/configs/bgp-big-as-cloud
@@ -982,6 +982,10 @@ policy {
}
}
}
+ set {
+ as-path-exclude "100 200 300"
+ as-path-prepend "64512 64512 64512"
+ }
}
rule 100 {
action deny
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 37e6b9e7a..b8f944575 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -173,6 +173,45 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_output = cmd(f'sudo nft list chain {table} {chain}')
self.assertTrue('jump VYOS_STATE_POLICY' in nftables_output)
+ def test_state_and_status_rules(self):
+ self.cli_set(['firewall', 'name', 'smoketest', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'state', 'related', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'reject'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'state', 'invalid', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'state', 'new', 'enable'])
+
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'connection-status', 'nat', 'destination'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'state', 'new', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'connection-status', 'nat', 'source'])
+
+ self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['iifname "eth0"', 'jump NAME_smoketest'],
+ ['ct state { established, related }', 'return'],
+ ['ct state { invalid }', 'reject'],
+ ['ct state { new }', 'ct status { dnat }', 'return'],
+ ['ct state { established, new }', 'ct status { snat }', 'return'],
+ ['smoketest default-action', 'drop']
+ ]
+
+ nftables_output = cmd('sudo nft list table ip filter')
+
+ for search in nftables_search:
+ matched = False
+ for line in nftables_output.split("\n"):
+ if all(item in line for item in search):
+ matched = True
+ break
+ self.assertTrue(matched, msg=search)
+
def test_sysfs(self):
for name, conf in sysfs_config.items():
paths = glob(conf['sysfs'])
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index b232a2241..e8c6ff19b 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 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
@@ -800,27 +800,28 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
'10' : {
'action' : 'deny',
'set' : {
- 'aggregator-as' : '1234567890',
- 'aggregator-ip' : '10.255.255.0',
- 'as-path-exclude' : '1234',
- 'as-path-prepend' : '1234567890 987654321',
- 'atomic-aggregate' : '',
- 'distance' : '110',
- 'extcommunity-bw' : '20000',
- 'extcommunity-rt' : '123:456',
- 'extcommunity-soo' : '456:789',
- 'ipv6-next-hop-global': '2001::1',
- 'ipv6-next-hop-local' : 'fe80::1',
- 'ip-next-hop' : '192.168.1.1',
- 'large-community' : '100:200:300',
- 'local-preference' : '500',
- 'metric' : '150',
- 'metric-type' : 'type-1',
- 'origin' : 'incomplete',
- 'originator-id' : '172.16.10.1',
- 'src' : '100.0.0.1',
- 'tag' : '65530',
- 'weight' : '2',
+ 'aggregator-as' : '1234567890',
+ 'aggregator-ip' : '10.255.255.0',
+ 'as-path-exclude' : '1234',
+ 'as-path-prepend' : '1234567890 987654321',
+ 'as-path-prepend-last-as' : '5',
+ 'atomic-aggregate' : '',
+ 'distance' : '110',
+ 'extcommunity-bw' : '20000',
+ 'extcommunity-rt' : '123:456',
+ 'extcommunity-soo' : '456:789',
+ 'ipv6-next-hop-global' : '2001::1',
+ 'ipv6-next-hop-local' : 'fe80::1',
+ 'ip-next-hop' : '192.168.1.1',
+ 'large-community' : '100:200:300',
+ 'local-preference' : '500',
+ 'metric' : '150',
+ 'metric-type' : 'type-1',
+ 'origin' : 'incomplete',
+ 'originator-id' : '172.16.10.1',
+ 'src' : '100.0.0.1',
+ 'tag' : '65530',
+ 'weight' : '2',
},
},
},
@@ -848,6 +849,13 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
'evpn-vni' : '1234',
},
},
+ '20' : {
+ 'action' : 'permit',
+ 'set' : {
+ 'evpn-gateway-ipv4' : '192.0.2.99',
+ 'evpn-gateway-ipv6' : '2001:db8:f00::1',
+ },
+ },
},
},
}
@@ -958,9 +966,9 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
if 'aggregator-ip' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'aggregator', 'ip', rule_config['set']['aggregator-ip']])
if 'as-path-exclude' in rule_config['set']:
- self.cli_set(path + ['rule', rule, 'set', 'as-path-exclude', rule_config['set']['as-path-exclude']])
+ self.cli_set(path + ['rule', rule, 'set', 'as-path', 'exclude', rule_config['set']['as-path-exclude']])
if 'as-path-prepend' in rule_config['set']:
- self.cli_set(path + ['rule', rule, 'set', 'as-path-prepend', rule_config['set']['as-path-prepend']])
+ self.cli_set(path + ['rule', rule, 'set', 'as-path', 'prepend', rule_config['set']['as-path-prepend']])
if 'atomic-aggregate' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'atomic-aggregate'])
if 'distance' in rule_config['set']:
@@ -995,6 +1003,10 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
self.cli_set(path + ['rule', rule, 'set', 'tag', rule_config['set']['tag']])
if 'weight' in rule_config['set']:
self.cli_set(path + ['rule', rule, 'set', 'weight', rule_config['set']['weight']])
+ if 'evpn-gateway-ipv4' in rule_config['set']:
+ self.cli_set(path + ['rule', rule, 'set', 'evpn', 'gateway', 'ipv4', rule_config['set']['evpn-gateway-ipv4']])
+ if 'evpn-gateway-ipv6' in rule_config['set']:
+ self.cli_set(path + ['rule', rule, 'set', 'evpn', 'gateway', 'ipv6', rule_config['set']['evpn-gateway-ipv6']])
self.cli_commit()
@@ -1118,6 +1130,8 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
tmp += 'as-path exclude ' + rule_config['set']['as-path-exclude']
elif 'as-path-prepend' in rule_config['set']:
tmp += 'as-path prepend ' + rule_config['set']['as-path-prepend']
+ elif 'as-path-prepend-last-as' in rule_config['set']:
+ tmp += 'as-path prepend last-as' + rule_config['set']['as-path-prepend-last-as']
elif 'atomic-aggregate' in rule_config['set']:
tmp += 'atomic-aggregate'
elif 'distance' in rule_config['set']:
@@ -1152,6 +1166,10 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
tmp += 'tag ' + rule_config['set']['tag']
elif 'weight' in rule_config['set']:
tmp += 'weight ' + rule_config['set']['weight']
+ elif 'vpn-gateway-ipv4' in rule_config['set']:
+ tmp += 'evpn gateway ipv4 ' + rule_config['set']['vpn-gateway-ipv4']
+ elif 'vpn-gateway-ipv6' in rule_config['set']:
+ tmp += 'evpn gateway ipv6 ' + rule_config['set']['vpn-gateway-ipv6']
self.assertIn(tmp, config)
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 9035f0832..e2d70f289 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 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,15 +23,26 @@ from vyos.util import cmd
mark = '100'
table_mark_offset = 0x7fffffff
table_id = '101'
+interface = 'eth0'
+interface_ip = '172.16.10.1/24'
class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
- def setUp(self):
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'address', '172.16.10.1/24'])
- self.cli_set(['protocols', 'static', 'table', '101', 'route', '0.0.0.0/0', 'interface', 'eth0'])
+ @classmethod
+ def setUpClass(cls):
+ super(TestPolicyRoute, cls).setUpClass()
+
+ cls.cli_set(cls, ['interfaces', 'ethernet', interface, 'address', interface_ip])
+ cls.cli_set(cls, ['protocols', 'static', 'table', table_id, 'route', '0.0.0.0/0', 'interface', interface])
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.cli_delete(cls, ['interfaces', 'ethernet', interface, 'address', interface_ip])
+ cls.cli_delete(cls, ['protocols', 'static', 'table', table_id])
+
+ super(TestPolicyRoute, cls).tearDownClass()
def tearDown(self):
- self.cli_delete(['interfaces', 'ethernet', 'eth0'])
- self.cli_delete(['protocols', 'static'])
+ self.cli_delete(['interfaces', 'ethernet', interface, 'policy'])
self.cli_delete(['policy', 'route'])
self.cli_delete(['policy', 'route6'])
self.cli_commit()
@@ -41,14 +52,14 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'destination', 'address', '172.16.10.10'])
self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'set', 'mark', mark])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'policy', 'route', 'smoketest'])
+ self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
self.cli_commit()
mark_hex = "{0:#010x}".format(int(mark))
nftables_search = [
- ['iifname "eth0"', 'jump VYOS_PBR_smoketest'],
+ [f'iifname "{interface}"','jump VYOS_PBR_smoketest'],
['ip daddr 172.16.10.10', 'ip saddr 172.16.20.10', 'meta mark set ' + mark_hex],
]
@@ -72,8 +83,8 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'destination', 'port', '8888'])
self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'set', 'table', table_id])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'policy', 'route', 'smoketest'])
- self.cli_set(['interfaces', 'ethernet', 'eth0', 'policy', 'route6', 'smoketest6'])
+ self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+ self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
self.cli_commit()
@@ -82,7 +93,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
# IPv4
nftables_search = [
- ['iifname "eth0"', 'jump VYOS_PBR_smoketest'],
+ [f'iifname "{interface}"', 'jump VYOS_PBR_smoketest'],
['tcp flags & (syn | ack) == syn', 'tcp dport { 8888 }', 'meta mark set ' + mark_hex]
]
@@ -99,7 +110,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
# IPv6
nftables6_search = [
- ['iifname "eth0"', 'jump VYOS_PBR6_smoketest'],
+ [f'iifname "{interface}"', 'jump VYOS_PBR6_smoketest'],
['meta l4proto { tcp, udp }', 'th dport { 8888 }', 'meta mark set ' + mark_hex]
]
diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py
index 6f92457b2..9c0c93779 100755
--- a/smoketest/scripts/cli/test_protocols_bgp.py
+++ b/smoketest/scripts/cli/test_protocols_bgp.py
@@ -887,6 +887,7 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
remote_asn = str(int(ASN) + 150)
neighbor = '192.0.2.1'
peer_group = 'bar'
+ interface = 'eth0'
self.cli_set(base_path + ['local-as', ASN])
self.cli_set(base_path + ['neighbor', neighbor, 'remote-as', remote_asn])
@@ -898,6 +899,20 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
self.cli_delete(base_path + ['neighbor', neighbor, 'remote-as'])
+ # re-test with interface based peer-group
+ self.cli_set(base_path + ['neighbor', interface, 'interface', 'peer-group', peer_group])
+ self.cli_set(base_path + ['neighbor', interface, 'interface', 'remote-as', 'external'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['neighbor', interface, 'interface', 'remote-as'])
+
+ # re-test with interface based v6only peer-group
+ self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'peer-group', peer_group])
+ self.cli_set(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as', 'external'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['neighbor', interface, 'interface', 'v6only', 'remote-as'])
+
self.cli_commit()
frrconfig = self.getFRRconfig(f'router bgp {ASN}')
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index 77ad5bc0d..0b029dd00 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.py
@@ -213,5 +213,54 @@ class TestServiceSSH(VyOSUnitTestSHIM.TestCase):
usernames = [x[0] for x in getpwall()]
self.assertNotIn(test_user, usernames)
+ def test_ssh_dynamic_protection(self):
+ # check sshguard service
+
+ SSHGUARD_CONFIG = '/etc/sshguard/sshguard.conf'
+ SSHGUARD_WHITELIST = '/etc/sshguard/whitelist'
+ SSHGUARD_PROCESS = 'sshguard'
+ block_time = '123'
+ detect_time = '1804'
+ port = '22'
+ threshold = '10'
+ allow_list = ['192.0.2.0/24', '2001:db8::/48']
+
+ self.cli_set(base_path + ['dynamic-protection', 'block-time', block_time])
+ self.cli_set(base_path + ['dynamic-protection', 'detect-time', detect_time])
+ self.cli_set(base_path + ['dynamic-protection', 'threshold', threshold])
+ for allow in allow_list:
+ self.cli_set(base_path + ['dynamic-protection', 'allow-from', allow])
+
+ # commit changes
+ self.cli_commit()
+
+ # Check configured port
+ tmp = get_config_value('Port')
+ self.assertIn(port, tmp)
+
+ # Check sshgurad service
+ self.assertTrue(process_named_running(SSHGUARD_PROCESS))
+
+ sshguard_lines = [
+ f'THRESHOLD={threshold}',
+ f'BLOCK_TIME={block_time}',
+ f'DETECTION_TIME={detect_time}'
+ ]
+
+ tmp_sshguard_conf = read_file(SSHGUARD_CONFIG)
+ for line in sshguard_lines:
+ self.assertIn(line, tmp_sshguard_conf)
+
+ tmp_whitelist_conf = read_file(SSHGUARD_WHITELIST)
+ for allow in allow_list:
+ self.assertIn(allow, tmp_whitelist_conf)
+
+ # Delete service ssh dynamic-protection
+ # but not service ssh itself
+ self.cli_delete(base_path + ['dynamic-protection'])
+ self.cli_commit()
+
+ self.assertFalse(process_named_running(SSHGUARD_PROCESS))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py
index 5a73ebc7d..a6eef3fb6 100755
--- a/smoketest/scripts/cli/test_system_flow-accounting.py
+++ b/smoketest/scripts/cli/test_system_flow-accounting.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 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,6 +20,8 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.ifconfig import Section
+from vyos.template import bracketize_ipv6
+from vyos.template import is_ipv6
from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
@@ -103,14 +105,12 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
agent_address = '192.0.2.2'
sflow_server = {
- '1.2.3.4' : {
- },
- '5.6.7.8' : {
- 'port' : '6000'
- }
+ '1.2.3.4' : { },
+ '5.6.7.8' : { 'port' : '6000' },
}
self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32'])
+ self.cli_set(['interfaces', 'dummy', dummy_if, 'address', source_address + '/32'])
self.cli_set(base_path + ['disable-imt'])
# You need to configure at least one interface for flow-accounting
@@ -155,6 +155,54 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['interfaces', 'dummy', dummy_if])
+ def test_sflow_ipv6(self):
+ sampling_rate = '100'
+ sflow_server = {
+ '2001:db8::1' : { },
+ '2001:db8::2' : { 'port' : '6000' },
+ }
+
+ self.cli_set(base_path + ['disable-imt'])
+
+ # You need to configure at least one interface for flow-accounting
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ for interface in Section.interfaces('ethernet'):
+ self.cli_set(base_path + ['interface', interface])
+
+
+ # You need to configure at least one sFlow or NetFlow protocol, or not
+ # set "disable-imt" for flow-accounting
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(base_path + ['sflow', 'sampling-rate', sampling_rate])
+ for server, server_config in sflow_server.items():
+ self.cli_set(base_path + ['sflow', 'server', server])
+ if 'port' in server_config:
+ self.cli_set(base_path + ['sflow', 'server', server, 'port', server_config['port']])
+
+ # commit changes
+ self.cli_commit()
+
+ uacctd = read_file(uacctd_conf)
+
+ # when 'disable-imt' is not configured on the CLI it must be present
+ self.assertNotIn(f'imt_path: /tmp/uacctd.pipe', uacctd)
+ self.assertNotIn(f'imt_mem_pools_number: 169', uacctd)
+ self.assertNotIn(f'plugins: memory', uacctd)
+
+ for server, server_config in sflow_server.items():
+ tmp_srv = server
+ if is_ipv6(tmp_srv):
+ tmp_srv = tmp_srv.replace(':', '.')
+
+ if 'port' in server_config:
+ self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}', uacctd)
+ else:
+ self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}:6343', uacctd)
+ self.assertIn(f'sampling_rate[sf_{tmp_srv}]: {sampling_rate}', uacctd)
+
def test_netflow(self):
engine_id = '33'
max_flows = '667'
@@ -173,14 +221,13 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
tmo_udp = '10'
netflow_server = {
- '11.22.33.44' : {
- },
- '55.66.77.88' : {
- 'port' : '6000'
- }
+ '11.22.33.44' : { },
+ '55.66.77.88' : { 'port' : '6000' },
+ '2001:db8::1' : { },
}
self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32'])
+ self.cli_set(['interfaces', 'dummy', dummy_if, 'address', source_address + '/32'])
for interface in Section.interfaces('ethernet'):
self.cli_set(base_path + ['interface', interface])
@@ -217,23 +264,30 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
tmp = []
for server, server_config in netflow_server.items():
- tmp.append(f'nfprobe[nf_{server}]')
+ tmp_srv = server
+ if is_ipv6(tmp_srv):
+ tmp_srv = tmp_srv.replace(':', '.')
+ tmp.append(f'nfprobe[nf_{tmp_srv}]')
tmp.append('memory')
self.assertIn('plugins: ' + ','.join(tmp), uacctd)
for server, server_config in netflow_server.items():
- self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd)
- self.assertIn(f'nfprobe_maxflows[nf_{server}]: {max_flows}', uacctd)
- self.assertIn(f'sampling_rate[nf_{server}]: {sampling_rate}', uacctd)
- self.assertIn(f'nfprobe_source_ip[nf_{server}]: {source_address}', uacctd)
- self.assertIn(f'nfprobe_version[nf_{server}]: {version}', uacctd)
+ tmp_srv = server
+ if is_ipv6(tmp_srv):
+ tmp_srv = tmp_srv.replace(':', '.')
+
+ self.assertIn(f'nfprobe_engine[nf_{tmp_srv}]: {engine_id}', uacctd)
+ self.assertIn(f'nfprobe_maxflows[nf_{tmp_srv}]: {max_flows}', uacctd)
+ self.assertIn(f'sampling_rate[nf_{tmp_srv}]: {sampling_rate}', uacctd)
+ self.assertIn(f'nfprobe_source_ip[nf_{tmp_srv}]: {source_address}', uacctd)
+ self.assertIn(f'nfprobe_version[nf_{tmp_srv}]: {version}', uacctd)
if 'port' in server_config:
- self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}', uacctd)
+ self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {bracketize_ipv6(server)}', uacctd)
else:
- self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}:2055', uacctd)
+ self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {bracketize_ipv6(server)}:2055', uacctd)
- self.assertIn(f'nfprobe_timeouts[nf_{server}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd)
+ self.assertIn(f'nfprobe_timeouts[nf_{tmp_srv}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd)
self.cli_delete(['interfaces', 'dummy', dummy_if])
diff --git a/smoketest/scripts/cli/test_system_frr.py b/smoketest/scripts/cli/test_system_frr.py
new file mode 100755
index 000000000..331133ed4
--- /dev/null
+++ b/smoketest/scripts/cli/test_system_frr.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019-2020 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import re
+import unittest
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.util import read_file
+
+config_file = '/etc/frr/daemons'
+base_path = ['system', 'frr']
+
+
+def daemons_config_parse(daemons_config):
+ # create regex for parsing daemons options
+ regex_daemon_config = re.compile(
+ r'^(?P<daemon_name>\w+)_options="(?P<daemon_options>.*)"$', re.M)
+ # create empty dict for config
+ daemons_config_dict = {}
+ # fill dictionary with actual config
+ for daemon in regex_daemon_config.finditer(daemons_config):
+ daemon_name = daemon.group('daemon_name')
+ daemon_options = daemon.group('daemon_options')
+ daemons_config_dict[daemon_name] = daemon_options
+
+ # return daemons config
+ return (daemons_config_dict)
+
+
+class TestSystemFRR(VyOSUnitTestSHIM.TestCase):
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_frr_snmp_multipledaemons(self):
+ # test SNMP integration for multiple daemons
+ test_daemon_names = ['ospfd', 'bgpd']
+ for test_daemon_name in test_daemon_names:
+ self.cli_set(base_path + ['snmp', test_daemon_name])
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex for matching SNMP integration
+ regex_snmp = re.compile(r'^.* -M snmp.*$')
+ for (daemon_name, daemon_options) in daemons_config_dict.items():
+ snmp_enabled = regex_snmp.match(daemon_options)
+ if daemon_name in test_daemon_names:
+ self.assertTrue(snmp_enabled)
+ else:
+ self.assertFalse(snmp_enabled)
+
+ def test_frr_snmp_addandremove(self):
+ # test enabling and disabling of SNMP integration
+ test_daemon_names = ['ospfd', 'bgpd']
+ for test_daemon_name in test_daemon_names:
+ self.cli_set(base_path + ['snmp', test_daemon_name])
+ self.cli_commit()
+
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex for matching SNMP integration
+ regex_snmp = re.compile(r'^.* -M snmp.*$')
+ for test_daemon_name in test_daemon_names:
+ snmp_enabled = regex_snmp.match(
+ daemons_config_dict[test_daemon_name])
+ self.assertFalse(snmp_enabled)
+
+ def test_frr_snmp_empty(self):
+ # test empty config section
+ self.cli_set(base_path + ['snmp'])
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex for matching SNMP integration
+ regex_snmp = re.compile(r'^.* -M snmp.*$')
+ for daemon_options in daemons_config_dict.values():
+ snmp_enabled = regex_snmp.match(daemon_options)
+ self.assertFalse(snmp_enabled)
+
+ def test_frr_bmp(self):
+ # test BMP
+ self.cli_set(base_path + ['bmp'])
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex
+ regex_bmp = re.compile(r'^.* -M bmp.*$')
+ bmp_enabled = regex_bmp.match(daemons_config_dict['bgpd'])
+ self.assertTrue(bmp_enabled)
+
+ def test_frr_irdp(self):
+ # test IRDP
+ self.cli_set(base_path + ['irdp'])
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex
+ regex_irdp = re.compile(r'^.* -M irdp.*$')
+ irdp_enabled = regex_irdp.match(daemons_config_dict['zebra'])
+ self.assertTrue(irdp_enabled)
+
+ def test_frr_bmpandsnmp(self):
+ # test empty config section
+ self.cli_set(base_path + ['bmp'])
+ self.cli_set(base_path + ['snmp', 'bgpd'])
+ self.cli_commit()
+
+ # read the config file and check content
+ daemons_config = read_file(config_file)
+ daemons_config_dict = daemons_config_parse(daemons_config)
+ # prepare regex
+ regex_snmp = re.compile(r'^.* -M bmp.*$')
+ regex_snmp = re.compile(r'^.* -M snmp.*$')
+ bmp_enabled = regex_snmp.match(daemons_config_dict['bgpd'])
+ snmp_enabled = regex_snmp.match(daemons_config_dict['bgpd'])
+ self.assertTrue(bmp_enabled)
+ self.assertTrue(snmp_enabled)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2, failfast=True)
diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py
index ff18f7261..176c095fb 100755
--- a/smoketest/scripts/cli/test_vrf.py
+++ b/smoketest/scripts/cli/test_vrf.py
@@ -127,6 +127,9 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
for vrf in vrfs:
# Ensure VRF was created
self.assertIn(vrf, interfaces())
+ # Verify IP forwarding is 1 (enabled)
+ self.assertEqual(read_file(f'/proc/sys/net/ipv4/conf/{vrf}/forwarding'), '1')
+ self.assertEqual(read_file(f'/proc/sys/net/ipv6/conf/{vrf}/forwarding'), '1')
# Test for proper loopback IP assignment
for addr in loopbacks:
self.assertTrue(is_intf_addr_assigned(vrf, addr))
@@ -267,5 +270,26 @@ class VRFTest(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['interfaces', 'dummy', interface])
self.cli_commit()
+ def test_vrf_disable_forwarding(self):
+ table = '2000'
+ for vrf in vrfs:
+ base = base_path + ['name', vrf]
+ self.cli_set(base + ['table', table])
+ self.cli_set(base + ['ip', 'disable-forwarding'])
+ self.cli_set(base + ['ipv6', 'disable-forwarding'])
+ table = str(int(table) + 1)
+
+ # commit changes
+ self.cli_commit()
+
+ # Verify VRF configuration
+ loopbacks = ['127.0.0.1', '::1']
+ for vrf in vrfs:
+ # Ensure VRF was created
+ self.assertIn(vrf, interfaces())
+ # Verify IP forwarding is 0 (disabled)
+ self.assertEqual(read_file(f'/proc/sys/net/ipv4/conf/{vrf}/forwarding'), '0')
+ self.assertEqual(read_file(f'/proc/sys/net/ipv6/conf/{vrf}/forwarding'), '0')
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/bcast_relay.py b/src/conf_mode/bcast_relay.py
index d93a2a8f4..39a2971ce 100755
--- a/src/conf_mode/bcast_relay.py
+++ b/src/conf_mode/bcast_relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2020 VyOS maintainers and contributors
+# Copyright (C) 2017-2022 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
@@ -78,7 +78,7 @@ def generate(relay):
continue
config['instance'] = instance
- render(config_file_base + instance, 'bcast-relay/udp-broadcast-relay.tmpl',
+ render(config_file_base + instance, 'bcast-relay/udp-broadcast-relay.j2',
config)
return None
diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py
index aabf2bdf5..82289526f 100755
--- a/src/conf_mode/conntrack.py
+++ b/src/conf_mode/conntrack.py
@@ -101,9 +101,9 @@ def verify(conntrack):
return None
def generate(conntrack):
- render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.tmpl', conntrack)
- render(sysctl_file, 'conntrack/sysctl.conf.tmpl', conntrack)
- render(nftables_ct_file, 'conntrack/nftables-ct.tmpl', conntrack)
+ render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack)
+ render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack)
+ render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack)
# dry-run newly generated configuration
tmp = run(f'nft -c -f {nftables_ct_file}')
diff --git a/src/conf_mode/conntrack_sync.py b/src/conf_mode/conntrack_sync.py
index 34d1f7398..c4b2bb488 100755
--- a/src/conf_mode/conntrack_sync.py
+++ b/src/conf_mode/conntrack_sync.py
@@ -111,11 +111,12 @@ def generate(conntrack):
os.unlink(config_file)
return None
- render(config_file, 'conntrackd/conntrackd.conf.tmpl', conntrack)
+ render(config_file, 'conntrackd/conntrackd.conf.j2', conntrack)
return None
def apply(conntrack):
+ systemd_service = 'conntrackd.service'
if not conntrack:
# Failover mechanism daemon should be indicated that it no longer needs
# to execute conntrackd actions on transition. This is only required
@@ -123,7 +124,7 @@ def apply(conntrack):
if process_named_running('conntrackd'):
resync_vrrp()
- call('systemctl stop conntrackd.service')
+ call(f'systemctl stop {systemd_service}')
return None
# Failover mechanism daemon should be indicated that it needs to execute
@@ -132,7 +133,7 @@ def apply(conntrack):
if not process_named_running('conntrackd'):
resync_vrrp()
- call('systemctl restart conntrackd.service')
+ call(f'systemctl reload-or-restart {systemd_service}')
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/containers.py b/src/conf_mode/container.py
index 1cc6f5a35..2110fd9e0 100755
--- a/src/conf_mode/containers.py
+++ b/src/conf_mode/container.py
@@ -15,13 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import json
from ipaddress import ip_address
from ipaddress import ip_network
from time import sleep
from json import dumps as json_write
+from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
@@ -110,15 +110,21 @@ def verify(container):
if 'image' not in container_config:
raise ConfigError(f'Container image for "{name}" is mandatory!')
- # verify container image exists locally
- image = container_config['image']
-
# Check if requested container image exists locally. If it does not
- # exist locally - inform the user.
+ # exist locally - inform the user. This is required as there is a
+ # shared container image storage accross all VyOS images. A user can
+ # delete a container image from the system, boot into another version
+ # of VyOS and then it would fail to boot. This is to prevent any
+ # configuration error when container images are deleted from the
+ # global storage. A per image local storage would be a super waste
+ # of diskspace as there will be a full copy (up tu several GB/image)
+ # on upgrade. This is the "cheapest" and fastest solution in terms
+ # of image upgrade and deletion.
+ image = container_config['image']
if run(f'podman image exists {image}') != 0:
- raise ConfigError(f'Image "{image}" used in contianer "{name}" does not exist '\
- f'locally.\nPlease use "add container image {image}" to add it '\
- 'to the system!')
+ Warning(f'Image "{image}" used in contianer "{name}" does not exist '\
+ f'locally. Please use "add container image {image}" to add it '\
+ f'to the system! Container "{name}" will not be started!')
if 'network' in container_config:
if len(container_config['network']) > 1:
@@ -254,8 +260,8 @@ def generate(container):
write_file(f'/etc/cni/net.d/{network}.conflist', json_write(tmp, indent=2))
- render(config_containers_registry, 'containers/registries.conf.j2', container)
- render(config_containers_storage, 'containers/storage.conf.j2', container)
+ render(config_containers_registry, 'container/registries.conf.j2', container)
+ render(config_containers_storage, 'container/storage.conf.j2', container)
return None
@@ -279,6 +285,11 @@ def apply(container):
for name, container_config in container['name'].items():
image = container_config['image']
+ if run(f'podman image exists {image}') != 0:
+ # container image does not exist locally - user already got
+ # informed by a WARNING in verfiy() - bail out early
+ continue
+
if 'disable' in container_config:
# check if there is a container by that name running
tmp = _cmd('podman ps -a --format "{{.Names}}"')
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index de78d53a8..6924bf555 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -327,8 +327,8 @@ def generate(firewall):
else:
firewall['cleanup_commands'] = cleanup_commands(firewall)
- render(nftables_conf, 'firewall/nftables.tmpl', firewall)
- render(nftables_defines_conf, 'firewall/nftables-defines.tmpl', firewall)
+ render(nftables_conf, 'firewall/nftables.j2', firewall)
+ render(nftables_defines_conf, 'firewall/nftables-defines.j2', firewall)
return None
def apply_sysfs(firewall):
diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py
index 25bf54790..7750c1247 100755
--- a/src/conf_mode/flow_accounting_conf.py
+++ b/src/conf_mode/flow_accounting_conf.py
@@ -22,6 +22,7 @@ import ipaddress
from ipaddress import ip_address
+from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.ifconfig import Section
@@ -109,6 +110,9 @@ def _nftables_config(configured_ifaces, direction, length=None):
iface_prefix = "o" if direction == "egress" else "i"
rule_definition = f'{iface_prefix}ifname "{iface}" counter log group 2 snaplen {length} queue-threshold 100 comment "FLOW_ACCOUNTING_RULE"'
nftable_commands.append(f'nft insert rule {nftables_table} {nftables_chain} {rule_definition}')
+ # Also add IPv6 ingres logging
+ if nftables_table == nftables_nflog_table:
+ nftable_commands.append(f'nft insert rule ip6 {nftables_table} {nftables_chain} {rule_definition}')
# change nftables
for command in nftable_commands:
@@ -172,7 +176,7 @@ def verify(flow_config):
if interface not in Section.interfaces():
# Changed from error to warning to allow adding dynamic interfaces
# and interface templates
- print(f'Warning: Interface "{interface}" is not presented in the system')
+ Warning(f'Interface "{interface}" is not presented in the system')
# check sFlow configuration
if 'sflow' in flow_config:
@@ -200,7 +204,13 @@ def verify(flow_config):
if 'agent_address' in flow_config['sflow']:
tmp = flow_config['sflow']['agent_address']
if not is_addr_assigned(tmp):
- print(f'Warning: Configured "sflow agent-address {tmp}" does not exist in the system!')
+ raise ConfigError(f'Configured "sflow agent-address {tmp}" does not exist in the system!')
+
+ # Check if configured netflow source-address exist in the system
+ if 'source_address' in flow_config['sflow']:
+ if not is_addr_assigned(flow_config['sflow']['source_address']):
+ tmp = flow_config['sflow']['source_address']
+ raise ConfigError(f'Configured "sflow source-address {tmp}" does not exist on the system!')
# check NetFlow configuration
if 'netflow' in flow_config:
@@ -212,7 +222,7 @@ def verify(flow_config):
if 'source_address' in flow_config['netflow']:
if not is_addr_assigned(flow_config['netflow']['source_address']):
tmp = flow_config['netflow']['source_address']
- print(f'Warning: Configured "netflow source-address {tmp}" does not exist on the system!')
+ raise ConfigError(f'Configured "netflow source-address {tmp}" does not exist on the system!')
# Check if engine-id compatible with selected protocol version
if 'engine_id' in flow_config['netflow']:
@@ -239,8 +249,8 @@ def generate(flow_config):
if not flow_config:
return None
- render(uacctd_conf_path, 'pmacct/uacctd.conf.tmpl', flow_config)
- render(systemd_override, 'pmacct/override.conf.tmpl', flow_config)
+ render(uacctd_conf_path, 'pmacct/uacctd.conf.j2', flow_config)
+ render(systemd_override, 'pmacct/override.conf.j2', flow_config)
# Reload systemd manager configuration
call('systemctl daemon-reload')
diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py
index 7d51bb393..e14050dd3 100755
--- a/src/conf_mode/high-availability.py
+++ b/src/conf_mode/high-availability.py
@@ -28,7 +28,6 @@ from vyos.template import render
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos.util import call
-from vyos.util import is_systemd_service_running
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -152,7 +151,7 @@ def generate(ha):
if not ha:
return None
- render(VRRP.location['config'], 'high-availability/keepalived.conf.tmpl', ha)
+ render(VRRP.location['config'], 'high-availability/keepalived.conf.j2', ha)
return None
def apply(ha):
@@ -161,12 +160,7 @@ def apply(ha):
call(f'systemctl stop {service_name}')
return None
- # XXX: T3944 - reload keepalived configuration if service is already running
- # to not cause any service disruption when applying changes.
- if is_systemd_service_running(service_name):
- call(f'systemctl reload {service_name}')
- else:
- call(f'systemctl restart {service_name}')
+ call(f'systemctl reload-or-restart {service_name}')
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/http-api.py b/src/conf_mode/http-api.py
index 00f3d4f7f..4a7906c17 100755
--- a/src/conf_mode/http-api.py
+++ b/src/conf_mode/http-api.py
@@ -117,7 +117,7 @@ def generate(http_api):
with open(api_conf_file, 'w') as f:
json.dump(http_api, f, indent=2)
- render(systemd_service, 'https/vyos-http-api.service.tmpl', http_api)
+ render(systemd_service, 'https/vyos-http-api.service.j2', http_api)
return None
def apply(http_api):
diff --git a/src/conf_mode/https.py b/src/conf_mode/https.py
index 37fa36797..3057357fc 100755
--- a/src/conf_mode/https.py
+++ b/src/conf_mode/https.py
@@ -214,8 +214,8 @@ def generate(https):
'certbot': certbot
}
- render(config_file, 'https/nginx.default.tmpl', data)
- render(systemd_override, 'https/override.conf.tmpl', https)
+ render(config_file, 'https/nginx.default.j2', data)
+ render(systemd_override, 'https/override.conf.j2', https)
return None
def apply(https):
diff --git a/src/conf_mode/igmp_proxy.py b/src/conf_mode/igmp_proxy.py
index 37df3dc92..de6a51c64 100755
--- a/src/conf_mode/igmp_proxy.py
+++ b/src/conf_mode/igmp_proxy.py
@@ -96,7 +96,7 @@ def generate(igmp_proxy):
Warning('IGMP Proxy will be deactivated because it is disabled')
return None
- render(config_file, 'igmp-proxy/igmpproxy.conf.tmpl', igmp_proxy)
+ render(config_file, 'igmp-proxy/igmpproxy.conf.j2', igmp_proxy)
return None
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 26daa8381..e2fdc7a42 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -92,7 +92,7 @@ def generate(pppoe):
return None
# Create PPP configuration files
- render(config_pppoe, 'pppoe/peer.tmpl', pppoe, permission=0o640)
+ render(config_pppoe, 'pppoe/peer.j2', pppoe, permission=0o640)
return None
diff --git a/src/conf_mode/lldp.py b/src/conf_mode/lldp.py
index 2bb615eb7..c703c1fe0 100755
--- a/src/conf_mode/lldp.py
+++ b/src/conf_mode/lldp.py
@@ -111,8 +111,8 @@ def generate(lldp):
if lldp is None:
return
- render(config_file, 'lldp/lldpd.tmpl', lldp)
- render(vyos_config_file, 'lldp/vyos.conf.tmpl', lldp)
+ render(config_file, 'lldp/lldpd.j2', lldp)
+ render(vyos_config_file, 'lldp/vyos.conf.j2', lldp)
def apply(lldp):
systemd_service = 'lldpd.service'
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index 8aaebf9ff..85819a77e 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -181,7 +181,7 @@ def verify(nat):
return None
def generate(nat):
- render(nftables_nat_config, 'firewall/nftables-nat.tmpl', nat)
+ render(nftables_nat_config, 'firewall/nftables-nat.j2', nat)
# dry-run newly generated configuration
tmp = run(f'nft -c -f {nftables_nat_config}')
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 1cd15811f..0972151a0 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -146,8 +146,8 @@ def verify(nat):
return None
def generate(nat):
- render(nftables_nat66_config, 'firewall/nftables-nat66.tmpl', nat, permission=0o755)
- render(ndppd_config, 'ndppd/ndppd.conf.tmpl', nat, permission=0o755)
+ render(nftables_nat66_config, 'firewall/nftables-nat66.j2', nat, permission=0o755)
+ render(ndppd_config, 'ndppd/ndppd.conf.j2', nat, permission=0o755)
return None
def apply(nat):
diff --git a/src/conf_mode/policy-route.py b/src/conf_mode/policy-route.py
index 09d181d43..5de341beb 100755
--- a/src/conf_mode/policy-route.py
+++ b/src/conf_mode/policy-route.py
@@ -204,7 +204,7 @@ def generate(policy):
else:
policy['cleanup_commands'] = cleanup_commands(policy)
- render(nftables_conf, 'firewall/nftables-policy.tmpl', policy)
+ render(nftables_conf, 'firewall/nftables-policy.j2', policy)
return None
def apply_table_marks(policy):
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index a9173ab87..cd46cbcb4 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -169,6 +169,16 @@ def verify(bgp):
peer_group = peer_config['peer_group']
if 'remote_as' in peer_config and 'remote_as' in bgp['peer_group'][peer_group]:
raise ConfigError(f'Peer-group member "{peer}" cannot override remote-as of peer-group "{peer_group}"!')
+ if 'interface' in peer_config:
+ if 'peer_group' in peer_config['interface']:
+ peer_group = peer_config['interface']['peer_group']
+ if 'remote_as' in peer_config['interface'] and 'remote_as' in bgp['peer_group'][peer_group]:
+ raise ConfigError(f'Peer-group member "{peer}" cannot override remote-as of peer-group "{peer_group}"!')
+ if 'v6only' in peer_config['interface']:
+ if 'peer_group' in peer_config['interface']['v6only']:
+ peer_group = peer_config['interface']['v6only']['peer_group']
+ if 'remote_as' in peer_config['interface']['v6only'] and 'remote_as' in bgp['peer_group'][peer_group]:
+ raise ConfigError(f'Peer-group member "{peer}" cannot override remote-as of peer-group "{peer_group}"!')
# Only checks for ipv4 and ipv6 neighbors
# Check if neighbor address is assigned as system interface address
diff --git a/src/conf_mode/protocols_nhrp.py b/src/conf_mode/protocols_nhrp.py
index ff8ae8eeb..56939955d 100755
--- a/src/conf_mode/protocols_nhrp.py
+++ b/src/conf_mode/protocols_nhrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 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
@@ -81,10 +81,15 @@ def verify(nhrp):
for map_name, map_conf in nhrp_conf['dynamic_map'].items():
if 'nbma_domain_name' not in map_conf:
raise ConfigError(f'nbma-domain-name missing on dynamic-map {map_name} on tunnel {name}')
+
+ if 'cisco_authentication' in nhrp_conf:
+ if len(nhrp_conf['cisco_authentication']) > 8:
+ raise ConfigError('Maximum length of the secret is 8 characters!')
+
return None
def generate(nhrp):
- render(opennhrp_conf, 'nhrp/opennhrp.conf.tmpl', nhrp)
+ render(opennhrp_conf, 'nhrp/opennhrp.conf.j2', nhrp)
return None
def apply(nhrp):
@@ -104,8 +109,8 @@ def apply(nhrp):
if rule_handle:
remove_nftables_rule('ip filter', 'VYOS_FW_OUTPUT', rule_handle)
- action = 'reload-or-restart' if nhrp and 'tunnel' in nhrp else 'stop'
- run(f'systemctl {action} opennhrp')
+ action = 'restart' if nhrp and 'tunnel' in nhrp else 'stop'
+ run(f'systemctl {action} opennhrp.service')
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py
index 51050e702..a2e411e49 100755
--- a/src/conf_mode/service_console-server.py
+++ b/src/conf_mode/service_console-server.py
@@ -81,7 +81,7 @@ def generate(proxy):
if not proxy:
return None
- render(config_file, 'conserver/conserver.conf.tmpl', proxy)
+ render(config_file, 'conserver/conserver.conf.j2', proxy)
if 'device' in proxy:
for device, device_config in proxy['device'].items():
if 'ssh' not in device_config:
@@ -92,7 +92,7 @@ def generate(proxy):
'port' : device_config['ssh']['port'],
}
render(dropbear_systemd_file.format(**tmp),
- 'conserver/dropbear@.service.tmpl', tmp)
+ 'conserver/dropbear@.service.j2', tmp)
return None
diff --git a/src/conf_mode/service_ids_fastnetmon.py b/src/conf_mode/service_ids_fastnetmon.py
index 67edeb630..ae7e582ec 100755
--- a/src/conf_mode/service_ids_fastnetmon.py
+++ b/src/conf_mode/service_ids_fastnetmon.py
@@ -67,8 +67,8 @@ def generate(fastnetmon):
return
- render(config_file, 'ids/fastnetmon.tmpl', fastnetmon)
- render(networks_list, 'ids/fastnetmon_networks_list.tmpl', fastnetmon)
+ render(config_file, 'ids/fastnetmon.j2', fastnetmon)
+ render(networks_list, 'ids/fastnetmon_networks_list.j2', fastnetmon)
return None
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index 2ebee8018..559d1bcd5 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -296,10 +296,10 @@ def generate(ipoe):
if not ipoe:
return None
- render(ipoe_conf, 'accel-ppp/ipoe.config.tmpl', ipoe)
+ render(ipoe_conf, 'accel-ppp/ipoe.config.j2', ipoe)
if ipoe['auth_mode'] == 'local':
- render(ipoe_chap_secrets, 'accel-ppp/chap-secrets.ipoe.tmpl', ipoe)
+ render(ipoe_chap_secrets, 'accel-ppp/chap-secrets.ipoe.j2', ipoe)
os.chmod(ipoe_chap_secrets, S_IRUSR | S_IWUSR | S_IRGRP)
else:
diff --git a/src/conf_mode/service_mdns-repeater.py b/src/conf_mode/service_mdns-repeater.py
index d31a0c49e..2383a53fb 100755
--- a/src/conf_mode/service_mdns-repeater.py
+++ b/src/conf_mode/service_mdns-repeater.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2020 VyOS maintainers and contributors
+# Copyright (C) 2017-2022 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
@@ -92,7 +92,7 @@ def generate(mdns):
if len(mdns['interface']) < 2:
return None
- render(config_file, 'mdns-repeater/avahi-daemon.tmpl', mdns)
+ render(config_file, 'mdns-repeater/avahi-daemon.j2', mdns)
return None
def apply(mdns):
diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py
index 8a972b9fe..daf75d740 100755
--- a/src/conf_mode/service_monitoring_telegraf.py
+++ b/src/conf_mode/service_monitoring_telegraf.py
@@ -99,6 +99,32 @@ def get_config(config=None):
monitoring['interfaces_ethernet'] = get_interfaces('ethernet', vlan=False)
monitoring['nft_chains'] = get_nft_filter_chains()
+ if 'authentication' in monitoring or \
+ 'url' in monitoring:
+ monitoring['influxdb_configured'] = True
+
+ # Redefine azure group-metrics 'single-table' and 'table-per-metric'
+ if 'azure_data_explorer' in monitoring:
+ if 'single-table' in monitoring['azure_data_explorer']['group_metrics']:
+ monitoring['azure_data_explorer']['group_metrics'] = 'SingleTable'
+ else:
+ monitoring['azure_data_explorer']['group_metrics'] = 'TablePerMetric'
+ # Set azure env
+ if 'authentication' in monitoring['azure_data_explorer']:
+ auth_config = monitoring['azure_data_explorer']['authentication']
+ if {'client_id', 'client_secret', 'tenant_id'} <= set(auth_config):
+ os.environ['AZURE_CLIENT_ID'] = auth_config['client_id']
+ os.environ['AZURE_CLIENT_SECRET'] = auth_config['client_secret']
+ os.environ['AZURE_TENANT_ID'] = auth_config['tenant_id']
+
+ # Ignore default XML values if config doesn't exists
+ # Delete key from dict
+ if not conf.exists(base + ['prometheus-client']):
+ del monitoring['prometheus_client']
+
+ if not conf.exists(base + ['azure-data-explorer']):
+ del monitoring['azure_data_explorer']
+
return monitoring
def verify(monitoring):
@@ -106,13 +132,41 @@ def verify(monitoring):
if not monitoring:
return None
- if 'authentication' not in monitoring or \
- 'organization' not in monitoring['authentication'] or \
- 'token' not in monitoring['authentication']:
- raise ConfigError(f'Authentication "organization and token" are mandatory!')
+ if 'influxdb_configured' in monitoring:
+ if 'authentication' not in monitoring or \
+ 'organization' not in monitoring['authentication'] or \
+ 'token' not in monitoring['authentication']:
+ raise ConfigError(f'Authentication "organization and token" are mandatory!')
+
+ if 'url' not in monitoring:
+ raise ConfigError(f'Monitoring "url" is mandatory!')
+
+ # Verify azure-data-explorer
+ if 'azure_data_explorer' in monitoring:
+ if 'authentication' not in monitoring['azure_data_explorer'] or \
+ 'client_id' not in monitoring['azure_data_explorer']['authentication'] or \
+ 'client_secret' not in monitoring['azure_data_explorer']['authentication'] or \
+ 'tenant_id' not in monitoring['azure_data_explorer']['authentication']:
+ raise ConfigError(f'Authentication "client-id, client-secret and tenant-id" are mandatory!')
+
+ if 'database' not in monitoring['azure_data_explorer']:
+ raise ConfigError(f'Monitoring "database" is mandatory!')
+
+ if 'url' not in monitoring['azure_data_explorer']:
+ raise ConfigError(f'Monitoring "url" is mandatory!')
+
+ if monitoring['azure_data_explorer']['group_metrics'] == 'SingleTable' and \
+ 'table' not in monitoring['azure_data_explorer']:
+ raise ConfigError(f'Monitoring "table" name for single-table mode is mandatory!')
+
+ # Verify Splunk
+ if 'splunk' in monitoring:
+ if 'authentication' not in monitoring['splunk'] or \
+ 'token' not in monitoring['splunk']['authentication']:
+ raise ConfigError(f'Authentication "organization and token" are mandatory!')
- if 'url' not in monitoring:
- raise ConfigError(f'Monitoring "url" is mandatory!')
+ if 'url' not in monitoring['splunk']:
+ raise ConfigError(f'Monitoring splunk "url" is mandatory!')
return None
@@ -145,10 +199,10 @@ def generate(monitoring):
os.mkdir(custom_scripts_dir)
# Render telegraf configuration and systemd override
- render(config_telegraf, 'monitoring/telegraf.tmpl', monitoring)
- render(systemd_telegraf_service, 'monitoring/systemd_vyos_telegraf_service.tmpl', monitoring)
- render(systemd_override, 'monitoring/override.conf.tmpl', monitoring, permission=0o640)
- render(syslog_telegraf, 'monitoring/syslog_telegraf.tmpl', monitoring)
+ render(config_telegraf, 'monitoring/telegraf.j2', monitoring)
+ render(systemd_telegraf_service, 'monitoring/systemd_vyos_telegraf_service.j2', monitoring)
+ render(systemd_override, 'monitoring/override.conf.j2', monitoring, permission=0o640)
+ render(syslog_telegraf, 'monitoring/syslog_telegraf.j2', monitoring)
chown(base_dir, 'telegraf', 'telegraf')
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index 1f31d132d..6086ef859 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -88,10 +88,10 @@ def generate(pppoe):
for vlan_range in pppoe['interface'][iface]['vlan_range']:
pppoe['interface'][iface]['regex'].append(range_to_regex(vlan_range))
- render(pppoe_conf, 'accel-ppp/pppoe.config.tmpl', pppoe)
+ render(pppoe_conf, 'accel-ppp/pppoe.config.j2', pppoe)
if dict_search('authentication.mode', pppoe) == 'local':
- render(pppoe_chap_secrets, 'accel-ppp/chap-secrets.config_dict.tmpl',
+ render(pppoe_chap_secrets, 'accel-ppp/chap-secrets.config_dict.j2',
pppoe, permission=0o640)
else:
if os.path.exists(pppoe_chap_secrets):
diff --git a/src/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py
index 9afcdd63e..71b758399 100755
--- a/src/conf_mode/service_router-advert.py
+++ b/src/conf_mode/service_router-advert.py
@@ -101,7 +101,7 @@ def generate(rtradv):
if not rtradv:
return None
- render(config_file, 'router-advert/radvd.conf.tmpl', rtradv, permission=0o644)
+ render(config_file, 'router-advert/radvd.conf.j2', rtradv, permission=0o644)
return None
def apply(rtradv):
diff --git a/src/conf_mode/service_upnp.py b/src/conf_mode/service_upnp.py
index d21b31990..36f3e18a7 100755
--- a/src/conf_mode/service_upnp.py
+++ b/src/conf_mode/service_upnp.py
@@ -135,7 +135,7 @@ def generate(upnpd):
if os.path.isfile(config_file):
os.unlink(config_file)
- render(config_file, 'firewall/upnpd.conf.tmpl', upnpd)
+ render(config_file, 'firewall/upnpd.conf.j2', upnpd)
def apply(upnpd):
systemd_service_name = 'miniupnpd.service'
diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py
index a16cc4aeb..32af31bde 100755
--- a/src/conf_mode/service_webproxy.py
+++ b/src/conf_mode/service_webproxy.py
@@ -61,7 +61,7 @@ def generate_sg_localdb(category, list_type, role, proxy):
user=user_group, group=user_group)
# temporary config file, deleted after generation
- render(sg_tmp_file, 'squid/sg_acl.conf.tmpl', tmp,
+ render(sg_tmp_file, 'squid/sg_acl.conf.j2', tmp,
user=user_group, group=user_group)
call(f'su - {user_group} -c "squidGuard -d -c {sg_tmp_file} -C {db_file}"')
@@ -166,8 +166,8 @@ def generate(proxy):
if not proxy:
return None
- render(squid_config_file, 'squid/squid.conf.tmpl', proxy)
- render(squidguard_config_file, 'squid/squidGuard.conf.tmpl', proxy)
+ render(squid_config_file, 'squid/squid.conf.j2', proxy)
+ render(squidguard_config_file, 'squid/squidGuard.conf.j2', proxy)
cat_dict = {
'local-block' : 'domains',
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index e35bb8a0c..5cd24db32 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -270,15 +270,15 @@ def generate(snmp):
call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" privacy plaintext-password > /dev/null')
# Write client config file
- render(config_file_client, 'snmp/etc.snmp.conf.tmpl', snmp)
+ render(config_file_client, 'snmp/etc.snmp.conf.j2', snmp)
# Write server config file
- render(config_file_daemon, 'snmp/etc.snmpd.conf.tmpl', snmp)
+ render(config_file_daemon, 'snmp/etc.snmpd.conf.j2', snmp)
# Write access rights config file
- render(config_file_access, 'snmp/usr.snmpd.conf.tmpl', snmp)
+ render(config_file_access, 'snmp/usr.snmpd.conf.j2', snmp)
# Write access rights config file
- render(config_file_user, 'snmp/var.snmpd.conf.tmpl', snmp)
+ render(config_file_user, 'snmp/var.snmpd.conf.j2', snmp)
# Write daemon configuration file
- render(systemd_override, 'snmp/override.conf.tmpl', snmp)
+ render(systemd_override, 'snmp/override.conf.j2', snmp)
return None
@@ -293,7 +293,15 @@ def apply(snmp):
call(f'systemctl restart {systemd_service}')
# Enable AgentX in FRR
- call('vtysh -c "configure terminal" -c "agentx" >/dev/null')
+ # This should be done for each daemon individually because common command
+ # works only if all the daemons started with SNMP support
+ frr_daemons_list = [
+ 'bgpd', 'ospf6d', 'ospfd', 'ripd', 'ripngd', 'isisd', 'ldpd', 'zebra'
+ ]
+ for frr_daemon in frr_daemons_list:
+ call(
+ f'vtysh -c "configure terminal" -d {frr_daemon} -c "agentx" >/dev/null'
+ )
return None
diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py
index 487e8c229..28669694b 100755
--- a/src/conf_mode/ssh.py
+++ b/src/conf_mode/ssh.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2021 VyOS maintainers and contributors
+# Copyright (C) 2018-2022 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
@@ -33,6 +33,9 @@ airbag.enable()
config_file = r'/run/sshd/sshd_config'
systemd_override = r'/etc/systemd/system/ssh.service.d/override.conf'
+sshguard_config_file = '/etc/sshguard/sshguard.conf'
+sshguard_whitelist = '/etc/sshguard/whitelist'
+
key_rsa = '/etc/ssh/ssh_host_rsa_key'
key_dsa = '/etc/ssh/ssh_host_dsa_key'
key_ed25519 = '/etc/ssh/ssh_host_ed25519_key'
@@ -54,6 +57,11 @@ def get_config(config=None):
# pass config file path - used in override template
ssh['config_file'] = config_file
+ # Ignore default XML values if config doesn't exists
+ # Delete key from dict
+ if not conf.exists(base + ['dynamic-protection']):
+ del ssh['dynamic_protection']
+
return ssh
def verify(ssh):
@@ -86,6 +94,10 @@ def generate(ssh):
render(config_file, 'ssh/sshd_config.j2', ssh)
render(systemd_override, 'ssh/override.conf.j2', ssh)
+
+ if 'dynamic_protection' in ssh:
+ render(sshguard_config_file, 'ssh/sshguard_config.j2', ssh)
+ render(sshguard_whitelist, 'ssh/sshguard_whitelist.j2', ssh)
# Reload systemd manager configuration
call('systemctl daemon-reload')
@@ -95,7 +107,12 @@ def apply(ssh):
if not ssh:
# SSH access is removed in the commit
call('systemctl stop ssh.service')
+ call('systemctl stop sshguard.service')
return None
+ if 'dynamic_protection' not in ssh:
+ call('systemctl stop sshguard.service')
+ else:
+ call('systemctl restart sshguard.service')
call('systemctl restart ssh.service')
return None
diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py
index c9c6aa187..c717286ae 100755
--- a/src/conf_mode/system-login.py
+++ b/src/conf_mode/system-login.py
@@ -197,7 +197,7 @@ def generate(login):
pass
if 'radius' in login:
- render(radius_config_file, 'login/pam_radius_auth.conf.tmpl', login,
+ render(radius_config_file, 'login/pam_radius_auth.conf.j2', login,
permission=0o600, user='root', group='root')
else:
if os.path.isfile(radius_config_file):
@@ -241,7 +241,7 @@ def apply(login):
#
# XXX: Should we deny using root at all?
home_dir = getpwnam(user).pw_dir
- render(f'{home_dir}/.ssh/authorized_keys', 'login/authorized_keys.tmpl',
+ render(f'{home_dir}/.ssh/authorized_keys', 'login/authorized_keys.j2',
user_config, permission=0o600,
formater=lambda _: _.replace("&quot;", '"'),
user=user, group='users')
diff --git a/src/conf_mode/system-logs.py b/src/conf_mode/system-logs.py
index e6296656d..c71938a79 100755
--- a/src/conf_mode/system-logs.py
+++ b/src/conf_mode/system-logs.py
@@ -57,13 +57,13 @@ def generate(logs_config):
logrotate_atop = dict_search('logrotate.atop', logs_config)
# generate new config file for atop
syslog.debug('Adding logrotate config for atop')
- render(logrotate_atop_file, 'logs/logrotate/vyos-atop.tmpl', logrotate_atop)
+ render(logrotate_atop_file, 'logs/logrotate/vyos-atop.j2', logrotate_atop)
# get configuration for logrotate rsyslog
logrotate_rsyslog = dict_search('logrotate.messages', logs_config)
# generate new config file for rsyslog
syslog.debug('Adding logrotate config for rsyslog')
- render(logrotate_rsyslog_file, 'logs/logrotate/vyos-rsyslog.tmpl',
+ render(logrotate_rsyslog_file, 'logs/logrotate/vyos-rsyslog.j2',
logrotate_rsyslog)
diff --git a/src/conf_mode/system-option.py b/src/conf_mode/system-option.py
index b1c63e316..36dbf155b 100755
--- a/src/conf_mode/system-option.py
+++ b/src/conf_mode/system-option.py
@@ -74,8 +74,8 @@ def verify(options):
return None
def generate(options):
- render(curlrc_config, 'system/curlrc.tmpl', options)
- render(ssh_config, 'system/ssh_config.tmpl', options)
+ render(curlrc_config, 'system/curlrc.j2', options)
+ render(ssh_config, 'system/ssh_config.j2', options)
return None
def apply(options):
diff --git a/src/conf_mode/system-syslog.py b/src/conf_mode/system-syslog.py
index 309b4bdb0..a9d3bbe31 100755
--- a/src/conf_mode/system-syslog.py
+++ b/src/conf_mode/system-syslog.py
@@ -204,7 +204,7 @@ def generate(c):
return None
conf = '/etc/rsyslog.d/vyos-rsyslog.conf'
- render(conf, 'syslog/rsyslog.conf.tmpl', c)
+ render(conf, 'syslog/rsyslog.conf.j2', c)
# cleanup current logrotate config files
logrotate_files = Path('/etc/logrotate.d/').glob('vyos-rsyslog-generated-*')
@@ -216,7 +216,7 @@ def generate(c):
for filename, fileconfig in c.get('files', {}).items():
if fileconfig['log-file'].startswith('/var/log/user/'):
conf = '/etc/logrotate.d/vyos-rsyslog-generated-' + filename
- render(conf, 'syslog/logrotate.tmpl', { 'config_render': fileconfig })
+ render(conf, 'syslog/logrotate.j2', { 'config_render': fileconfig })
def verify(c):
diff --git a/src/conf_mode/system_console.py b/src/conf_mode/system_console.py
index 19b252513..86985d765 100755
--- a/src/conf_mode/system_console.py
+++ b/src/conf_mode/system_console.py
@@ -103,7 +103,7 @@ def generate(console):
config_file = base_dir + f'/serial-getty@{device}.service'
getty_wants_symlink = base_dir + f'/getty.target.wants/serial-getty@{device}.service'
- render(config_file, 'getty/serial-getty.service.tmpl', device_config)
+ render(config_file, 'getty/serial-getty.service.j2', device_config)
os.symlink(config_file, getty_wants_symlink)
# GRUB
diff --git a/src/conf_mode/system_frr.py b/src/conf_mode/system_frr.py
new file mode 100755
index 000000000..1af0055f6
--- /dev/null
+++ b/src/conf_mode/system_frr.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from pathlib import Path
+from sys import exit
+
+from vyos import ConfigError
+from vyos import airbag
+from vyos.config import Config
+from vyos.logger import syslog
+from vyos.template import render_to_string
+from vyos.util import read_file, write_file, run
+airbag.enable()
+
+# path to daemons config and config status files
+config_file = '/etc/frr/daemons'
+vyos_status_file = '/tmp/vyos-config-status'
+# path to watchfrr for FRR control
+watchfrr = '/usr/lib/frr/watchfrr.sh'
+
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ base = ['system', 'frr']
+ frr_config = conf.get_config_dict(base, get_first_key=True)
+
+ return frr_config
+
+
+def verify(frr_config):
+ # Nothing to verify here
+ pass
+
+
+def generate(frr_config):
+ # read daemons config file
+ daemons_config_current = read_file(config_file)
+ # generate new config file
+ daemons_config_new = render_to_string('frr/daemons.frr.tmpl', frr_config)
+ # update configuration file if this is necessary
+ if daemons_config_new != daemons_config_current:
+ syslog.warning('FRR daemons configuration file need to be changed')
+ write_file(config_file, daemons_config_new)
+ frr_config['config_file_changed'] = True
+
+
+def apply(frr_config):
+ # check if this is initial commit during boot or intiated by CLI
+ # if the file exists, this must be CLI commit
+ commit_type_cli = Path(vyos_status_file).exists()
+ # display warning to user
+ if commit_type_cli and frr_config.get('config_file_changed'):
+ # Since FRR restart is not safe thing, better to give
+ # control over this to users
+ print('''
+ You need to reboot a router (preferred) or restart FRR
+ to apply changes in modules settings
+ ''')
+ # restart FRR automatically. DUring the initial boot this should be
+ # safe in most cases
+ if not commit_type_cli and frr_config.get('config_file_changed'):
+ syslog.warning('Restarting FRR to apply changes in modules')
+ run(f'{watchfrr} restart')
+
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/conf_mode/system_lcd.py b/src/conf_mode/system_lcd.py
index b5ce32beb..3341dd738 100755
--- a/src/conf_mode/system_lcd.py
+++ b/src/conf_mode/system_lcd.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2022 VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -61,9 +61,9 @@ def generate(lcd):
lcd['device'] = find_device_file(lcd['device'])
# Render config file for daemon LCDd
- render(lcdd_conf, 'lcd/LCDd.conf.tmpl', lcd)
+ render(lcdd_conf, 'lcd/LCDd.conf.j2', lcd)
# Render config file for client lcdproc
- render(lcdproc_conf, 'lcd/lcdproc.conf.tmpl', lcd)
+ render(lcdproc_conf, 'lcd/lcdproc.conf.j2', lcd)
return None
diff --git a/src/conf_mode/system_sysctl.py b/src/conf_mode/system_sysctl.py
index 4f16d1ed6..2e0004ffa 100755
--- a/src/conf_mode/system_sysctl.py
+++ b/src/conf_mode/system_sysctl.py
@@ -50,7 +50,7 @@ def generate(sysctl):
os.unlink(config_file)
return None
- render(config_file, 'system/sysctl.conf.tmpl', sysctl)
+ render(config_file, 'system/sysctl.conf.j2', sysctl)
return None
def apply(sysctl):
diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py
index 95050624e..c5daccb7f 100755
--- a/src/conf_mode/tftp_server.py
+++ b/src/conf_mode/tftp_server.py
@@ -98,7 +98,7 @@ def generate(tftpd):
config['vrf'] = address_config['vrf']
file = config_file + str(idx)
- render(file, 'tftp-server/default.tmpl', config)
+ render(file, 'tftp-server/default.j2', config)
idx = idx + 1
return None
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index dc134fd1f..bad9cfbd8 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -503,7 +503,7 @@ def generate(ipsec):
charon_radius_conf, interface_conf, swanctl_conf]:
if os.path.isfile(config_file):
os.unlink(config_file)
- render(charon_conf, 'ipsec/charon.tmpl', {'install_routes': default_install_routes})
+ render(charon_conf, 'ipsec/charon.j2', {'install_routes': default_install_routes})
return
if ipsec['dhcp_no_address']:
@@ -567,13 +567,13 @@ def generate(ipsec):
ipsec['site_to_site']['peer'][peer]['tunnel'][tunnel]['passthrough'] = passthrough
- render(ipsec_conf, 'ipsec/ipsec.conf.tmpl', ipsec)
- render(ipsec_secrets, 'ipsec/ipsec.secrets.tmpl', ipsec)
- render(charon_conf, 'ipsec/charon.tmpl', ipsec)
- render(charon_dhcp_conf, 'ipsec/charon/dhcp.conf.tmpl', ipsec)
- render(charon_radius_conf, 'ipsec/charon/eap-radius.conf.tmpl', ipsec)
- render(interface_conf, 'ipsec/interfaces_use.conf.tmpl', ipsec)
- render(swanctl_conf, 'ipsec/swanctl.conf.tmpl', ipsec)
+ render(ipsec_conf, 'ipsec/ipsec.conf.j2', ipsec)
+ render(ipsec_secrets, 'ipsec/ipsec.secrets.j2', ipsec)
+ render(charon_conf, 'ipsec/charon.j2', ipsec)
+ render(charon_dhcp_conf, 'ipsec/charon/dhcp.conf.j2', ipsec)
+ render(charon_radius_conf, 'ipsec/charon/eap-radius.conf.j2', ipsec)
+ render(interface_conf, 'ipsec/interfaces_use.conf.j2', ipsec)
+ render(swanctl_conf, 'ipsec/swanctl.conf.j2', ipsec)
def resync_nhrp(ipsec):
if ipsec and not ipsec['nhrp_exists']:
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 818e8fa0b..fd5a4acd8 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -358,10 +358,10 @@ def generate(l2tp):
if not l2tp:
return None
- render(l2tp_conf, 'accel-ppp/l2tp.config.tmpl', l2tp)
+ render(l2tp_conf, 'accel-ppp/l2tp.config.j2', l2tp)
if l2tp['auth_mode'] == 'local':
- render(l2tp_chap_secrets, 'accel-ppp/chap-secrets.tmpl', l2tp)
+ render(l2tp_chap_secrets, 'accel-ppp/chap-secrets.j2', l2tp)
os.chmod(l2tp_chap_secrets, S_IRUSR | S_IWUSR | S_IRGRP)
else:
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 84d31f9a5..8e0e30bbf 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -157,9 +157,9 @@ def generate(ocserv):
if "radius" in ocserv["authentication"]["mode"]:
# Render radius client configuration
- render(radius_cfg, 'ocserv/radius_conf.tmpl', ocserv["authentication"]["radius"])
+ render(radius_cfg, 'ocserv/radius_conf.j2', ocserv["authentication"]["radius"])
# Render radius servers
- render(radius_servers, 'ocserv/radius_servers.tmpl', ocserv["authentication"]["radius"])
+ render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"])
elif "local" in ocserv["authentication"]["mode"]:
# if mode "OTP", generate OTP users file parameters
if "otp" in ocserv["authentication"]["mode"]["local"]:
@@ -184,24 +184,24 @@ def generate(ocserv):
if "password-otp" in ocserv["authentication"]["mode"]["local"]:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
# Render local users OTP keys
- render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
elif "password" in ocserv["authentication"]["mode"]["local"]:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
elif "otp" in ocserv["authentication"]["mode"]["local"]:
# Render local users OTP keys
- render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
else:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
else:
if "local_users" in ocserv["authentication"]:
for user in ocserv["authentication"]["local_users"]["username"]:
ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"])
# Render local users
- render(ocserv_passwd, 'ocserv/ocserv_passwd.tmpl', ocserv["authentication"]["local_users"])
+ render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
if "ssl" in ocserv:
cert_file_path = os.path.join(cfg_dir, 'cert.pem')
@@ -227,7 +227,7 @@ def generate(ocserv):
f.write(wrap_certificate(pki_ca_cert['certificate']))
# Render config
- render(ocserv_conf, 'ocserv/ocserv_config.tmpl', ocserv)
+ render(ocserv_conf, 'ocserv/ocserv_config.j2', ocserv)
def apply(ocserv):
diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py
index 30abe4782..7550c411e 100755
--- a/src/conf_mode/vpn_pptp.py
+++ b/src/conf_mode/vpn_pptp.py
@@ -264,10 +264,10 @@ def generate(pptp):
if not pptp:
return None
- render(pptp_conf, 'accel-ppp/pptp.config.tmpl', pptp)
+ render(pptp_conf, 'accel-ppp/pptp.config.j2', pptp)
if pptp['local_users']:
- render(pptp_chap_secrets, 'accel-ppp/chap-secrets.tmpl', pptp)
+ render(pptp_chap_secrets, 'accel-ppp/chap-secrets.j2', pptp)
os.chmod(pptp_chap_secrets, S_IRUSR | S_IWUSR | S_IRGRP)
else:
if os.path.exists(pptp_chap_secrets):
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index 68980e5ab..db53463cf 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -114,7 +114,7 @@ def generate(sstp):
return None
# accel-cmd reload doesn't work so any change results in a restart of the daemon
- render(sstp_conf, 'accel-ppp/sstp.config.tmpl', sstp)
+ render(sstp_conf, 'accel-ppp/sstp.config.j2', sstp)
cert_name = sstp['ssl']['certificate']
pki_cert = sstp['pki']['certificate'][cert_name]
@@ -127,7 +127,7 @@ def generate(sstp):
write_file(ca_cert_file_path, wrap_certificate(pki_ca['certificate']))
if dict_search('authentication.mode', sstp) == 'local':
- render(sstp_chap_secrets, 'accel-ppp/chap-secrets.config_dict.tmpl',
+ render(sstp_chap_secrets, 'accel-ppp/chap-secrets.config_dict.j2',
sstp, permission=0o640)
else:
if os.path.exists(sstp_chap_secrets):
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index f79c8a21e..972d0289b 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -83,7 +83,8 @@ def get_config(config=None):
conf = Config()
base = ['vrf']
- vrf = conf.get_config_dict(base, get_first_key=True)
+ vrf = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True, get_first_key=True)
# determine which VRF has been removed
for name in node_changed(conf, base + ['name']):
@@ -133,10 +134,10 @@ def verify(vrf):
def generate(vrf):
- render(config_file, 'vrf/vrf.conf.tmpl', vrf)
+ render(config_file, 'vrf/vrf.conf.j2', vrf)
# Render nftables zones config
- render(nft_vrf_config, 'firewall/nftables-vrf-zones.tmpl', vrf)
+ render(nft_vrf_config, 'firewall/nftables-vrf-zones.j2', vrf)
return None
@@ -152,7 +153,7 @@ def apply(vrf):
# set the default VRF global behaviour
bind_all = '0'
- if 'bind-to-all' in vrf:
+ if 'bind_to_all' in vrf:
bind_all = '1'
sysctl_write('net.ipv4.tcp_l3mdev_accept', bind_all)
sysctl_write('net.ipv4.udp_l3mdev_accept', bind_all)
@@ -222,6 +223,15 @@ def apply(vrf):
# add VRF description if available
vrf_if.set_alias(config.get('description', ''))
+ # Enable/Disable IPv4 forwarding
+ tmp = dict_search('ip.disable_forwarding', config)
+ value = '0' if (tmp != None) else '1'
+ vrf_if.set_ipv4_forwarding(value)
+ # Enable/Disable IPv6 forwarding
+ tmp = dict_search('ipv6.disable_forwarding', config)
+ value = '0' if (tmp != None) else '1'
+ vrf_if.set_ipv6_forwarding(value)
+
# Enable/Disable of an interface must always be done at the end of the
# derived class to make use of the ref-counting set_admin_state()
# function. We will only enable the interface if 'up' was called as
diff --git a/src/conf_mode/zone_policy.py b/src/conf_mode/zone_policy.py
index dc0617353..070a4deea 100755
--- a/src/conf_mode/zone_policy.py
+++ b/src/conf_mode/zone_policy.py
@@ -192,7 +192,7 @@ def generate(zone_policy):
if 'local_zone' in zone_conf:
zone_conf['from_local'] = get_local_from(data, zone)
- render(nftables_conf, 'zone_policy/nftables.tmpl', data)
+ render(nftables_conf, 'zone_policy/nftables.j2', data)
return None
def apply(zone_policy):
diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper
index 74a7e83bf..5d879471d 100644
--- a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper
+++ b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper
@@ -26,7 +26,7 @@ function iptovtysh () {
local VTYSH_GATEWAY=""
local VTYSH_DEV=""
local VTYSH_TAG="210"
- local VTYSH_DISTANCE=""
+ local VTYSH_DISTANCE=$IF_METRIC
# convert default route to 0.0.0.0/0
if [ "$4" == "default" ] ; then
VTYSH_NETADDR="0.0.0.0/0"
diff --git a/src/migration-scripts/quagga/9-to-10 b/src/migration-scripts/quagga/9-to-10
new file mode 100755
index 000000000..249738822
--- /dev/null
+++ b/src/migration-scripts/quagga/9-to-10
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022 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/>.
+
+# re-organize route-map as-path
+
+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()
+
+base = ['policy', 'route-map']
+
+config = ConfigTree(config_file)
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+for route_map in config.list_nodes(base):
+ # Bail out Early
+ if not config.exists(base + [route_map, 'rule']):
+ continue
+
+ for rule in config.list_nodes(base + [route_map, 'rule']):
+ rule_base = base + [route_map, 'rule', rule]
+ if config.exists(rule_base + ['set', 'as-path-exclude']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-exclude'])
+ config.delete(rule_base + ['set', 'as-path-exclude'])
+ config.set(rule_base + ['set', 'as-path', 'exclude'], value=tmp)
+
+ if config.exists(rule_base + ['set', 'as-path-prepend']):
+ tmp = config.return_value(rule_base + ['set', 'as-path-prepend'])
+ config.delete(rule_base + ['set', 'as-path-prepend'])
+ config.set(rule_base + ['set', 'as-path', 'prepend'], value=tmp)
+
+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/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py
index 89f6df4b9..e45c38f07 100755
--- a/src/op_mode/conntrack_sync.py
+++ b/src/op_mode/conntrack_sync.py
@@ -77,7 +77,7 @@ def xml_to_stdout(xml):
parsed = xmltodict.parse(line)
out.append(parsed)
- print(render_to_string('conntrackd/conntrackd.op-mode.tmpl', {'data' : out}))
+ print(render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out}))
if __name__ == '__main__':
args = parser.parse_args()
diff --git a/src/op_mode/containers_op.py b/src/op_mode/containers_op.py
deleted file mode 100755
index c55a48b3c..000000000
--- a/src/op_mode/containers_op.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import argparse
-
-from getpass import getuser
-from vyos.configquery import ConfigTreeQuery
-from vyos.base import Warning
-from vyos.util import cmd
-from subprocess import STDOUT
-
-parser = argparse.ArgumentParser()
-parser.add_argument("-a", "--all", action="store_true", help="Show all containers")
-parser.add_argument("-i", "--image", action="store_true", help="Show container images")
-parser.add_argument("-n", "--networks", action="store_true", help="Show container images")
-parser.add_argument("-p", "--pull", action="store", help="Pull image for container")
-parser.add_argument("-d", "--remove", action="store", help="Delete container image")
-parser.add_argument("-u", "--update", action="store", help="Update given container image")
-
-config = ConfigTreeQuery()
-base = ['container']
-
-if getuser() != 'root':
- raise OSError('This functions needs to be run as root to return correct results!')
-
-if __name__ == '__main__':
- args = parser.parse_args()
-
- if args.all:
- print(cmd('podman ps --all'))
- elif args.image:
- print(cmd('podman image ls'))
- elif args.networks:
- print(cmd('podman network ls'))
-
- elif args.pull:
- image = args.pull
- registry_config = '/etc/containers/registries.conf'
- if not os.path.exists(registry_config):
- Warning('No container registry configured. Please use full URL when '\
- 'adding an image. E.g. prefix with docker.io/image-name.')
- try:
- print(os.system(f'podman image pull {image}'))
- except Exception as e:
- print(f'Unable to download image "{image}". {e}')
-
- elif args.remove:
- image = args.remove
- try:
- print(os.system(f'podman image rm {image}'))
- except FileNotFoundError as e:
- print(f'Unable to delete image "{image}". {e}')
-
- elif args.update:
- tmp = config.get_config_dict(base + ['name', args.update],
- key_mangling=('-', '_'), get_first_key=True)
- try:
- image = tmp['image']
- print(cmd(f'podman image pull {image}'))
- except Exception as e:
- print(f'Unable to download image "{image}". {e}')
- else:
- parser.print_help()
- exit(1)
-
- exit(0)
diff --git a/src/op_mode/ikev2_profile_generator.py b/src/op_mode/ikev2_profile_generator.py
index 990b06c12..21561d16f 100755
--- a/src/op_mode/ikev2_profile_generator.py
+++ b/src/op_mode/ikev2_profile_generator.py
@@ -222,9 +222,9 @@ except KeyboardInterrupt:
print('\n\n==== <snip> ====')
if args.os == 'ios':
- print(render_to_string('ipsec/ios_profile.tmpl', data))
+ print(render_to_string('ipsec/ios_profile.j2', data))
print('==== </snip> ====\n')
print('Save the XML from above to a new file named "vyos.mobileconfig" and E-Mail it to your phone.')
elif args.os == 'windows':
- print(render_to_string('ipsec/windows_profile.tmpl', data))
+ print(render_to_string('ipsec/windows_profile.j2', data))
print('==== </snip> ====\n')
diff --git a/src/op_mode/show_openvpn.py b/src/op_mode/show_openvpn.py
index f7b99cc0d..9a5adcffb 100755
--- a/src/op_mode/show_openvpn.py
+++ b/src/op_mode/show_openvpn.py
@@ -26,10 +26,10 @@ outp_tmpl = """
{% if clients %}
OpenVPN status on {{ intf }}
-Client CN Remote Host Local Host TX bytes RX bytes Connected Since
---------- ----------- ---------- -------- -------- ---------------
+Client CN Remote Host Tunnel IP Local Host TX bytes RX bytes Connected Since
+--------- ----------- --------- ---------- -------- -------- ---------------
{% for c in clients %}
-{{ "%-15s"|format(c.name) }} {{ "%-21s"|format(c.remote) }} {{ "%-21s"|format(local) }} {{ "%-9s"|format(c.tx_bytes) }} {{ "%-9s"|format(c.rx_bytes) }} {{ c.online_since }}
+{{ "%-15s"|format(c.name) }} {{ "%-21s"|format(c.remote) }} {{ "%-15s"|format(c.tunnel) }} {{ "%-21s"|format(local) }} {{ "%-9s"|format(c.tx_bytes) }} {{ "%-9s"|format(c.rx_bytes) }} {{ c.online_since }}
{% endfor %}
{% endif %}
"""
@@ -50,6 +50,19 @@ def bytes2HR(size):
output="{0:.1f} {1}".format(size, suff[suffIdx])
return output
+def get_vpn_tunnel_address(peer, interface):
+ lst = []
+ status_file = '/var/run/openvpn/{}.status'.format(interface)
+
+ with open(status_file, 'r') as f:
+ lines = f.readlines()
+ for line in lines:
+ if peer in line:
+ lst.append(line)
+ tunnel_ip = lst[1].split(',')[0]
+
+ return tunnel_ip
+
def get_status(mode, interface):
status_file = '/var/run/openvpn/{}.status'.format(interface)
# this is an empirical value - I assume we have no more then 999999
@@ -110,7 +123,7 @@ def get_status(mode, interface):
'tx_bytes': bytes2HR(line.split(',')[3]),
'online_since': line.split(',')[4]
}
-
+ client["tunnel"] = get_vpn_tunnel_address(client['remote'], interface)
data['clients'].append(client)
continue
else:
@@ -173,5 +186,7 @@ if __name__ == '__main__':
if len(remote_host) >= 1:
client['remote'] = str(remote_host[0]) + ':' + remote_port
+ client['tunnel'] = 'N/A'
+
tmpl = jinja2.Template(outp_tmpl)
print(tmpl.render(data))
diff --git a/src/op_mode/show_uptime.py b/src/op_mode/show_uptime.py
index 1b5e33fa9..b70c60cf8 100755
--- a/src/op_mode/show_uptime.py
+++ b/src/op_mode/show_uptime.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 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 as
@@ -26,14 +26,17 @@ def get_uptime_seconds():
def get_load_averages():
from re import search
from vyos.util import cmd
+ from vyos.cpu import get_core_count
data = cmd("uptime")
matches = search(r"load average:\s*(?P<one>[0-9\.]+)\s*,\s*(?P<five>[0-9\.]+)\s*,\s*(?P<fifteen>[0-9\.]+)\s*", data)
+ core_count = get_core_count()
+
res = {}
- res[1] = float(matches["one"])
- res[5] = float(matches["five"])
- res[15] = float(matches["fifteen"])
+ res[1] = float(matches["one"]) / core_count
+ res[5] = float(matches["five"]) / core_count
+ res[15] = float(matches["fifteen"]) / core_count
return res
@@ -53,9 +56,9 @@ def get_formatted_output():
out = "Uptime: {}\n\n".format(data["uptime"])
avgs = data["load_average"]
out += "Load averages:\n"
- out += "1 minute: {:.02f}%\n".format(avgs[1]*100)
- out += "5 minutes: {:.02f}%\n".format(avgs[5]*100)
- out += "15 minutes: {:.02f}%\n".format(avgs[15]*100)
+ out += "1 minute: {:.01f}%\n".format(avgs[1]*100)
+ out += "5 minutes: {:.01f}%\n".format(avgs[5]*100)
+ out += "15 minutes: {:.01f}%\n".format(avgs[15]*100)
return out
diff --git a/src/op_mode/traceroute.py b/src/op_mode/traceroute.py
new file mode 100755
index 000000000..4299d6e5f
--- /dev/null
+++ b/src/op_mode/traceroute.py
@@ -0,0 +1,207 @@
+#! /usr/bin/env python3
+
+# Copyright (C) 2022 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import socket
+import ipaddress
+
+options = {
+ 'backward-hops': {
+ 'traceroute': '{command} --back',
+ 'type': 'noarg',
+ 'help': 'Display number of backward hops when they different from the forwarded path'
+ },
+ 'bypass': {
+ 'traceroute': '{command} -r',
+ 'type': 'noarg',
+ 'help': 'Bypass the normal routing tables and send directly to a host on an attached network'
+ },
+ 'do-not-fragment': {
+ 'traceroute': '{command} -F',
+ 'type': 'noarg',
+ 'help': 'Do not fragment probe packets.'
+ },
+ 'first-ttl': {
+ 'traceroute': '{command} -f {value}',
+ 'type': '<ttl>',
+ 'help': 'Specifies with what TTL to start. Defaults to 1.'
+ },
+ 'icmp': {
+ 'traceroute': '{command} -I',
+ 'type': 'noarg',
+ 'help': 'Use ICMP ECHO for tracerouting'
+ },
+ 'interface': {
+ 'traceroute': '{command} -i {value}',
+ 'type': '<interface>',
+ 'help': 'Source interface'
+ },
+ 'lookup-as': {
+ 'traceroute': '{command} -A',
+ 'type': 'noarg',
+ 'help': 'Perform AS path lookups'
+ },
+ 'mark': {
+ 'traceroute': '{command} --fwmark={value}',
+ 'type': '<fwmark>',
+ 'help': 'Set the firewall mark for outgoing packets'
+ },
+ 'no-resolve': {
+ 'traceroute': '{command} -n',
+ 'type': 'noarg',
+ 'help': 'Do not resolve hostnames'
+ },
+ 'port': {
+ 'traceroute': '{command} -p {value}',
+ 'type': '<port>',
+ 'help': 'Destination port'
+ },
+ 'source-address': {
+ 'traceroute': '{command} -s {value}',
+ 'type': '<x.x.x.x> <h:h:h:h:h:h:h:h>',
+ 'help': 'Specify source IP v4/v6 address'
+ },
+ 'tcp': {
+ 'traceroute': '{command} -T',
+ 'type': 'noarg',
+ 'help': 'Use TCP SYN for tracerouting (default port is 80)'
+ },
+ 'tos': {
+ 'traceroute': '{commad} -t {value}',
+ 'type': '<tos>',
+ 'help': 'Mark packets with specified TOS'
+ },
+ 'ttl': {
+ 'traceroute': '{command} -m {value}',
+ 'type': '<ttl>',
+ 'help': 'Maximum number of hops'
+ },
+ 'udp': {
+ 'traceroute': '{command} -U',
+ 'type': 'noarg',
+ 'help': 'Use UDP to particular port for tracerouting (default port is 53)'
+ },
+ 'vrf': {
+ 'traceroute': 'sudo ip vrf exec {value} {command}',
+ 'type': '<vrf>',
+ 'help': 'Use specified VRF table',
+ 'dflt': 'default'}
+}
+
+traceroute = {
+ 4: '/bin/traceroute -4',
+ 6: '/bin/traceroute -6',
+}
+
+
+class List (list):
+ def first (self):
+ return self.pop(0) if self else ''
+
+ def last(self):
+ return self.pop() if self else ''
+
+ def prepend(self,value):
+ self.insert(0,value)
+
+
+def expension_failure(option, completions):
+ reason = 'Ambiguous' if completions else 'Invalid'
+ sys.stderr.write('\n\n {} command: {} [{}]\n\n'.format(reason,' '.join(sys.argv), option))
+ if completions:
+ sys.stderr.write(' Possible completions:\n ')
+ sys.stderr.write('\n '.join(completions))
+ sys.stderr.write('\n')
+ sys.stdout.write('<nocomps>')
+ sys.exit(1)
+
+
+def complete(prefix):
+ return [o for o in options if o.startswith(prefix)]
+
+
+def convert(command, args):
+ while args:
+ shortname = args.first()
+ longnames = complete(shortname)
+ if len(longnames) != 1:
+ expension_failure(shortname, longnames)
+ longname = longnames[0]
+ if options[longname]['type'] == 'noarg':
+ command = options[longname]['traceroute'].format(
+ command=command, value='')
+ elif not args:
+ sys.exit(f'traceroute: missing argument for {longname} option')
+ else:
+ command = options[longname]['traceroute'].format(
+ command=command, value=args.first())
+ return command
+
+
+if __name__ == '__main__':
+ args = List(sys.argv[1:])
+ host = args.first()
+
+ if not host:
+ sys.exit("traceroute: Missing host")
+
+ if host == '--get-options':
+ args.first() # pop traceroute
+ args.first() # pop IP
+ while args:
+ option = args.first()
+
+ matched = complete(option)
+ if not args:
+ sys.stdout.write(' '.join(matched))
+ sys.exit(0)
+
+ if len(matched) > 1 :
+ sys.stdout.write(' '.join(matched))
+ sys.exit(0)
+
+ if options[matched[0]]['type'] == 'noarg':
+ continue
+
+ value = args.first()
+ if not args:
+ matched = complete(option)
+ sys.stdout.write(options[matched[0]]['type'])
+ sys.exit(0)
+
+ for name,option in options.items():
+ if 'dflt' in option and name not in args:
+ args.append(name)
+ args.append(option['dflt'])
+
+ try:
+ ip = socket.gethostbyname(host)
+ except UnicodeError:
+ sys.exit(f'tracroute: Unknown host: {host}')
+ except socket.gaierror:
+ ip = host
+
+ try:
+ version = ipaddress.ip_address(ip).version
+ except ValueError:
+ sys.exit(f'traceroute: Unknown host: {host}')
+
+ command = convert(traceroute[version],args)
+
+ # print(f'{command} {host}')
+ os.system(f'{command} {host}')
+
diff --git a/src/validators/as-number-list b/src/validators/as-number-list
new file mode 100755
index 000000000..432d44180
--- /dev/null
+++ b/src/validators/as-number-list
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (C) 2022 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/>.
+
+if [ $# -lt 1 ]; then
+ echo "Illegal number of parameters"
+ exit 1
+fi
+
+for var in "$@"; do
+ ${vyos_validators_dir}/numeric --range 1-4294967294 $var
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+done
+
+exit 0