diff options
307 files changed, 15380 insertions, 12081 deletions
diff --git a/.github/workflows/package-smoketest.yml b/.github/workflows/package-smoketest.yml index 49bd91669..27272a6e2 100644 --- a/.github/workflows/package-smoketest.yml +++ b/.github/workflows/package-smoketest.yml @@ -1,13 +1,22 @@ -name: Package ISO Test +name: VyOS ISO integration Test on: - pull_request: + pull_request_target: branches: - current + - circinus + +permissions: + pull-requests: write + contents: read + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed for PR comments jobs: build: runs-on: ubuntu-24.04 + timeout-minutes: 45 container: image: vyos/vyos-build:current options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged @@ -24,9 +33,7 @@ jobs: - name: Clone vyos-1x source code uses: actions/checkout@v4 with: - repository: vyos/vyos-1x path: packages/vyos-1x - fetch-tags: true # required for Debian package version - name: Build vyos-1x package run: | cd packages/vyos-1x; dpkg-buildpackage -uc -us -tc -b @@ -51,6 +58,7 @@ jobs: cli-smoketests: needs: build runs-on: ubuntu-24.04 + timeout-minutes: 180 container: image: vyos/vyos-build:current options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged @@ -65,11 +73,21 @@ jobs: name: vyos-${{ needs.build.outputs.build_version }} path: build - name: VyOS CLI smoketests - run: ls -al; ls -al build; sudo make test + run: sudo make test + - name: Add PR comment + if: always() + uses: mshick/add-pr-comment@v2 + with: + message-success: '👍 VyOS CLI smoketests finished successfully!' + message-failure: '❌ VyOS CLI smoketests failed!' + message-cancelled: '❌ VyOS CLI smoketests cancelled!' + allow-repeats: false + refresh-message-position: true config-load-tests: needs: build runs-on: ubuntu-24.04 + timeout-minutes: 90 container: image: vyos/vyos-build:current options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged @@ -85,10 +103,20 @@ jobs: path: build - name: VyOS config tests run: sudo make testc + - name: Add PR comment + if: always() + uses: mshick/add-pr-comment@v2 + with: + message-success: '👍 VyOS config tests finished successfully!' + message-failure: '❌ VyOS config tests failed!' + message-cancelled: '❌ VyOS config tests cancelled!' + allow-repeats: false + refresh-message-position: true raid1-install-test: needs: build runs-on: ubuntu-24.04 + timeout-minutes: 20 container: image: vyos/vyos-build:current options: --sysctl net.ipv6.conf.lo.disable_ipv6=0 --privileged @@ -104,3 +132,12 @@ jobs: path: build - name: VyOS RAID1 install test run: sudo make testraid + - name: Add PR comment + if: always() + uses: mshick/add-pr-comment@v2 + with: + message-success: '👍 RAID1 Smoketests finished successfully!' + message-failure: '❌ RAID1 Smoketests failed!' + message-cancelled: '❌ RAID1 action cancelled!' + allow-repeats: false + refresh-message-position: true diff --git a/.gitignore b/.gitignore index 507daceee..01333d5b1 100644 --- a/.gitignore +++ b/.gitignore @@ -145,6 +145,8 @@ data/component-versions.json # vyos-1x XML cache python/vyos/xml_ref/cache.py python/vyos/xml_ref/pkg_cache/*_cache.py +# autogenerated vyos-configd JSON definition +data/configd-include.json # We do not use pip Pipfile @@ -78,18 +78,7 @@ vyshim: $(MAKE) -C $(SHIM_DIR) .PHONY: all -all: clean interface_definitions op_mode_definitions check test j2lint vyshim check_migration_scripts_executable - -.PHONY: check -.ONESHELL: -check: - @echo "Checking which CLI scripts are not enabled to work with vyos-configd..." - @for file in `ls src/conf_mode -I__pycache__` - do - if ! grep -q $$file data/configd-include.json; then - echo "* $$file" - fi - done +all: clean interface_definitions op_mode_definitions test j2lint vyshim generate-configd-include-json .PHONY: clean clean: @@ -99,7 +88,7 @@ clean: $(MAKE) -C $(SHIM_DIR) clean .PHONY: test -test: +test: generate-configd-include-json set -e; python3 -m compileall -q -x '/vmware-tools/scripts/, /ppp/' . PYTHONPATH=python/ python3 -m "nose" --with-xunit src --with-coverage --cover-erase --cover-xml --cover-package src/conf_mode,src/op_mode,src/completion,src/helpers,src/validators,src/tests --verbose @@ -127,6 +116,10 @@ unused-imports: deb: dpkg-buildpackage -uc -us -tc -b +.PHONY: generate-configd-include-json +generate-configd-include-json: + @scripts/generate-configd-include-json.py + .PHONY: schema schema: trang -I rnc -O rng schema/interface_definition.rnc schema/interface_definition.rng diff --git a/data/configd-include.json b/data/configd-include.json deleted file mode 100644 index 224a9c390..000000000 --- a/data/configd-include.json +++ /dev/null @@ -1,115 +0,0 @@ -[ -"container.py", -"firewall.py", -"high-availability.py", -"interfaces_bonding.py", -"interfaces_bridge.py", -"interfaces_dummy.py", -"interfaces_ethernet.py", -"interfaces_geneve.py", -"interfaces_input.py", -"interfaces_l2tpv3.py", -"interfaces_loopback.py", -"interfaces_macsec.py", -"interfaces_openvpn.py", -"interfaces_pppoe.py", -"interfaces_pseudo-ethernet.py", -"interfaces_sstpc.py", -"interfaces_tunnel.py", -"interfaces_virtual-ethernet.py", -"interfaces_vti.py", -"interfaces_vxlan.py", -"interfaces_wireguard.py", -"interfaces_wireless.py", -"interfaces_wwan.py", -"load-balancing_reverse-proxy.py", -"load-balancing_wan.py", -"nat.py", -"nat64.py", -"nat66.py", -"netns.py", -"pki.py", -"policy.py", -"policy_route.py", -"policy_local-route.py", -"protocols_babel.py", -"protocols_bfd.py", -"protocols_bgp.py", -"protocols_eigrp.py", -"protocols_failover.py", -"protocols_igmp-proxy.py", -"protocols_isis.py", -"protocols_mpls.py", -"protocols_nhrp.py", -"protocols_ospf.py", -"protocols_ospfv3.py", -"protocols_pim.py", -"protocols_pim6.py", -"protocols_rip.py", -"protocols_ripng.py", -"protocols_rpki.py", -"protocols_segment-routing.py", -"protocols_static.py", -"protocols_static_arp.py", -"protocols_static_multicast.py", -"protocols_static_neighbor-proxy.py", -"qos.py", -"service_aws_glb.py", -"service_broadcast-relay.py", -"service_config-sync.py", -"service_conntrack-sync.py", -"service_console-server.py", -"service_dhcp-relay.py", -"service_dhcp-server.py", -"service_dhcpv6-relay.py", -"service_dhcpv6-server.py", -"service_dns_dynamic.py", -"service_dns_forwarding.py", -"service_event-handler.py", -"service_https.py", -"service_ids_ddos-protection.py", -"service_ipoe-server.py", -"service_lldp.py", -"service_mdns_repeater.py", -"service_monitoring_telegraf.py", -"service_monitoring_zabbix-agent.py", -"service_ndp-proxy.py", -"service_ntp.py", -"service_pppoe-server.py", -"service_router-advert.py", -"service_salt-minion.py", -"service_sla.py", -"service_snmp.py", -"service_ssh.py", -"service_stunnel.py", -"service_tftp-server.py", -"service_webproxy.py", -"system_acceleration.py", -"system_config-management.py", -"system_conntrack.py", -"system_console.py", -"system_flow-accounting.py", -"system_frr.py", -"system_host-name.py", -"system_ip.py", -"system_ipv6.py", -"system_lcd.py", -"system_login.py", -"system_login_banner.py", -"system_logs.py", -"system_option.py", -"system_proxy.py", -"system_sflow.py", -"system_sysctl.py", -"system_syslog.py", -"system_task-scheduler.py", -"system_timezone.py", -"system_update-check.py", -"system_wireless.py", -"vpn_ipsec.py", -"vpn_l2tp.py", -"vpn_openconnect.py", -"vpn_pptp.py", -"vpn_sstp.py", -"vrf.py" -] diff --git a/data/templates/accel-ppp/pppoe.config.j2 b/data/templates/accel-ppp/pppoe.config.j2 index 6711f2ec9..73ffe0963 100644 --- a/data/templates/accel-ppp/pppoe.config.j2 +++ b/data/templates/accel-ppp/pppoe.config.j2 @@ -31,10 +31,13 @@ copy=1 level={{ log.level }} {% endif %} -{% if authentication.mode is vyos_defined("noauth") %} [auth] +{% if authentication.mode is vyos_defined("noauth") %} noauth=1 {% endif %} +{% if authentication.any_login is vyos_defined %} +any-login=1 +{% endif %} [client-ip-range] 0.0.0.0/0 diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2 index ee34f58fc..68a3bfd87 100644 --- a/data/templates/firewall/nftables.j2 +++ b/data/templates/firewall/nftables.j2 @@ -239,7 +239,7 @@ table ip6 vyos_filter { {% for prior, conf in ipv6.output.items() %} chain VYOS_IPV6_OUTPUT_{{ prior }} { type filter hook output priority {{ prior }}; policy accept; -{% if global_options.state_policy is vyos_defined %} +{% if global_options.state_policy is vyos_defined and prior == 'filter' %} jump VYOS_STATE_POLICY6 {% endif %} {% if conf.rule is vyos_defined %} diff --git a/data/templates/wifi/hostapd.conf.j2 b/data/templates/wifi/hostapd.conf.j2 index e1a08f7e4..0459fbc69 100644 --- a/data/templates/wifi/hostapd.conf.j2 +++ b/data/templates/wifi/hostapd.conf.j2 @@ -1,108 +1,58 @@ {# j2lint: disable=operator-enclosed-by-spaces #} ### Autogenerated by interfaces_wireless.py ### +### hostapd.conf reference: +### https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4 + {% if description is vyos_defined %} # Description: {{ description }} # User-friendly description of device; up to 32 octets encoded in UTF-8 device_name={{ description | truncate(32, True) }} {% endif %} -# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for -# management frames with the Host AP driver); wlan0 with many nl80211 drivers -# Note: This attribute can be overridden by the values supplied with the '-i' -# command line parameter. interface={{ ifname }} - {% if is_bridge_member is vyos_defined %} -# In case of atheros and nl80211 driver interfaces, an additional -# configuration parameter, bridge, may be used to notify hostapd if the -# interface is included in a bridge. This parameter is not used with Host AP -# driver. If the bridge parameter is not set, the drivers will automatically -# figure out the bridge interface (assuming sysfs is enabled and mounted to -# /sys) and this parameter may not be needed. -# -# For nl80211, this parameter can be used to request the AP interface to be -# added to the bridge automatically (brctl may refuse to do this before hostapd -# has been started to change the interface mode). If needed, the bridge -# interface is also created. {# as there can only be one bridge interface it is save to loop #} {% for bridge in is_bridge_member %} bridge={{ bridge }} {% endfor %} - -# WDS (4-address frame) mode with per-station virtual interfaces -# (only supported with driver=nl80211) -# This mode allows associated stations to use 4-address frames to allow layer 2 -# bridging to be used. wds_sta=1 {% endif %} - -# Driver interface type (hostap/wired/none/nl80211/bsd); -# default: hostap). nl80211 is used with all Linux mac80211 drivers. -# Use driver=none if building hostapd as a standalone RADIUS server that does -# not control any wireless/wired driver. driver=nl80211 - -# Levels (minimum value for logged events): -# 0 = verbose debugging -# 1 = debugging -# 2 = informational messages -# 3 = notification -# 4 = warning logger_syslog=-1 logger_syslog_level=0 logger_stdout=-1 logger_stdout_level=0 - +{# regulatory domain and protocol stuff #} {% if country_code %} -# Country code (ISO/IEC 3166-1). Used to set regulatory domain. -# Set as needed to indicate country in which device is operating. -# This can limit available channels and transmit power. +{# Watch out for default value of "00" - World Regulatory Domain is set by "XX" in hostapd.conf #} +{% if '00' in country_code %} +country_code=XX +{% else %} country_code={{ country_code | upper }} - -# Enable IEEE 802.11d. This advertises the country_code and the set of allowed -# channels and transmit power levels based on the regulatory limits. The -# country_code setting must be configured with the correct country for -# IEEE 802.11d functions. +{% endif %} ieee80211d=1 {% endif %} - {% if ssid %} -# SSID to be used in IEEE 802.11 management frames ssid={{ ssid }} {% endif %} - {% if channel %} -# Channel number (IEEE 802.11) -# (default: 0, i.e., not set) -# Please note that some drivers do not use this value from hostapd and the -# channel will need to be configured separately with iwconfig. channel={{ channel }} {% endif %} - {% if mode is vyos_defined %} -# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), -# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used -# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this -# needs to be set to hw_mode a. For IEEE 802.11ax (HE) on 6 GHz this needs -# to be set to hw_mode a. When using ACS (see channel parameter), a -# special value "any" can be used to indicate that any support band can be used. -# This special case is currently supported only with drivers with which -# offloaded ACS is used. {% if mode is vyos_defined('n') %} hw_mode=g {% elif mode is vyos_defined('ac') %} hw_mode=a ieee80211h=1 ieee80211ac=1 +{% elif mode is vyos_defined('ax') %} +hw_mode=a +ieee80211h=1 +ieee80211ax=1 {% else %} hw_mode={{ mode }} {% endif %} {% endif %} - -# ieee80211w: Whether management frame protection (MFP) is enabled -# 0 = disabled (default) -# 1 = optional -# 2 = required {% if 'disabled' in mgmt_frame_protection %} ieee80211w=0 {% elif 'optional' in mgmt_frame_protection %} @@ -110,43 +60,14 @@ ieee80211w=1 {% elif 'required' in mgmt_frame_protection %} ieee80211w=2 {% endif %} - -{% if capabilities is vyos_defined %} -# ht_capab: HT capabilities (list of flags) -# LDPC coding capability: [LDPC] = supported -# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary -# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz -# with secondary channel above the primary channel -# (20 MHz only if neither is set) -# Note: There are limits on which channels can be used with HT40- and -# HT40+. Following table shows the channels that may be available for -# HT40- and HT40+ use per IEEE 802.11n Annex J: -# freq HT40- HT40+ -# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) -# 5 GHz 40,48,56,64 36,44,52,60 -# (depending on the location, not all of these channels may be available -# for use) -# Please note that 40 MHz channels may switch their primary and secondary -# channels if needed or creation of 40 MHz channel maybe rejected based -# on overlapping BSSes. These changes are done automatically when hostapd -# is setting up the 40 MHz channel. -# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] -# (SMPS disabled if neither is set) -# HT-greenfield: [GF] (disabled if not set) -# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) -# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) -# Tx STBC: [TX-STBC] (disabled if not set) -# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial -# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC -# disabled if none of these set -# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) -# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not -# set) -# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) -# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set) -# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) +{% if enable_bf_protection is vyos_defined %} +beacon_prot=1 +{% else %} +beacon_prot=0 +{% endif %} +{# HT (802.11n 2.4GHz and 5GHz) #} +{% if capabilities.ht is vyos_defined %} {% set output = namespace(value='') %} - {% if capabilities.ht.fourtymhz_incapable is vyos_defined %} {% set output.value = output.value ~ '[40-INTOLERANT]' %} {% endif %} @@ -177,174 +98,35 @@ ieee80211w=2 {% if capabilities.ht.smps is vyos_defined %} {% set output.value = output.value ~ '[SMPS-' ~ capabilities.ht.smps | upper ~ ']' %} {% endif %} - {% if capabilities.ht.channel_set_width is vyos_defined %} {% for csw in capabilities.ht.channel_set_width %} {% set output.value = output.value ~ '[' ~ csw | upper ~ ']' %} {% endfor %} {% endif %} - {% if capabilities.ht.short_gi is vyos_defined %} {% for short_gi in capabilities.ht.short_gi %} {% set output.value = output.value ~ '[SHORT-GI-' ~ short_gi | upper ~ ']' %} {% endfor %} {% endif %} - ht_capab={{ output.value }} - {% if capabilities.ht.auto_powersave is vyos_defined %} -# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] -# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) uapsd_advertisement_enabled=1 {% endif %} {% endif %} - -# Required for full HT and VHT functionality -wme_enabled=1 - - {% if capabilities.require_ht is vyos_defined %} -# Require stations to support HT PHY (reject association if they do not) require_ht=1 {% endif %} - +{# VHT (802.11ac 5GHz) #} {% if capabilities.vht is vyos_defined %} -# vht_capab: VHT capabilities (list of flags) -# -# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454] -# Indicates maximum MPDU length -# 0 = 3895 octets (default) -# 1 = 7991 octets -# 2 = 11454 octets -# 3 = reserved -# -# supported_chan_width: [VHT160] [VHT160-80PLUS80] -# Indicates supported Channel widths -# 0 = 160 MHz & 80+80 channel widths are not supported (default) -# 1 = 160 MHz channel width is supported -# 2 = 160 MHz & 80+80 channel widths are supported -# 3 = reserved -# -# Rx LDPC coding capability: [RXLDPC] -# Indicates support for receiving LDPC coded pkts -# 0 = Not supported (default) -# 1 = Supported -# -# Short GI for 80 MHz: [SHORT-GI-80] -# Indicates short GI support for reception of packets transmitted with TXVECTOR -# params format equal to VHT and CBW = 80Mhz -# 0 = Not supported (default) -# 1 = Supported -# -# Short GI for 160 MHz: [SHORT-GI-160] -# Indicates short GI support for reception of packets transmitted with TXVECTOR -# params format equal to VHT and CBW = 160Mhz -# 0 = Not supported (default) -# 1 = Supported -# -# Tx STBC: [TX-STBC-2BY1] -# Indicates support for the transmission of at least 2x1 STBC -# 0 = Not supported (default) -# 1 = Supported -# -# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234] -# Indicates support for the reception of PPDUs using STBC -# 0 = Not supported (default) -# 1 = support of one spatial stream -# 2 = support of one and two spatial streams -# 3 = support of one, two and three spatial streams -# 4 = support of one, two, three and four spatial streams -# 5,6,7 = reserved -# -# SU Beamformer Capable: [SU-BEAMFORMER] -# Indicates support for operation as a single user beamformer -# 0 = Not supported (default) -# 1 = Supported -# -# SU Beamformee Capable: [SU-BEAMFORMEE] -# Indicates support for operation as a single user beamformee -# 0 = Not supported (default) -# 1 = Supported -# -# Compressed Steering Number of Beamformer Antennas Supported: -# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4] -# Beamformee's capability indicating the maximum number of beamformer -# antennas the beamformee can support when sending compressed beamforming -# feedback -# If SU beamformer capable, set to maximum value minus 1 -# else reserved (default) -# -# Number of Sounding Dimensions: -# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4] -# Beamformer's capability indicating the maximum value of the NUM_STS parameter -# in the TXVECTOR of a VHT NDP -# If SU beamformer capable, set to maximum value minus 1 -# else reserved (default) -# -# MU Beamformer Capable: [MU-BEAMFORMER] -# Indicates support for operation as an MU beamformer -# 0 = Not supported or sent by Non-AP STA (default) -# 1 = Supported -# -# VHT TXOP PS: [VHT-TXOP-PS] -# Indicates whether or not the AP supports VHT TXOP Power Save Mode -# or whether or not the STA is in VHT TXOP Power Save mode -# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS -# mode -# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save -# mode -# -# +HTC-VHT Capable: [HTC-VHT] -# Indicates whether or not the STA supports receiving a VHT variant HT Control -# field. -# 0 = Not supported (default) -# 1 = supported -# -# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7] -# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv -# This field is an integer in the range of 0 to 7. -# The length defined by this field is equal to -# 2 pow(13 ~ Maximum A-MPDU Length Exponent) -1 octets -# -# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3] -# Indicates whether or not the STA supports link adaptation using VHT variant -# HT Control field -# If +HTC-VHTcapable is 1 -# 0 = (no feedback) if the STA does not provide VHT MFB (default) -# 1 = reserved -# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB -# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the -# STA provides unsolicited VHT MFB -# Reserved if +HTC-VHTcapable is 0 -# -# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN] -# Indicates the possibility of Rx antenna pattern change -# 0 = Rx antenna pattern might change during the lifetime of an association -# 1 = Rx antenna pattern does not change during the lifetime of an association -# -# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN] -# Indicates the possibility of Tx antenna pattern change -# 0 = Tx antenna pattern might change during the lifetime of an association -# 1 = Tx antenna pattern does not change during the lifetime of an - {% if capabilities.vht.center_channel_freq.freq_1 is vyos_defined %} -# center freq = 5 GHz ~ (5 * index) -# So index 42 gives center freq 5.210 GHz -# which is channel 42 in 5G band vht_oper_centr_freq_seg0_idx={{ capabilities.vht.center_channel_freq.freq_1 }} {% endif %} - {% if capabilities.vht.center_channel_freq.freq_2 is vyos_defined %} -# center freq = 5 GHz ~ (5 * index) -# So index 159 gives center freq 5.795 GHz -# which is channel 159 in 5G band vht_oper_centr_freq_seg1_idx={{ capabilities.vht.center_channel_freq.freq_2 }} {% endif %} - {% if capabilities.vht.channel_set_width is vyos_defined %} vht_oper_chwidth={{ capabilities.vht.channel_set_width }} {% endif %} - {% set output = namespace(value='') %} {% if capabilities.vht.channel_set_width is vyos_defined('2') %} {% set output.value = output.value ~ '[VHT160]' %} @@ -405,136 +187,85 @@ vht_oper_chwidth={{ capabilities.vht.channel_set_width }} {% endif %} {% endif %} {% endif %} - vht_capab={{ output.value }} {% endif %} - -# ieee80211n: Whether IEEE 802.11n (HT) is enabled -# 0 = disabled (default) -# 1 = enabled -# Note: You will also need to enable WMM for full HT functionality. -# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band. -{% if capabilities.require_vht is vyos_defined %} +{# TODO: Research if require_(ht|vht|he) are mutually exclusive! #} +{% if capabilities.require_vht is vyos_defined or capabilities.require_he is vyos_defined %} +{% if capabilities.require_vht is vyos_defined %} ieee80211n=0 -# Require stations to support VHT PHY (reject association if they do not) require_vht=1 +{% endif %} +{% if capabilities.require_he is vyos_defined %} +ieee80211n=0 +require_he=1 +{% endif %} {% else %} -ieee80211n={{ '1' if 'n' in mode or 'ac' in mode else '0' }} +ieee80211n={{ '1' if 'n' in mode or 'ac' in mode or 'ax' in mode else '0' }} {% endif %} - +{# HE (802.11ax 6GHz) #} +{% if capabilities.he is vyos_defined and mode in 'ax' %} +{# For now, hard-code power levels for indoor-only AP #} +he_6ghz_reg_pwr_type=0 +{# If we had an option to set indoor/outdoor/all environments for a reg domain, we would need to configure the country3 value as well! #} +{# country3=0x4f #} +{% if capabilities.he.center_channel_freq.freq_1 is vyos_defined %} +he_oper_centr_freq_seg0_idx={{ capabilities.he.center_channel_freq.freq_1 }} +{% endif %} +{% if capabilities.he.center_channel_freq.freq_2 is vyos_defined %} +he_oper_centr_freq_seg1_idx={{ capabilities.he.center_channel_freq.freq_2 }} +{% endif %} +{% if capabilities.he.channel_set_width is vyos_defined %} +op_class={{ capabilities.he.channel_set_width }} +{% endif %} +{% if capabilities.he.bss_color is vyos_defined %} +he_bss_color={{ capabilities.he.bss_color }} +{% endif %} +he_6ghz_rx_ant_pat={{ '1' if capabilities.he.antenna_pattern_fixed is vyos_defined else '0' }} +he_su_beamformer={{ '1' if capabilities.he.beamform.single_user_beamformer is vyos_defined else '0' }} +he_su_beamformee={{ '1' if capabilities.he.beamform.single_user_beamformee is vyos_defined else '0' }} +he_mu_beamformer={{ '1' if capabilities.he.beamform.multi_user_beamformer is vyos_defined else '0' }} +{% endif %} +{# generic stuff #} {% if disable_broadcast_ssid is vyos_defined %} -# Send empty SSID in beacons and ignore probe request frames that do not -# specify full SSID, i.e., require stations to know SSID. -# default: disabled (0) -# 1 = send empty (length=0) SSID in beacon and ignore probe request for -# broadcast SSID -# 2 = clear SSID (ASCII 0), but keep the original length (this may be required -# with some clients that do not support empty SSID) and ignore probe -# requests for broadcast SSID ignore_broadcast_ssid=1 {% endif %} - {% if type is vyos_defined('access-point') %} -# Station MAC address-based authentication -# Please note that this kind of access control requires a driver that uses -# hostapd to take care of management frame processing and as such, this can be -# used with driver=hostap or driver=nl80211, but not with driver=atheros. -# 0 = accept unless in deny list -# 1 = deny unless in accept list -# 2 = use external RADIUS server (accept/deny lists are searched first) macaddr_acl={{ '0' if security.station_address.mode is vyos_defined('accept') else '1' }} - -# Accept/deny lists are read from separate files (containing list of -# MAC addresses, one per line). Use absolute path name to make sure that the -# files can be read on SIGHUP configuration reloads. accept_mac_file={{ hostapd_accept_station_conf }} deny_mac_file={{ hostapd_deny_station_conf }} {% endif %} - +{% if stationary_ap is vyos_defined %} +stationary_ap=1 +{% endif %} {% if max_stations is vyos_defined %} -# Maximum number of stations allowed in station table. New stations will be -# rejected after the station table is full. IEEE 802.11 has a limit of 2007 -# different association IDs, so this number should not be larger than that. -# (default: 2007) max_num_sta={{ max_stations }} {% endif %} - {% if isolate_stations is vyos_defined %} -# Client isolation can be used to prevent low-level bridging of frames between -# associated stations in the BSS. By default, this bridging is allowed. ap_isolate=1 {% endif %} - +{# enable_background_radar not yet supported by VyOS's version of hostapd +{% if background_radar_detection is vyos_defined %} +enable_background_radar=1 +{% endif %} + #} {% if reduce_transmit_power is vyos_defined %} -# Add Power Constraint element to Beacon and Probe Response frames -# This config option adds Power Constraint element when applicable and Country -# element is added. Power Constraint element is required by Transmit Power -# Control. This can be used only with ieee80211d=1. -# Valid values are 0..255. local_pwr_constraint={{ reduce_transmit_power }} {% endif %} - {% if expunge_failing_stations is vyos_defined %} -# Disassociate stations based on excessive transmission failures or other -# indications of connection loss. This depends on the driver capabilities and -# may not be available with all drivers. disassoc_low_ack=1 {% endif %} - - {% if security.wep is vyos_defined %} -# IEEE 802.11 specifies two authentication algorithms. hostapd can be -# configured to allow both of these or only one. Open system authentication -# should be used with IEEE 802.1X. -# Bit fields of allowed authentication algorithms: -# bit 0 = Open System Authentication -# bit 1 = Shared Key Authentication (requires WEP) auth_algs=2 - -# WEP rekeying (disabled if key lengths are not set or are set to 0) -# Key lengths for default/broadcast and individual/unicast keys: -# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) -# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) wep_key_len_broadcast=5 wep_key_len_unicast=5 - -# Static WEP key configuration -# -# The key number to use when transmitting. -# It must be between 0 and 3, and the corresponding key must be set. -# default: not set wep_default_key=0 - -# The WEP keys to use. -# A key may be a quoted string or unquoted hexadecimal digits. -# The key length should be 5, 13, or 16 characters, or 10, 26, or 32 -# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or -# 128-bit (152-bit) WEP is used. -# Only the default key must be supplied; the others are optional. {% if security.wep.key is vyos_defined %} {% for key in sec_wep_key %} wep_key{{ loop.index -1 }}={{ security.wep.key }} {% endfor %} {% endif %} - - {% elif security.wpa is vyos_defined %} -##### WPA/IEEE 802.11i configuration ########################################## - -# Enable WPA. Setting this variable configures the AP to require WPA (either -# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either -# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. -# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice. -# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), -# RADIUS authentication server must be configured, and WPA-EAP must be included -# in wpa_key_mgmt. -# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) -# and/or WPA2 (full IEEE 802.11i/RSN): -# bit0 = WPA -# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) -# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2. -# In other words, for WPA3, wpa 2 is used the configuration (and -# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK). +auth_algs=1 {% if security.wpa.mode is vyos_defined('wpa+wpa2') %} wpa=3 {% elif security.wpa.mode is vyos_defined('wpa2') or security.wpa.mode is vyos_defined('wpa3') %} @@ -542,122 +273,459 @@ wpa=2 {% elif security.wpa.mode is vyos_defined('wpa') %} wpa=1 {% endif %} - {% if security.wpa.cipher is vyos_defined %} -# Set of accepted cipher suites (encryption algorithms) for pairwise keys -# (unicast packets). This is a space separated list of algorithms: -# CCMP = AES in Counter mode with CBC-MAC (CCMP-128) -# TKIP = Temporal Key Integrity Protocol -# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key -# GCMP = Galois/counter mode protocol (GCMP-128) -# GCMP-256 = Galois/counter mode protocol with 256-bit key -# Group cipher suite (encryption algorithm for broadcast and multicast frames) -# is automatically selected based on this configuration. If only CCMP is -# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, -# TKIP will be used as the group cipher. The optional group_cipher parameter can -# be used to override this automatic selection. - -{% if security.wpa.mode is vyos_defined('wpa2') %} -# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) +{% if security.wpa.mode is vyos_defined('wpa2') or security.wpa.mode is vyos_defined('wpa3') %} rsn_pairwise={{ security.wpa.cipher | join(" ") }} {% else %} -# Pairwise cipher for WPA (v1) (default: TKIP) wpa_pairwise={{ security.wpa.cipher | join(" ") }} {% endif %} {% endif %} - {% if security.wpa.group_cipher is vyos_defined %} -# Optional override for automatic group cipher selection -# This can be used to select a specific group cipher regardless of which -# pairwise ciphers were enabled for WPA and RSN. It should be noted that -# overriding the group cipher with an unexpected value can result in -# interoperability issues and in general, this parameter is mainly used for -# testing purposes. -group_cipher={{ security.wpa.group_cipher | join(" ") }} +group_cipher={{ security.wpa.group_cipher }} +{% endif %} +{% if security.wpa.group_mgmt_cipher is vyos_defined %} +group_mgmt_cipher={{ security.wpa.group_mgmt_cipher }} {% endif %} - {% if security.wpa.passphrase is vyos_defined %} -# IEEE 802.11 specifies two authentication algorithms. hostapd can be -# configured to allow both of these or only one. Open system authentication -# should be used with IEEE 802.1X. -# Bit fields of allowed authentication algorithms: -# bit 0 = Open System Authentication -# bit 1 = Shared Key Authentication (requires WEP) -auth_algs=1 - -# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit -# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase -# (8..63 characters) that will be converted to PSK. This conversion uses SSID -# so the PSK changes when ASCII passphrase is used and the SSID is changed. -wpa_passphrase={{ security.wpa.passphrase }} - -# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The -# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be -# added to enable SHA256-based stronger algorithms. -# WPA-PSK = WPA-Personal / WPA2-Personal -# WPA-PSK-SHA256 = WPA2-Personal using SHA256 -# WPA-EAP = WPA-Enterprise / WPA2-Enterprise -# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256 -# SAE = SAE (WPA3-Personal) -# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite {% if security.wpa.mode is vyos_defined('wpa3') %} wpa_key_mgmt=SAE +sae_password={{ security.wpa.passphrase }} +extended_key_id=1 +wpa_gmk_rekey=86400 +wpa_group_rekey=86400 +wpa_group_update_count=4 {% else %} wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256 +wpa_passphrase={{ security.wpa.passphrase }} {% endif %} - {% elif security.wpa.radius is vyos_defined %} -##### IEEE 802.1X-2004 related configuration ################################## -# Require IEEE 802.1X authorization ieee8021x=1 - -# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The -# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be -# added to enable SHA256-based stronger algorithms. -# WPA-PSK = WPA-Personal / WPA2-Personal -# WPA-PSK-SHA256 = WPA2-Personal using SHA256 -# WPA-EAP = WPA-Enterprise / WPA2-Enterprise -# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256 -# SAE = SAE (WPA3-Personal) -# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite {% if security.wpa.mode is vyos_defined('wpa3') %} wpa_key_mgmt=WPA-EAP-SUITE-B-192 {% else %} wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256 {% endif %} - {% if security.wpa.radius.server is vyos_defined %} -# RADIUS client forced local IP address for the access point -# Normally the local IP address is determined automatically based on configured -# IP addresses, but this field can be used to force a specific address to be -# used, e.g., when the device has multiple IP addresses. -# The own IP address of the access point (used as NAS-IP-Address) {% if security.wpa.radius.source_address is vyos_defined %} radius_client_addr={{ security.wpa.radius.source_address }} own_ip_addr={{ security.wpa.radius.source_address }} {% else %} own_ip_addr=127.0.0.1 {% endif %} - {% for radius in security.wpa.radius.server if not radius.disabled %} -# RADIUS authentication server auth_server_addr={{ radius.server }} auth_server_port={{ radius.port }} auth_server_shared_secret={{ radius.key }} - {% if radius.acc_port %} -# RADIUS accounting server acct_server_addr={{ radius.server }} acct_server_port={{ radius.acc_port }} acct_server_shared_secret={{ radius.key }} {% endif %} {% endfor %} {% else %} -# Open system auth_algs=1 {% endif %} {% endif %} {% endif %} +tx_queue_data3_aifs=7 +tx_queue_data3_cwmin=15 +tx_queue_data3_cwmax=1023 +tx_queue_data3_burst=0 +tx_queue_data2_aifs=3 +tx_queue_data2_cwmin=15 +tx_queue_data2_cwmax=63 +tx_queue_data2_burst=0 +tx_queue_data1_aifs=1 +tx_queue_data1_cwmin=7 +tx_queue_data1_cwmax=15 +tx_queue_data1_burst=3.0 +tx_queue_data0_aifs=1 +tx_queue_data0_cwmin=3 +tx_queue_data0_cwmax=7 +tx_queue_data0_burst=1.5 +wme_enabled=1 +wmm_enabled=1 +wmm_ac_bk_cwmin=4 +wmm_ac_bk_cwmax=10 +wmm_ac_bk_aifs=7 +wmm_ac_bk_txop_limit=0 +wmm_ac_bk_acm=0 +wmm_ac_be_aifs=3 +wmm_ac_be_cwmin=4 +wmm_ac_be_cwmax=10 +wmm_ac_be_txop_limit=0 +wmm_ac_be_acm=0 +wmm_ac_vi_aifs=2 +wmm_ac_vi_cwmin=3 +wmm_ac_vi_cwmax=4 +wmm_ac_vi_txop_limit=94 +wmm_ac_vi_acm=0 +wmm_ac_vo_aifs=2 +wmm_ac_vo_cwmin=2 +wmm_ac_vo_cwmax=3 +wmm_ac_vo_txop_limit=47 +wmm_ac_vo_acm=0 + +{# +# hostapd.conf for hostapd 2.10 +# hostapd.conf reference: +# https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4 + +##### hostapd configuration file ############################################## +# Empty lines and lines starting with # are ignored + +# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for +# management frames with the Host AP driver); wlan0 with many nl80211 drivers +# Note: This attribute can be overridden by the values supplied with the '-i' +# command line parameter. +interface=wlan0 + +# In case of atheros and nl80211 driver interfaces, an additional +# configuration parameter, bridge, may be used to notify hostapd if the +# interface is included in a bridge. This parameter is not used with Host AP +# driver. If the bridge parameter is not set, the drivers will automatically +# figure out the bridge interface (assuming sysfs is enabled and mounted to +# /sys) and this parameter may not be needed. +# +# For nl80211, this parameter can be used to request the AP interface to be +# added to the bridge automatically (brctl may refuse to do this before hostapd +# has been started to change the interface mode). If needed, the bridge +# interface is also created. +#bridge=br0 + +# Driver interface type (hostap/wired/none/nl80211/bsd); +# default: hostap). nl80211 is used with all Linux mac80211 drivers. +# Use driver=none if building hostapd as a standalone RADIUS server that does +# not control any wireless/wired driver. +# driver=hostap + +# Driver interface parameters (mainly for development testing use) +# driver_params=<params> + +# hostapd event logger configuration +# +# Two output method: syslog and stdout (only usable if not forking to +# background). +# +# Module bitfield (ORed bitfield of modules that will be logged; -1 = all +# modules): +# bit 0 (1) = IEEE 802.11 +# bit 1 (2) = IEEE 802.1X +# bit 2 (4) = RADIUS +# bit 3 (8) = WPA +# bit 4 (16) = driver interface +# bit 6 (64) = MLME +# +# Levels (minimum value for logged events): +# 0 = verbose debugging +# 1 = debugging +# 2 = informational messages +# 3 = notification +# 4 = warning +# +logger_syslog=-1 +logger_syslog_level=2 +logger_stdout=-1 +logger_stdout_level=2 + +# Interface for separate control program. If this is specified, hostapd +# will create this directory and a UNIX domain socket for listening to requests +# from external programs (CLI/GUI, etc.) for status information and +# configuration. The socket file will be named based on the interface name, so +# multiple hostapd processes/interfaces can be run at the same time if more +# than one interface is used. +# /var/run/hostapd is the recommended directory for sockets and by default, +# hostapd_cli will use it when trying to connect with hostapd. +ctrl_interface=/var/run/hostapd + +# Access control for the control interface can be configured by setting the +# directory to allow only members of a group to use sockets. This way, it is +# possible to run hostapd as root (since it needs to change network +# configuration and open raw sockets) and still allow GUI/CLI components to be +# run as non-root users. However, since the control interface can be used to +# change the network configuration, this access needs to be protected in many +# cases. By default, hostapd is configured to use gid 0 (root). If you +# want to allow non-root users to use the control interface, add a new group +# and change this value to match with that group. Add users that should have +# control interface access to this group. +# +# This variable can be a group name or gid. +#ctrl_interface_group=wheel +ctrl_interface_group=0 + + +##### IEEE 802.11 related configuration ####################################### + +# SSID to be used in IEEE 802.11 management frames +ssid=test +# Alternative formats for configuring SSID +# (double quoted string, hexdump, printf-escaped string) +#ssid2="test" +#ssid2=74657374 +#ssid2=P"hello\nthere" + +# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding +#utf8_ssid=1 + +# Country code (ISO/IEC 3166-1). Used to set regulatory domain. +# Set as needed to indicate country in which device is operating. +# This can limit available channels and transmit power. +# These two octets are used as the first two octets of the Country String +# (dot11CountryString) +#country_code=US + +# The third octet of the Country String (dot11CountryString) +# This parameter is used to set the third octet of the country string. +# +# All environments of the current frequency band and country (default) +#country3=0x20 +# Outdoor environment only +#country3=0x4f +# Indoor environment only +#country3=0x49 +# Noncountry entity (country_code=XX) +#country3=0x58 +# IEEE 802.11 standard Annex E table indication: 0x01 .. 0x1f +# Annex E, Table E-4 (Global operating classes) +#country3=0x04 + +# Enable IEEE 802.11d. This advertises the country_code and the set of allowed +# channels and transmit power levels based on the regulatory limits. The +# country_code setting must be configured with the correct country for +# IEEE 802.11d functions. +# (default: 0 = disabled) +#ieee80211d=1 + +# Enable IEEE 802.11h. This enables radar detection and DFS support if +# available. DFS support is required on outdoor 5 GHz channels in most countries +# of the world. This can be used only with ieee80211d=1. +# (default: 0 = disabled) +#ieee80211h=1 + +# Add Power Constraint element to Beacon and Probe Response frames +# This config option adds Power Constraint element when applicable and Country +# element is added. Power Constraint element is required by Transmit Power +# Control. This can be used only with ieee80211d=1. +# Valid values are 0..255. +#local_pwr_constraint=3 + +# Set Spectrum Management subfield in the Capability Information field. +# This config option forces the Spectrum Management bit to be set. When this +# option is not set, the value of the Spectrum Management bit depends on whether +# DFS or TPC is required by regulatory authorities. This can be used only with +# ieee80211d=1 and local_pwr_constraint configured. +#spectrum_mgmt_required=1 + +# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), +# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used +# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this +# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs +# to be set to hw_mode=a. When using ACS (see channel parameter), a +# special value "any" can be used to indicate that any support band can be used. +# This special case is currently supported only with drivers with which +# offloaded ACS is used. +# Default: IEEE 802.11b +hw_mode=g + +# Channel number (IEEE 802.11) +# (default: 0, i.e., not set) +# Please note that some drivers do not use this value from hostapd and the +# channel will need to be configured separately with iwconfig. +# +# If CONFIG_ACS build option is enabled, the channel can be selected +# automatically at run time by setting channel=acs_survey or channel=0, both of +# which will enable the ACS survey based algorithm. +channel=1 + +# Global operating class (IEEE 802.11, Annex E, Table E-4) +# This option allows hostapd to specify the operating class of the channel +# configured with the channel parameter. channel and op_class together can +# uniquely identify channels across different bands, including the 6 GHz band. +#op_class=131 + +# ACS tuning - Automatic Channel Selection +# See: https://wireless.wiki.kernel.org/en/users/documentation/acs +# +# You can customize the ACS survey algorithm with following variables: +# +# acs_num_scans requirement is 1..100 - number of scans to be performed that +# are used to trigger survey data gathering of an underlying device driver. +# Scans are passive and typically take a little over 100ms (depending on the +# driver) on each available channel for given hw_mode. Increasing this value +# means sacrificing startup time and gathering more data wrt channel +# interference that may help choosing a better channel. This can also help fine +# tune the ACS scan time in case a driver has different scan dwell times. +# +# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be +# used to increase (or decrease) the likelihood of a specific channel to be +# selected by the ACS algorithm. The total interference factor for each channel +# gets multiplied by the specified bias value before finding the channel with +# the lowest value. In other words, values between 0.0 and 1.0 can be used to +# make a channel more likely to be picked while values larger than 1.0 make the +# specified channel less likely to be picked. This can be used, e.g., to prefer +# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default +# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified). +# +# Defaults: +#acs_num_scans=5 +#acs_chan_bias=1:0.8 6:0.8 11:0.8 + +# Channel list restriction. This option allows hostapd to select one of the +# provided channels when a channel should be automatically selected. +# Channel list can be provided as range using hyphen ('-') or individual +# channels can be specified by space (' ') separated values +# Default: all channels allowed in selected hw_mode +#chanlist=100 104 108 112 116 +#chanlist=1 6 11-13 + +# Frequency list restriction. This option allows hostapd to select one of the +# provided frequencies when a frequency should be automatically selected. +# Frequency list can be provided as range using hyphen ('-') or individual +# frequencies can be specified by comma (',') separated values +# Default: all frequencies allowed in selected hw_mode +#freqlist=2437,5955,5975 +#freqlist=2437,5985-6105 + +# Exclude DFS channels from ACS +# This option can be used to exclude all DFS channels from the ACS channel list +# in cases where the driver supports DFS channels. +#acs_exclude_dfs=1 + +# Include only preferred scan channels from 6 GHz band for ACS +# This option can be used to include only preferred scan channels in the 6 GHz +# band. This can be useful in particular for devices that operate only a 6 GHz +# BSS without a collocated 2.4/5 GHz BSS. +# Default behavior is to include all PSC and non-PSC channels. +#acs_exclude_6ghz_non_psc=1 + +# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection. +# (default 0, i.e., not constraint) +#min_tx_power=20 + +# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) +beacon_int=100 + +# DTIM (delivery traffic information message) period (range 1..255): +# number of beacons between DTIMs (1 = every beacon includes DTIM element) +# (default: 2) +dtim_period=2 + +# Maximum number of stations allowed in station table. New stations will be +# rejected after the station table is full. IEEE 802.11 has a limit of 2007 +# different association IDs, so this number should not be larger than that. +# (default: 2007) +max_num_sta=255 + +# RTS/CTS threshold; -1 = disabled (default); range -1..65535 +# If this field is not included in hostapd.conf, hostapd will not control +# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it. +rts_threshold=-1 + +# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346 +# If this field is not included in hostapd.conf, hostapd will not control +# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set +# it. +fragm_threshold=-1 + +# Rate configuration +# Default is to enable all rates supported by the hardware. This configuration +# item allows this list be filtered so that only the listed rates will be left +# in the list. If the list is empty, all rates are used. This list can have +# entries that are not in the list of rates the hardware supports (such entries +# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110. +# If this item is present, at least one rate have to be matching with the rates +# hardware supports. +# default: use the most common supported rate setting for the selected +# hw_mode (i.e., this line can be removed from configuration file in most +# cases) +#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540 + +# Basic rate set configuration +# List of rates (in 100 kbps) that are included in the basic rate set. +# If this item is not included, usually reasonable default set is used. +#basic_rates=10 20 +#basic_rates=10 20 55 110 +#basic_rates=60 120 240 + +# Beacon frame TX rate configuration +# This sets the TX rate that is used to transmit Beacon frames. If this item is +# not included, the driver default rate (likely lowest rate) is used. +# Legacy (CCK/OFDM rates): +# beacon_rate=<legacy rate in 100 kbps> +# HT: +# beacon_rate=ht:<HT MCS> +# VHT: +# beacon_rate=vht:<VHT MCS> +# HE: +# beacon_rate=he:<HE MCS> +# +# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM). +#beacon_rate=10 + +# Short Preamble +# This parameter can be used to enable optional use of short preamble for +# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance. +# This applies only to IEEE 802.11b-compatible networks and this should only be +# enabled if the local hardware supports use of short preamble. If any of the +# associated STAs do not support short preamble, use of short preamble will be +# disabled (and enabled when such STAs disassociate) dynamically. +# 0 = do not allow use of short preamble (default) +# 1 = allow use of short preamble +#preamble=1 + +# Station MAC address -based authentication +# Please note that this kind of access control requires a driver that uses +# hostapd to take care of management frame processing and as such, this can be +# used with driver=hostap or driver=nl80211, but not with driver=atheros. +# 0 = accept unless in deny list +# 1 = deny unless in accept list +# 2 = use external RADIUS server (accept/deny lists are searched first) +macaddr_acl=0 + +# Accept/deny lists are read from separate files (containing list of +# MAC addresses, one per line). Use absolute path name to make sure that the +# files can be read on SIGHUP configuration reloads. +#accept_mac_file=/etc/hostapd.accept +#deny_mac_file=/etc/hostapd.deny + +# IEEE 802.11 specifies two authentication algorithms. hostapd can be +# configured to allow both of these or only one. Open system authentication +# should be used with IEEE 802.1X. +# Bit fields of allowed authentication algorithms: +# bit 0 = Open System Authentication +# bit 1 = Shared Key Authentication (requires WEP) +auth_algs=3 + +# Send empty SSID in beacons and ignore probe request frames that do not +# specify full SSID, i.e., require stations to know SSID. +# default: disabled (0) +# 1 = send empty (length=0) SSID in beacon and ignore probe request for +# broadcast SSID +# 2 = clear SSID (ASCII 0), but keep the original length (this may be required +# with some clients that do not support empty SSID) and ignore probe +# requests for broadcast SSID +ignore_broadcast_ssid=0 + +# Do not reply to broadcast Probe Request frames from unassociated STA if there +# is no room for additional stations (max_num_sta). This can be used to +# discourage a STA from trying to associate with this AP if the association +# would be rejected due to maximum STA limit. +# Default: 0 (disabled) +#no_probe_resp_if_max_sta=0 + +# Additional vendor specific elements for Beacon and Probe Response frames +# This parameter can be used to add additional vendor specific element(s) into +# the end of the Beacon and Probe Response frames. The format for these +# element(s) is a hexdump of the raw information elements (id+len+payload for +# one or more elements) +#vendor_elements=dd0411223301 + +# Additional vendor specific elements for (Re)Association Response frames +# This parameter can be used to add additional vendor specific element(s) into +# the end of the (Re)Association Response frames. The format for these +# element(s) is a hexdump of the raw information elements (id+len+payload for +# one or more elements) +#assocresp_elements=dd0411223301 # TX queue parameters (EDCF / bursting) # tx_queue_<queue name>_<param> @@ -676,31 +744,48 @@ auth_algs=1 # to the clients. # # Low priority / AC_BK = background -tx_queue_data3_aifs=7 -tx_queue_data3_cwmin=15 -tx_queue_data3_cwmax=1023 -tx_queue_data3_burst=0 +#tx_queue_data3_aifs=7 +#tx_queue_data3_cwmin=15 +#tx_queue_data3_cwmax=1023 +#tx_queue_data3_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0 # # Normal priority / AC_BE = best effort -tx_queue_data2_aifs=3 -tx_queue_data2_cwmin=15 -tx_queue_data2_cwmax=63 -tx_queue_data2_burst=0 +#tx_queue_data2_aifs=3 +#tx_queue_data2_cwmin=15 +#tx_queue_data2_cwmax=63 +#tx_queue_data2_burst=0 # Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0 # # High priority / AC_VI = video -tx_queue_data1_aifs=1 -tx_queue_data1_cwmin=7 -tx_queue_data1_cwmax=15 -tx_queue_data1_burst=3.0 +#tx_queue_data1_aifs=1 +#tx_queue_data1_cwmin=7 +#tx_queue_data1_cwmax=15 +#tx_queue_data1_burst=3.0 # Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0 # # Highest priority / AC_VO = voice -tx_queue_data0_aifs=1 -tx_queue_data0_cwmin=3 -tx_queue_data0_cwmax=7 -tx_queue_data0_burst=1.5 +#tx_queue_data0_aifs=1 +#tx_queue_data0_cwmin=3 +#tx_queue_data0_cwmax=7 +#tx_queue_data0_burst=1.5 +# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3 + +# 802.1D Tag (= UP) to AC mappings +# WMM specifies following mapping of data frames to different ACs. This mapping +# can be configured using Linux QoS/tc and sch_pktpri.o module. +# 802.1D Tag 802.1D Designation Access Category WMM Designation +# 1 BK AC_BK Background +# 2 - AC_BK Background +# 0 BE AC_BE Best Effort +# 3 EE AC_BE Best Effort +# 4 CL AC_VI Video +# 5 VI AC_VI Video +# 6 VO AC_VO Voice +# 7 NC AC_VO Voice +# Data frames with no priority information: AC_BE +# Management frames: AC_VO +# PS-Poll frames: AC_BE # Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): # for 802.11a or 802.11g networks @@ -716,7 +801,11 @@ tx_queue_data0_burst=1.5 # wmm_ac_??_{cwmin,cwmax} is 0..15 with cwmax >= cwmin. # wmm_enabled=1 - +# +# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] +# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) +#uapsd_advertisement_enabled=1 +# # Low priority / AC_BK = background wmm_ac_bk_cwmin=4 wmm_ac_bk_cwmax=10 @@ -747,3 +836,2586 @@ wmm_ac_vo_cwmin=2 wmm_ac_vo_cwmax=3 wmm_ac_vo_txop_limit=47 wmm_ac_vo_acm=0 +# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 + +# Enable Multi-AP functionality +# 0 = disabled (default) +# 1 = AP support backhaul BSS +# 2 = AP support fronthaul BSS +# 3 = AP supports both backhaul BSS and fronthaul BSS +#multi_ap=0 + +# Static WEP key configuration +# +# The key number to use when transmitting. +# It must be between 0 and 3, and the corresponding key must be set. +# default: not set +#wep_default_key=0 +# The WEP keys to use. +# A key may be a quoted string or unquoted hexadecimal digits. +# The key length should be 5, 13, or 16 characters, or 10, 26, or 32 +# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or +# 128-bit (152-bit) WEP is used. +# Only the default key must be supplied; the others are optional. +# default: not set +#wep_key0=123456789a +#wep_key1="vwxyz" +#wep_key2=0102030405060708090a0b0c0d +#wep_key3=".2.4.6.8.0.23" + +# Station inactivity limit +# +# If a station does not send anything in ap_max_inactivity seconds, an +# empty data frame is sent to it in order to verify whether it is +# still in range. If this frame is not ACKed, the station will be +# disassociated and then deauthenticated. This feature is used to +# clear station table of old entries when the STAs move out of the +# range. +# +# The station can associate again with the AP if it is still in range; +# this inactivity poll is just used as a nicer way of verifying +# inactivity; i.e., client will not report broken connection because +# disassociation frame is not sent immediately without first polling +# the STA with a data frame. +# default: 300 (i.e., 5 minutes) +#ap_max_inactivity=300 +# +# The inactivity polling can be disabled to disconnect stations based on +# inactivity timeout so that idle stations are more likely to be disconnected +# even if they are still in range of the AP. This can be done by setting +# skip_inactivity_poll to 1 (default 0). +#skip_inactivity_poll=0 + +# Disassociate stations based on excessive transmission failures or other +# indications of connection loss. This depends on the driver capabilities and +# may not be available with all drivers. +#disassoc_low_ack=1 + +# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to +# remain asleep). Default: 65535 (no limit apart from field size) +#max_listen_interval=100 + +# WDS (4-address frame) mode with per-station virtual interfaces +# (only supported with driver=nl80211) +# This mode allows associated stations to use 4-address frames to allow layer 2 +# bridging to be used. +#wds_sta=1 + +# If bridge parameter is set, the WDS STA interface will be added to the same +# bridge by default. This can be overridden with the wds_bridge parameter to +# use a separate bridge. +#wds_bridge=wds-br0 + +# Start the AP with beaconing disabled by default. +#start_disabled=0 + +# Client isolation can be used to prevent low-level bridging of frames between +# associated stations in the BSS. By default, this bridging is allowed. +#ap_isolate=1 + +# BSS Load update period (in BUs) +# This field is used to enable and configure adding a BSS Load element into +# Beacon and Probe Response frames. +#bss_load_update_period=50 + +# Channel utilization averaging period (in BUs) +# This field is used to enable and configure channel utilization average +# calculation with bss_load_update_period. This should be in multiples of +# bss_load_update_period for more accurate calculation. +#chan_util_avg_period=600 + +# Fixed BSS Load value for testing purposes +# This field can be used to configure hostapd to add a fixed BSS Load element +# into Beacon and Probe Response frames for testing purposes. The format is +# <station count>:<channel utilization>:<available admission capacity> +#bss_load_test=12:80:20000 + +# Multicast to unicast conversion +# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and +# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent +# to each station separately, with the DA replaced by their own MAC address +# rather than the group address. +# +# Note that this may break certain expectations of the receiver, such as the +# ability to drop unicast IP packets received within multicast L2 frames, or the +# ability to not send ICMP destination unreachable messages for packets received +# in L2 multicast (which is required, but the receiver can't tell the difference +# if this new option is enabled). +# +# This also doesn't implement the 802.11 DMS (directed multicast service). +# +#multicast_to_unicast=0 + +# Send broadcast Deauthentication frame on AP start/stop +# Default: 1 (enabled) +#broadcast_deauth=1 + +# Get notifications for received Management frames on control interface +# Default: 0 (disabled) +#notify_mgmt_frames=0 + +##### IEEE 802.11n related configuration ###################################### + +# ieee80211n: Whether IEEE 802.11n (HT) is enabled +# 0 = disabled (default) +# 1 = enabled +# Note: You will also need to enable WMM for full HT functionality. +# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band. +#ieee80211n=1 + +# disable_11n: Boolean (0/1) to disable HT for a specific BSS +#disable_11n=0 + +# ht_capab: HT capabilities (list of flags) +# LDPC coding capability: [LDPC] = supported +# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary +# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz +# with secondary channel above the primary channel +# (20 MHz only if neither is set) +# Note: There are limits on which channels can be used with HT40- and +# HT40+. Following table shows the channels that may be available for +# HT40- and HT40+ use per IEEE 802.11n Annex J: +# freq HT40- HT40+ +# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) +# 5 GHz 40,48,56,64 36,44,52,60 +# (depending on the location, not all of these channels may be available +# for use) +# Please note that 40 MHz channels may switch their primary and secondary +# channels if needed or creation of 40 MHz channel maybe rejected based +# on overlapping BSSes. These changes are done automatically when hostapd +# is setting up the 40 MHz channel. +# HT-greenfield: [GF] (disabled if not set) +# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) +# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) +# Tx STBC: [TX-STBC] (disabled if not set) +# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial +# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC +# disabled if none of these set +# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) +# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not +# set) +# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) +# 40 MHz intolerant [40-INTOLERANT] (not advertised if not set) +# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) +#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] + +# Require stations to support HT PHY (reject association if they do not) +#require_ht=1 + +# If set non-zero, require stations to perform scans of overlapping +# channels to test for stations which would be affected by 40 MHz traffic. +# This parameter sets the interval in seconds between these scans. Setting this +# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if +# no co-existence issues with neighboring devices are found. +#obss_interval=0 + +##### IEEE 802.11ac related configuration ##################################### + +# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled +# 0 = disabled (default) +# 1 = enabled +# Note: You will also need to enable WMM for full VHT functionality. +# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT. +#ieee80211ac=1 + +# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS +#disable_11ac=0 + +# vht_capab: VHT capabilities (list of flags) +# +# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454] +# Indicates maximum MPDU length +# 0 = 3895 octets (default) +# 1 = 7991 octets +# 2 = 11454 octets +# 3 = reserved +# +# supported_chan_width: [VHT160] [VHT160-80PLUS80] +# Indicates supported Channel widths +# 0 = 160 MHz & 80+80 channel widths are not supported (default) +# 1 = 160 MHz channel width is supported +# 2 = 160 MHz & 80+80 channel widths are supported +# 3 = reserved +# +# Rx LDPC coding capability: [RXLDPC] +# Indicates support for receiving LDPC coded pkts +# 0 = Not supported (default) +# 1 = Supported +# +# Short GI for 80 MHz: [SHORT-GI-80] +# Indicates short GI support for reception of packets transmitted with TXVECTOR +# params format equal to VHT and CBW = 80Mhz +# 0 = Not supported (default) +# 1 = Supported +# +# Short GI for 160 MHz: [SHORT-GI-160] +# Indicates short GI support for reception of packets transmitted with TXVECTOR +# params format equal to VHT and CBW = 160Mhz +# 0 = Not supported (default) +# 1 = Supported +# +# Tx STBC: [TX-STBC-2BY1] +# Indicates support for the transmission of at least 2x1 STBC +# 0 = Not supported (default) +# 1 = Supported +# +# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234] +# Indicates support for the reception of PPDUs using STBC +# 0 = Not supported (default) +# 1 = support of one spatial stream +# 2 = support of one and two spatial streams +# 3 = support of one, two and three spatial streams +# 4 = support of one, two, three and four spatial streams +# 5,6,7 = reserved +# +# SU Beamformer Capable: [SU-BEAMFORMER] +# Indicates support for operation as a single user beamformer +# 0 = Not supported (default) +# 1 = Supported +# +# SU Beamformee Capable: [SU-BEAMFORMEE] +# Indicates support for operation as a single user beamformee +# 0 = Not supported (default) +# 1 = Supported +# +# Compressed Steering Number of Beamformer Antennas Supported: +# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4] +# Beamformee's capability indicating the maximum number of beamformer +# antennas the beamformee can support when sending compressed beamforming +# feedback +# If SU beamformer capable, set to maximum value minus 1 +# else reserved (default) +# +# Number of Sounding Dimensions: +# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4] +# Beamformer's capability indicating the maximum value of the NUM_STS parameter +# in the TXVECTOR of a VHT NDP +# If SU beamformer capable, set to maximum value minus 1 +# else reserved (default) +# +# MU Beamformer Capable: [MU-BEAMFORMER] +# Indicates support for operation as an MU beamformer +# 0 = Not supported or sent by Non-AP STA (default) +# 1 = Supported +# +# VHT TXOP PS: [VHT-TXOP-PS] +# Indicates whether or not the AP supports VHT TXOP Power Save Mode +# or whether or not the STA is in VHT TXOP Power Save mode +# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS +# mode +# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save +# mode +# +# +HTC-VHT Capable: [HTC-VHT] +# Indicates whether or not the STA supports receiving a VHT variant HT Control +# field. +# 0 = Not supported (default) +# 1 = supported +# +# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7] +# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv +# This field is an integer in the range of 0 to 7. +# The length defined by this field is equal to +# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets +# +# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3] +# Indicates whether or not the STA supports link adaptation using VHT variant +# HT Control field +# If +HTC-VHTcapable is 1 +# 0 = (no feedback) if the STA does not provide VHT MFB (default) +# 1 = reserved +# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB +# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the +# STA provides unsolicited VHT MFB +# Reserved if +HTC-VHTcapable is 0 +# +# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN] +# Indicates the possibility of Rx antenna pattern change +# 0 = Rx antenna pattern might change during the lifetime of an association +# 1 = Rx antenna pattern does not change during the lifetime of an association +# +# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN] +# Indicates the possibility of Tx antenna pattern change +# 0 = Tx antenna pattern might change during the lifetime of an association +# 1 = Tx antenna pattern does not change during the lifetime of an association +#vht_capab=[SHORT-GI-80][HTC-VHT] +# +# Require stations to support VHT PHY (reject association if they do not) +#require_vht=1 + +# 0 = 20 or 40 MHz operating Channel width +# 1 = 80 MHz channel width +# 2 = 160 MHz channel width +# 3 = 80+80 MHz channel width +#vht_oper_chwidth=1 +# +# center freq = 5 GHz + (5 * index) +# So index 42 gives center freq 5.210 GHz +# which is channel 42 in 5G band +# +#vht_oper_centr_freq_seg0_idx=42 +# +# center freq = 5 GHz + (5 * index) +# So index 159 gives center freq 5.795 GHz +# which is channel 159 in 5G band +# +#vht_oper_centr_freq_seg1_idx=159 + +# Workaround to use station's nsts capability in (Re)Association Response frame +# This may be needed with some deployed devices as an interoperability +# workaround for beamforming if the AP's capability is greater than the +# station's capability. This is disabled by default and can be enabled by +# setting use_sta_nsts=1. +#use_sta_nsts=0 + +##### IEEE 802.11ax related configuration ##################################### + +#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled +# 0 = disabled (default) +# 1 = enabled +#ieee80211ax=1 + +# disable_11ax: Boolean (0/1) to disable HE for a specific BSS +#disable_11ax=0 + +#he_su_beamformer: HE single user beamformer support +# 0 = not supported (default) +# 1 = supported +#he_su_beamformer=1 + +#he_su_beamformee: HE single user beamformee support +# 0 = not supported (default) +# 1 = supported +#he_su_beamformee=1 + +#he_mu_beamformer: HE multiple user beamformer support +# 0 = not supported (default) +# 1 = supported +#he_mu_beamformer=1 + +# he_bss_color: BSS color (1-63) +#he_bss_color=1 + +# he_bss_color_partial: BSS color AID equation +#he_bss_color_partial=0 + +#he_default_pe_duration: The duration of PE field in an HE PPDU in us +# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us +#he_default_pe_duration=0 + +#he_twt_required: Whether TWT is required +# 0 = not required (default) +# 1 = required +#he_twt_required=0 + +#he_twt_responder: Whether TWT (HE) responder is enabled +# 0 = disabled +# 1 = enabled if supported by the driver (default) +#he_twt_responder=1 + +#he_rts_threshold: Duration of STA transmission +# 0 = not set (default) +# unsigned integer = duration in units of 16 us +#he_rts_threshold=0 + +#he_er_su_disable: Disable 242-tone HE ER SU PPDU reception by the AP +# 0 = enable reception (default) +# 1 = disable reception +#he_er_su_disable=0 + +# HE operating channel information; see matching vht_* parameters for details. +# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80 +# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center +# frequency of the lower frequency segment. he_oper_centr_freq_seg1_idx field +# is used only with 80+80 MHz bandwidth operation and it is used to transmit +# the center frequency of the second segment. +# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset. +# For example idx=3 would result in 5965 MHz center frequency. In addition, +# he_oper_chwidth is ignored, and the channel width is derived from the +# configured operating class or center frequency indexes (see +# IEEE P802.11ax/D6.1 Annex E, Table E-4). +#he_oper_chwidth +#he_oper_centr_freq_seg0_idx +#he_oper_centr_freq_seg1_idx + +#he_basic_mcs_nss_set: Basic NSS/MCS set +# 16-bit combination of 2-bit values of Max HE-MCS For 1..8 SS; each 2-bit +# value having following meaning: +# 0 = HE-MCS 0-7, 1 = HE-MCS 0-9, 2 = HE-MCS 0-11, 3 = not supported +#he_basic_mcs_nss_set + +#he_mu_edca_qos_info_param_count +#he_mu_edca_qos_info_q_ack +#he_mu_edca_qos_info_queue_request=1 +#he_mu_edca_qos_info_txop_request +#he_mu_edca_ac_be_aifsn=0 +#he_mu_edca_ac_be_ecwmin=15 +#he_mu_edca_ac_be_ecwmax=15 +#he_mu_edca_ac_be_timer=255 +#he_mu_edca_ac_bk_aifsn=0 +#he_mu_edca_ac_bk_aci=1 +#he_mu_edca_ac_bk_ecwmin=15 +#he_mu_edca_ac_bk_ecwmax=15 +#he_mu_edca_ac_bk_timer=255 +#he_mu_edca_ac_vi_ecwmin=15 +#he_mu_edca_ac_vi_ecwmax=15 +#he_mu_edca_ac_vi_aifsn=0 +#he_mu_edca_ac_vi_aci=2 +#he_mu_edca_ac_vi_timer=255 +#he_mu_edca_ac_vo_aifsn=0 +#he_mu_edca_ac_vo_aci=3 +#he_mu_edca_ac_vo_ecwmin=15 +#he_mu_edca_ac_vo_ecwmax=15 +#he_mu_edca_ac_vo_timer=255 + +# Spatial Reuse Parameter Set +# +# SR Control field value +# B0 = PSR Disallowed +# B1 = Non-SRG OBSS PD SR Disallowed +# B2 = Non-SRG Offset Present +# B3 = SRG Information Present +# B4 = HESIGA_Spatial_reuse_value15_allowed +#he_spr_sr_control +# +# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1) +#he_spr_non_srg_obss_pd_max_offset + +# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1) +#he_spr_srg_obss_pd_min_offset +# +# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1) +#he_spr_srg_obss_pd_max_offset +# +# SPR SRG BSS Color (included if he_spr_sr_control B3=1) +# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter +# Set element that indicates the BSS color values used by members of the +# SRG of which the transmitting STA is a member. The value is in range of 0-63. +#he_spr_srg_bss_colors=1 2 10 63 +# +# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1) +# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse +# Parameter Set element that indicates the Partial BSSID values used by members +# of the SRG of which the transmitting STA is a member. The value range +# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest +# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit +# corresponds to Partial BSSID value 63. +#he_spr_srg_partial_bssid=0 1 3 63 +# +#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities. +# Indicates maximum MPDU length +# 0 = 3895 octets +# 1 = 7991 octets +# 2 = 11454 octets (default) +#he_6ghz_max_mpdu=2 +# +#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band +# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that +# the STA can receive. This field is an integer in the range of 0 to 7. +# The length defined by this field is equal to +# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets +# 0 = AMPDU length of 8k +# 1 = AMPDU length of 16k +# 2 = AMPDU length of 32k +# 3 = AMPDU length of 65k +# 4 = AMPDU length of 131k +# 5 = AMPDU length of 262k +# 6 = AMPDU length of 524k +# 7 = AMPDU length of 1048k (default) +#he_6ghz_max_ampdu_len_exp=7 +# +#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability. +# Indicates the possibility of Rx antenna pattern change +# 0 = Rx antenna pattern might change during the lifetime of an association +# 1 = Rx antenna pattern does not change during the lifetime of an association +# (default) +#he_6ghz_rx_ant_pat=1 +# +#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability. +# Indicates the possibility of Tx antenna pattern change +# 0 = Tx antenna pattern might change during the lifetime of an association +# 1 = Tx antenna pattern does not change during the lifetime of an association +# (default) +#he_6ghz_tx_ant_pat=1 + +# Unsolicited broadcast Probe Response transmission settings +# This is for the 6 GHz band only. If the interval is set to a non-zero value, +# the AP schedules unsolicited broadcast Probe Response frames to be +# transmitted for in-band discovery. Refer to +# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning. +# Valid range: 0..20 TUs; default is 0 (disabled) +#unsol_bcast_probe_resp_interval=0 + +##### IEEE 802.1X-2004 related configuration ################################## + +# Require IEEE 802.1X authorization +#ieee8021x=1 + +# IEEE 802.1X/EAPOL version +# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL +# version 2. However, there are many client implementations that do not handle +# the new version number correctly (they seem to drop the frames completely). +# In order to make hostapd interoperate with these clients, the version number +# can be set to the older version (1) with this configuration value. +# Note: When using MACsec, eapol_version shall be set to 3, which is +# defined in IEEE Std 802.1X-2010. +#eapol_version=2 + +# Optional displayable message sent with EAP Request-Identity. The first \0 +# in this string will be converted to ASCII-0 (nul). This can be used to +# separate network info (comma separated list of attribute=value pairs); see, +# e.g., RFC 4284. +#eap_message=hello +#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com + +# WEP rekeying (disabled if key lengths are not set or are set to 0) +# Key lengths for default/broadcast and individual/unicast keys: +# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) +# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) +#wep_key_len_broadcast=5 +#wep_key_len_unicast=5 +# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once) +#wep_rekey_period=300 + +# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if +# only broadcast keys are used) +eapol_key_index_workaround=0 + +# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable +# reauthentication). +# Note: Reauthentications may enforce a disconnection, check the related +# parameter wpa_deny_ptk0_rekey for details. +#eap_reauth_period=3600 + +# Use PAE group address (01:80:c2:00:00:03) instead of individual target +# address when sending EAPOL frames with driver=wired. This is the most common +# mechanism used in wired authentication, but it also requires that the port +# is only used by one station. +#use_pae_group_addr=1 + +# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696) +# +# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before +# EAP-Identity/Request +#erp_send_reauth_start=1 +# +# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not +# set (no local ER server). This is also used by the integrated EAP server if +# ERP is enabled (eap_server_erp=1). +#erp_domain=example.com + +##### MACsec ################################################################## + +# macsec_policy: IEEE 802.1X/MACsec options +# This determines how sessions are secured with MACsec (only for MACsec +# drivers). +# 0: MACsec not in use (default) +# 1: MACsec enabled - Should secure, accept key server's advice to +# determine whether to use a secure session or not. +# +# macsec_integ_only: IEEE 802.1X/MACsec transmit mode +# This setting applies only when MACsec is in use, i.e., +# - macsec_policy is enabled +# - the key server has decided to enable MACsec +# 0: Encrypt traffic (default) +# 1: Integrity only +# +# macsec_replay_protect: IEEE 802.1X/MACsec replay protection +# This setting applies only when MACsec is in use, i.e., +# - macsec_policy is enabled +# - the key server has decided to enable MACsec +# 0: Replay protection disabled (default) +# 1: Replay protection enabled +# +# macsec_replay_window: IEEE 802.1X/MACsec replay protection window +# This determines a window in which replay is tolerated, to allow receipt +# of frames that have been misordered by the network. +# This setting applies only when MACsec replay protection active, i.e., +# - macsec_replay_protect is enabled +# - the key server has decided to enable MACsec +# 0: No replay window, strict check (default) +# 1..2^32-1: number of packets that could be misordered +# +# macsec_port: IEEE 802.1X/MACsec port +# Port component of the SCI +# Range: 1-65534 (default: 1) +# +# mka_priority (Priority of MKA Actor) +# Range: 0..255 (default: 255) +# +# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode +# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair. +# In this mode, instances of hostapd can act as MACsec peers. The peer +# with lower priority will become the key server and start distributing SAKs. +# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit) +# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits) +# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string +# (2..64 hex-digits) + +##### Integrated EAP server ################################################### + +# Optionally, hostapd can be configured to use an integrated EAP server +# to process EAP authentication locally without need for an external RADIUS +# server. This functionality can be used both as a local authentication server +# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices. + +# Use integrated EAP server instead of external RADIUS authentication +# server. This is also needed if hostapd is configured to act as a RADIUS +# authentication server. +eap_server=0 + +# Path for EAP server user database +# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db" +# to use SQLite database instead of a text file. +#eap_user_file=/etc/hostapd.eap_user + +# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS +#ca_cert=/etc/hostapd.ca.pem + +# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS +#server_cert=/etc/hostapd.server.pem + +# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS +# This may point to the same file as server_cert if both certificate and key +# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be +# used by commenting out server_cert and specifying the PFX file as the +# private_key. +#private_key=/etc/hostapd.server.prv + +# Passphrase for private key +#private_key_passwd=secret passphrase + +# An alternative server certificate and private key can be configured with the +# following parameters (with values just like the parameters above without the +# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots +# for both server certificates and/or client certificates). +# +# The main use case for this alternative server certificate configuration is to +# enable both RSA and ECC public keys. The server will pick which one to use +# based on the client preferences for the cipher suite (in the TLS ClientHello +# message). It should be noted that number of deployed EAP peer implementations +# do not filter out the cipher suite list based on their local configuration and +# as such, configuration of alternative types of certificates on the server may +# result in interoperability issues. +#server_cert2=/etc/hostapd.server-ecc.pem +#private_key2=/etc/hostapd.server-ecc.prv +#private_key_passwd2=secret passphrase + + +# Server identity +# EAP methods that provide mechanism for authenticated server identity delivery +# use this value. If not set, "hostapd" is used as a default. +#server_id=server.example.com + +# Enable CRL verification. +# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a +# valid CRL signed by the CA is required to be included in the ca_cert file. +# This can be done by using PEM format for CA certificate and CRL and +# concatenating these into one file. Whenever CRL changes, hostapd needs to be +# restarted to take the new CRL into use. Alternatively, crl_reload_interval can +# be used to configure periodic updating of the loaded CRL information. +# 0 = do not verify CRLs (default) +# 1 = check the CRL of the user certificate +# 2 = check all CRLs in the certificate path +#check_crl=1 + +# Specify whether to ignore certificate CRL validity time mismatches with +# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID. +# +# 0 = ignore errors +# 1 = do not ignore errors (default) +#check_crl_strict=1 + +# CRL reload interval in seconds +# This can be used to reload ca_cert file and the included CRL on every new TLS +# session if difference between last reload and the current reload time in +# seconds is greater than crl_reload_interval. +# Note: If interval time is very short, CPU overhead may be negatively affected +# and it is advised to not go below 300 seconds. +# This is applicable only with check_crl values 1 and 2. +# 0 = do not reload CRLs (default) +# crl_reload_interval = 300 + +# If check_cert_subject is set, the value of every field will be checked +# against the DN of the subject in the client certificate. If the values do +# not match, the certificate verification will fail, rejecting the user. +# This option allows hostapd to match every individual field in the right order +# against the DN of the subject in the client certificate. +# +# For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will check +# every individual DN field of the subject in the client certificate. If OU=XYZ +# comes first in terms of the order in the client certificate (DN field of +# client certificate C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), hostapd will reject the +# client because the order of 'OU' is not matching the specified string in +# check_cert_subject. +# +# This option also allows '*' as a wildcard. This option has some limitation. +# It can only be used as per the following example. +# +# For example, check_cert_subject=C=US/O=XX/OU=Production* and we have two +# clients and DN of the subject in the first client certificate is +# (C=US/O=XX/OU=Production Unit) and DN of the subject in the second client is +# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both +# clients because the value of 'OU' field in both client certificates matches +# 'OU' value in 'check_cert_subject' up to 'wildcard'. +# +# * (Allow all clients, e.g., check_cert_subject=*) +#check_cert_subject=string + +# TLS Session Lifetime in seconds +# This can be used to allow TLS sessions to be cached and resumed with an +# abbreviated handshake when using EAP-TLS/TTLS/PEAP. +# (default: 0 = session caching and resumption disabled) +#tls_session_lifetime=3600 + +# TLS flags +# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on +# the TLS library, these may be disabled by default to enforce stronger +# security) +# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests +# the TLS library to accept certificates even if they are not currently +# valid, i.e., have expired or have not yet become valid; this should be +# used only for testing purposes) +# [DISABLE-TLSv1.0] = disable use of TLSv1.0 +# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows +# systemwide TLS policies to be overridden) +# [DISABLE-TLSv1.1] = disable use of TLSv1.1 +# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows +# systemwide TLS policies to be overridden) +# [DISABLE-TLSv1.2] = disable use of TLSv1.2 +# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows +# systemwide TLS policies to be overridden) +# [DISABLE-TLSv1.3] = disable use of TLSv1.3 +# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default) +#tls_flags=[flag1][flag2]... + +# Maximum number of EAP message rounds with data (default: 100) +#max_auth_rounds=100 + +# Maximum number of short EAP message rounds (default: 50) +#max_auth_rounds_short=50 + +# Cached OCSP stapling response (DER encoded) +# If set, this file is sent as a certificate status response by the EAP server +# if the EAP peer requests certificate status in the ClientHello message. +# This cache file can be updated, e.g., by running following command +# periodically to get an update from the OCSP responder: +# openssl ocsp \ +# -no_nonce \ +# -CAfile /etc/hostapd.ca.pem \ +# -issuer /etc/hostapd.ca.pem \ +# -cert /etc/hostapd.server.pem \ +# -url http://ocsp.example.com:8888/ \ +# -respout /tmp/ocsp-cache.der +#ocsp_stapling_response=/tmp/ocsp-cache.der + +# Cached OCSP stapling response list (DER encoded OCSPResponseList) +# This is similar to ocsp_stapling_response, but the extended version defined in +# RFC 6961 to allow multiple OCSP responses to be provided. +#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der + +# dh_file: File path to DH/DSA parameters file (in PEM format) +# This is an optional configuration file for setting parameters for an +# ephemeral DH key exchange. In most cases, the default RSA authentication does +# not use this configuration. However, it is possible setup RSA to use +# ephemeral DH key exchange. In addition, ciphers with DSA keys always use +# ephemeral DH keys. This can be used to achieve forward secrecy. If the file +# is in DSA parameters format, it will be automatically converted into DH +# params. This parameter is required if anonymous EAP-FAST is used. +# You can generate DH parameters file with OpenSSL, e.g., +# "openssl dhparam -out /etc/hostapd.dh.pem 2048" +#dh_file=/etc/hostapd.dh.pem + +# OpenSSL cipher string +# +# This is an OpenSSL specific configuration option for configuring the default +# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW" +# by default) is used. +# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation +# on cipher suite configuration. This is applicable only if hostapd is built to +# use OpenSSL. +#openssl_ciphers=DEFAULT:!EXP:!LOW + +# OpenSSL ECDH curves +# +# This is an OpenSSL specific configuration option for configuring the ECDH +# curves for EAP-TLS/TTLS/PEAP/FAST server. If not set, automatic curve +# selection is enabled. If set to an empty string, ECDH curve configuration is +# not done (the exact library behavior depends on the library version). +# Otherwise, this is a colon separated list of the supported curves (e.g., +# P-521:P-384:P-256). This is applicable only if hostapd is built to use +# OpenSSL. This must not be used for Suite B cases since the same OpenSSL +# parameter is set differently in those cases and this might conflict with that +# design. +#openssl_ecdh_curves=P-521:P-384:P-256 + +# Fragment size for EAP methods +#fragment_size=1400 + +# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters +# using the IANA repository for IKE (RFC 2409). +#pwd_group=19 + +# Configuration data for EAP-SIM database/authentication gateway interface. +# This is a text string in implementation specific format. The example +# implementation in eap_sim_db.c uses this as the UNIX domain socket name for +# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" +# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config), +# database file can be described with an optional db=<path> parameter. +#eap_sim_db=unix:/tmp/hlr_auc_gw.sock +#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db + +# EAP-SIM DB request timeout +# This parameter sets the maximum time to wait for a database request response. +# The parameter value is in seconds. +#eap_sim_db_timeout=1 + +# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, +# random value. It is configured as a 16-octet value in hex format. It can be +# generated, e.g., with the following command: +# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' ' +#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f + +# EAP-FAST authority identity (A-ID) +# A-ID indicates the identity of the authority that issues PACs. The A-ID +# should be unique across all issuing servers. In theory, this is a variable +# length field, but due to some existing implementations requiring A-ID to be +# 16 octets in length, it is strongly recommended to use that length for the +# field to provide interoperability with deployed peer implementations. This +# field is configured in hex format. +#eap_fast_a_id=101112131415161718191a1b1c1d1e1f + +# EAP-FAST authority identifier information (A-ID-Info) +# This is a user-friendly name for the A-ID. For example, the enterprise name +# and server name in a human-readable format. This field is encoded as UTF-8. +#eap_fast_a_id_info=test server + +# Enable/disable different EAP-FAST provisioning modes: +#0 = provisioning disabled +#1 = only anonymous provisioning allowed +#2 = only authenticated provisioning allowed +#3 = both provisioning modes allowed (default) +#eap_fast_prov=3 + +# EAP-FAST PAC-Key lifetime in seconds (hard limit) +#pac_key_lifetime=604800 + +# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard +# limit). The server will generate a new PAC-Key when this number of seconds +# (or fewer) of the lifetime remains. +#pac_key_refresh_time=86400 + +# EAP-TEAP authentication type +# 0 = inner EAP (default) +# 1 = Basic-Password-Auth +# 2 = Do not require Phase 2 authentication if client can be authenticated +# during Phase 1 +#eap_teap_auth=0 + +# EAP-TEAP authentication behavior when using PAC +# 0 = perform inner authentication (default) +# 1 = skip inner authentication (inner EAP/Basic-Password-Auth) +#eap_teap_pac_no_inner=0 + +# EAP-TEAP behavior with Result TLV +# 0 = include with Intermediate-Result TLV (default) +# 1 = send in a separate message (for testing purposes) +#eap_teap_separate_result=0 + +# EAP-TEAP identities +# 0 = allow any identity type (default) +# 1 = require user identity +# 2 = require machine identity +# 3 = request user identity; accept either user or machine identity +# 4 = request machine identity; accept either user or machine identity +# 5 = require both user and machine identity +#eap_teap_id=0 + +# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND +# (default: 0 = disabled). +#eap_sim_aka_result_ind=1 + +# EAP-SIM and EAP-AKA identity options +# 0 = do not use pseudonyms or fast reauthentication +# 1 = use pseudonyms, but not fast reauthentication +# 2 = do not use pseudonyms, but use fast reauthentication +# 3 = use pseudonyms and use fast reauthentication (default) +#eap_sim_id=3 + +# Trusted Network Connect (TNC) +# If enabled, TNC validation will be required before the peer is allowed to +# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other +# EAP method is enabled, the peer will be allowed to connect without TNC. +#tnc=1 + +# EAP Re-authentication Protocol (ERP) - RFC 6696 +# +# Whether to enable ERP on the EAP server. +#eap_server_erp=1 + + +##### RADIUS client configuration ############################################# +# for IEEE 802.1X with external Authentication Server, IEEE 802.11 +# authentication with external ACL for MAC addresses, and accounting + +# The own IP address of the access point (used as NAS-IP-Address) +own_ip_addr=127.0.0.1 + +# NAS-Identifier string for RADIUS messages. When used, this should be unique +# to the NAS within the scope of the RADIUS server. Please note that hostapd +# uses a separate RADIUS client for each BSS and as such, a unique +# nas_identifier value should be configured separately for each BSS. This is +# particularly important for cases where RADIUS accounting is used +# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions +# and that may get interpreted as applying to all BSSes if the same +# NAS-Identifier value is used.) For example, a fully qualified domain name +# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here. +# +# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and +# 48 octets long. +# +# It is mandatory to configure either own_ip_addr or nas_identifier to be +# compliant with the RADIUS protocol. When using RADIUS accounting, it is +# strongly recommended that nas_identifier is set to a unique value for each +# BSS. +#nas_identifier=ap.example.com + +# RADIUS client forced local IP address for the access point +# Normally the local IP address is determined automatically based on configured +# IP addresses, but this field can be used to force a specific address to be +# used, e.g., when the device has multiple IP addresses. +#radius_client_addr=127.0.0.1 + +# RADIUS client forced local interface. Helps run properly with VRF +# Default is none set which allows the network stack to pick the appropriate +# interface automatically. +# Example below binds to eth0 +#radius_client_dev=eth0 + +# RADIUS authentication server +#auth_server_addr=127.0.0.1 +#auth_server_port=1812 +#auth_server_shared_secret=secret + +# RADIUS accounting server +#acct_server_addr=127.0.0.1 +#acct_server_port=1813 +#acct_server_shared_secret=secret + +# Secondary RADIUS servers; to be used if primary one does not reply to +# RADIUS packets. These are optional and there can be more than one secondary +# server listed. +#auth_server_addr=127.0.0.2 +#auth_server_port=1812 +#auth_server_shared_secret=secret2 +# +#acct_server_addr=127.0.0.2 +#acct_server_port=1813 +#acct_server_shared_secret=secret2 + +# Retry interval for trying to return to the primary RADIUS server (in +# seconds). RADIUS client code will automatically try to use the next server +# when the current server is not replying to requests. If this interval is set, +# primary server will be retried after configured amount of time even if the +# currently used secondary server is still working. +#radius_retry_primary_interval=600 + + +# Interim accounting update interval +# If this is set (larger than 0) and acct_server is configured, hostapd will +# send interim accounting updates every N seconds. Note: if set, this overrides +# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this +# value should not be configured in hostapd.conf, if RADIUS server is used to +# control the interim interval. +# This value should not be less 600 (10 minutes) and must not be less than +# 60 (1 minute). +#radius_acct_interim_interval=600 + +# Request Chargeable-User-Identity (RFC 4372) +# This parameter can be used to configure hostapd to request CUI from the +# RADIUS server by including Chargeable-User-Identity attribute into +# Access-Request packets. +#radius_request_cui=1 + +# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN +# is used for the stations. This information is parsed from following RADIUS +# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), +# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value +# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can +# be used to set static client MAC address to VLAN ID mapping. +# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2 +# passphrase from wpa_psk_file or vlan_id parameter from sae_password. +# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used +# 1 = optional; use default interface if RADIUS server does not include VLAN ID +# 2 = required; reject authentication if RADIUS server does not include VLAN ID +#dynamic_vlan=0 + +# Per-Station AP_VLAN interface mode +# If enabled, each station is assigned its own AP_VLAN interface. +# This implies per-station group keying and ebtables filtering of inter-STA +# traffic (when passed through the AP). +# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be +# added to the bridge given by the "bridge" configuration option (see above). +# Otherwise, it will be added to the per-VLAN bridge. +# 0 = disabled (default) +# 1 = enabled +#per_sta_vif=0 + +# VLAN interface list for dynamic VLAN mode is read from a separate text file. +# This list is used to map VLAN ID from the RADIUS server to a network +# interface. Each station is bound to one interface in the same way as with +# multiple BSSIDs or SSIDs. Each line in this text file is defining a new +# interface and the line must include VLAN ID and interface name separated by +# white space (space or tab). +# If no entries are provided by this file, the station is statically mapped +# to <bss-iface>.<vlan-id> interfaces. +# Each line can optionally also contain the name of a bridge to add the VLAN to +#vlan_file=/etc/hostapd.vlan + +# Interface where 802.1q tagged packets should appear when a RADIUS server is +# used to determine which VLAN a station is on. hostapd creates a bridge for +# each VLAN. Then hostapd adds a VLAN interface (associated with the interface +# indicated by 'vlan_tagged_interface') and the appropriate wireless interface +# to the bridge. +#vlan_tagged_interface=eth0 + +# Bridge (prefix) to add the wifi and the tagged interface to. This gets the +# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given +# and br%s.%d if a tagged interface is given, provided %s = tagged interface +# and %d = VLAN ID. +#vlan_bridge=brvlan + +# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs +# to know how to name it. +# 0 = vlan<XXX>, e.g., vlan1 +# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1 +#vlan_naming=0 + +# Arbitrary RADIUS attributes can be added into Access-Request and +# Accounting-Request packets by specifying the contents of the attributes with +# the following configuration parameters. There can be multiple of these to +# add multiple attributes. These parameters can also be used to override some +# of the attributes added automatically by hostapd. +# Format: <attr_id>[:<syntax:value>] +# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific) +# syntax: s = string (UTF-8), d = integer, x = octet string +# value: attribute value in format indicated by the syntax +# If syntax and value parts are omitted, a null value (single 0x00 octet) is +# used. +# +# Additional Access-Request attributes +# radius_auth_req_attr=<attr_id>[:<syntax:value>] +# Examples: +# Operator-Name = "Operator" +#radius_auth_req_attr=126:s:Operator +# Service-Type = Framed (2) +#radius_auth_req_attr=6:d:2 +# Connect-Info = "testing" (this overrides the automatically generated value) +#radius_auth_req_attr=77:s:testing +# Same Connect-Info value set as a hexdump +#radius_auth_req_attr=77:x:74657374696e67 + +# +# Additional Accounting-Request attributes +# radius_acct_req_attr=<attr_id>[:<syntax:value>] +# Examples: +# Operator-Name = "Operator" +#radius_acct_req_attr=126:s:Operator + +# If SQLite support is included, path to a database from which additional +# RADIUS request attributes are extracted based on the station MAC address. +# +# The schema for the radius_attributes table is: +# id | sta | reqtype | attr : multi-key (sta, reqtype) +# id = autonumber +# sta = station MAC address in `11:22:33:44:55:66` format. +# type = `auth` | `acct` | NULL (match any) +# attr = existing config file format, e.g. `126:s:Test Operator` +#radius_req_attr_sqlite=radius_attr.sqlite + +# Dynamic Authorization Extensions (RFC 5176) +# This mechanism can be used to allow dynamic changes to user session based on +# commands from a RADIUS server (or some other disconnect client that has the +# needed session information). For example, Disconnect message can be used to +# request an associated station to be disconnected. +# +# This is disabled by default. Set radius_das_port to non-zero UDP port +# number to enable. +#radius_das_port=3799 +# +# DAS client (the host that can send Disconnect/CoA requests) and shared secret +# Format: <IP address> <shared secret> +# IP address 0.0.0.0 can be used to allow requests from any address. +#radius_das_client=192.168.1.123 shared secret here +# +# DAS Event-Timestamp time window in seconds +#radius_das_time_window=300 +# +# DAS require Event-Timestamp +#radius_das_require_event_timestamp=1 +# +# DAS require Message-Authenticator +#radius_das_require_message_authenticator=1 + +##### RADIUS authentication server configuration ############################## + +# hostapd can be used as a RADIUS authentication server for other hosts. This +# requires that the integrated EAP server is also enabled and both +# authentication services are sharing the same configuration. + +# File name of the RADIUS clients configuration for the RADIUS server. If this +# commented out, RADIUS server is disabled. +#radius_server_clients=/etc/hostapd.radius_clients + +# The UDP port number for the RADIUS authentication server +#radius_server_auth_port=1812 + +# The UDP port number for the RADIUS accounting server +# Commenting this out or setting this to 0 can be used to disable RADIUS +# accounting while still enabling RADIUS authentication. +#radius_server_acct_port=1813 + +# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) +#radius_server_ipv6=1 + + +##### WPA/IEEE 802.11i configuration ########################################## + +# Enable WPA. Setting this variable configures the AP to require WPA (either +# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either +# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. +# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice. +# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), +# RADIUS authentication server must be configured, and WPA-EAP must be included +# in wpa_key_mgmt. +# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) +# and/or WPA2 (full IEEE 802.11i/RSN): +# bit0 = WPA +# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) +# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2. +# In other words, for WPA3, wpa=2 is used the configuration (and +# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK). +#wpa=2 + +# Extended Key ID support for Individually Addressed frames +# +# Extended Key ID allows to rekey PTK keys without the impacts the "normal" +# PTK rekeying with only a single Key ID 0 has. It can only be used when the +# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher. +# +# 0 = force off, i.e., use only Key ID 0 (default) +# 1 = enable and use Extended Key ID support when possible +# 2 = identical to 1 but start with Key ID 1 when possible +#extended_key_id=0 + +# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit +# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase +# (8..63 characters) that will be converted to PSK. This conversion uses SSID +# so the PSK changes when ASCII passphrase is used and the SSID is changed. +# wpa_psk (dot11RSNAConfigPSKValue) +# wpa_passphrase (dot11RSNAConfigPSKPassPhrase) +#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +#wpa_passphrase=secret passphrase + +# Optionally, WPA PSKs can be read from a separate text file (containing list +# of (PSK,MAC address) pairs. This allows more than one PSK to be configured. +# Use absolute path name to make sure that the files can be read on SIGHUP +# configuration reloads. +#wpa_psk_file=/etc/hostapd.wpa_psk + +# Optionally, WPA passphrase can be received from RADIUS authentication server +# This requires macaddr_acl to be set to 2 (RADIUS) +# 0 = disabled (default) +# 1 = optional; use default passphrase/psk if RADIUS server does not include +# Tunnel-Password +# 2 = required; reject authentication if RADIUS server does not include +# Tunnel-Password +#wpa_psk_radius=0 + +# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The +# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be +# added to enable SHA256-based stronger algorithms. +# WPA-PSK = WPA-Personal / WPA2-Personal +# WPA-PSK-SHA256 = WPA2-Personal using SHA256 +# WPA-EAP = WPA-Enterprise / WPA2-Enterprise +# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256 +# SAE = SAE (WPA3-Personal) +# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite +# FT-PSK = FT with passphrase/PSK +# FT-EAP = FT with EAP +# FT-EAP-SHA384 = FT with EAP using SHA384 +# FT-SAE = FT with SAE +# FILS-SHA256 = Fast Initial Link Setup with SHA256 +# FILS-SHA384 = Fast Initial Link Setup with SHA384 +# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256 +# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384 +# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open) +# DPP = Device Provisioning Protocol +# OSEN = Hotspot 2.0 online signup with encryption +# (dot11RSNAConfigAuthenticationSuitesTable) +#wpa_key_mgmt=WPA-PSK WPA-EAP + +# Set of accepted cipher suites (encryption algorithms) for pairwise keys +# (unicast packets). This is a space separated list of algorithms: +# CCMP = AES in Counter mode with CBC-MAC (CCMP-128) +# TKIP = Temporal Key Integrity Protocol +# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key +# GCMP = Galois/counter mode protocol (GCMP-128) +# GCMP-256 = Galois/counter mode protocol with 256-bit key +# Group cipher suite (encryption algorithm for broadcast and multicast frames) +# is automatically selected based on this configuration. If only CCMP is +# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, +# TKIP will be used as the group cipher. The optional group_cipher parameter can +# be used to override this automatic selection. +# +# (dot11RSNAConfigPairwiseCiphersTable) +# Pairwise cipher for WPA (v1) (default: TKIP) +#wpa_pairwise=TKIP CCMP +# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) +#rsn_pairwise=CCMP + +# Optional override for automatic group cipher selection +# This can be used to select a specific group cipher regardless of which +# pairwise ciphers were enabled for WPA and RSN. It should be noted that +# overriding the group cipher with an unexpected value can result in +# interoperability issues and in general, this parameter is mainly used for +# testing purposes. +#group_cipher=CCMP + +# Time interval for rekeying GTK (broadcast/multicast encryption keys) in +# seconds. (dot11RSNAConfigGroupRekeyTime) +# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the +# group cipher and 600 seconds (once per 10 minutes) when using TKIP as the +# group cipher. +#wpa_group_rekey=86400 + +# Rekey GTK when any STA that possesses the current GTK is leaving the BSS. +# (dot11RSNAConfigGroupRekeyStrict) +#wpa_strict_rekey=1 + +# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is +#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount) +# This value should only be increased when stations are constantly +# deauthenticated during GTK rekeying with the log message +# "group key handshake failed...". +# You should consider to also increase wpa_pairwise_update_count then. +# Range 1..4294967295; default: 4 +#wpa_group_update_count=4 + +# Time interval for rekeying GMK (master key used internally to generate GTKs +# (in seconds). +#wpa_gmk_rekey=86400 + +# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of +# PTK to mitigate some attacks against TKIP deficiencies. +# Warning: PTK rekeying is buggy with many drivers/devices and with such +# devices, the only secure method to rekey the PTK without Extended Key ID +# support requires a disconnection. Check the related parameter +# wpa_deny_ptk0_rekey for details. +#wpa_ptk_rekey=600 + +# Workaround for PTK rekey issues +# +# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually +# Addressed Frames") can degrade the security and stability with some cards. +# To avoid such issues hostapd can replace those PTK rekeys (including EAP +# reauthentications) with disconnects. +# +# Available options: +# 0 = always rekey when configured/instructed (default) +# 1 = only rekey when the local driver is explicitly indicating it can perform +# this operation without issues +# 2 = never allow PTK0 rekeys +#wpa_deny_ptk0_rekey=0 + +# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way +# Handshake are retried per 4-Way Handshake attempt. +# (dot11RSNAConfigPairwiseUpdateCount) +# Range 1..4294967295; default: 4 +#wpa_pairwise_update_count=4 + +# Workaround for key reinstallation attacks +# +# This parameter can be used to disable retransmission of EAPOL-Key frames that +# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This +# is similar to setting wpa_group_update_count=1 and +# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with +# extended timeout on the response to avoid causing issues with stations that +# may use aggressive power saving have very long time in replying to the +# EAPOL-Key messages. +# +# This option can be used to work around key reinstallation attacks on the +# station (supplicant) side in cases those station devices cannot be updated +# for some reason. By removing the retransmissions the attacker cannot cause +# key reinstallation with a delayed frame transmission. This is related to the +# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079, +# CVE-2017-13080, and CVE-2017-13081. +# +# This workaround might cause interoperability issues and reduced robustness of +# key negotiation especially in environments with heavy traffic load due to the +# number of attempts to perform the key exchange is reduced significantly. As +# such, this workaround is disabled by default (unless overridden in build +# configuration). To enable this, set the parameter to 1. +#wpa_disable_eapol_key_retries=1 + +# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up +# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN +# authentication and key handshake before actually associating with a new AP. +# (dot11RSNAPreauthenticationEnabled) +#rsn_preauth=1 +# +# Space separated list of interfaces from which pre-authentication frames are +# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all +# interface that are used for connections to other APs. This could include +# wired interfaces and WDS links. The normal wireless data interface towards +# associated stations (e.g., wlan0) should not be added, since +# pre-authentication is only used with APs other than the currently associated +# one. +#rsn_preauth_interfaces=eth0 + +# ieee80211w: Whether management frame protection (MFP) is enabled +# 0 = disabled (default) +# 1 = optional +# 2 = required +#ieee80211w=0 +# The most common configuration options for this based on the PMF (protected +# management frames) certification program are: +# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256 +# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256 +# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used) +# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE + +# Group management cipher suite +# Default: AES-128-CMAC (BIP) +# Other options (depending on driver support): +# BIP-GMAC-128 +# BIP-GMAC-256 +# BIP-CMAC-256 +# Note: All the stations connecting to the BSS will also need to support the +# selected cipher. The default AES-128-CMAC is the only option that is commonly +# available in deployed devices. +#group_mgmt_cipher=AES-128-CMAC + +# Beacon Protection (management frame protection for Beacon frames) +# This depends on management frame protection being enabled (ieee80211w != 0) +# and beacon protection support indication from the driver. +# 0 = disabled (default) +# 1 = enabled +#beacon_prot=0 + +# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) +# (maximum time to wait for a SA Query response) +# dot11AssociationSAQueryMaximumTimeout, 1...4294967295 +#assoc_sa_query_max_timeout=1000 + +# Association SA Query retry timeout (in TU = 1.024 ms; for MFP) +# (time between two subsequent SA Query requests) +# dot11AssociationSAQueryRetryTimeout, 1...4294967295 +#assoc_sa_query_retry_timeout=201 + +# ocv: Operating Channel Validation +# This is a countermeasure against multi-channel on-path attacks. +# Enabling this depends on the driver's support for OCV when the driver SME is +# used. If hostapd SME is used, this will be enabled just based on this +# configuration. +# Enabling this automatically also enables ieee80211w, if not yet enabled. +# 0 = disabled (default) +# 1 = enabled +# 2 = enabled in workaround mode - Allow STA that claims OCV capability to +# connect even if the STA doesn't send OCI or negotiate PMF. This +# workaround is to improve interoperability with legacy STAs which are +# wrongly copying reserved bits of RSN capabilities from the AP's +# RSNE into (Re)Association Request frames. When this configuration is +# enabled, the AP considers STA is OCV capable only when the STA indicates +# MFP capability in (Re)Association Request frames and sends OCI in +# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association +# Request frame; otherwise, the AP disables OCV for the current connection +# with the STA. Enabling this workaround mode reduced OCV protection to +# some extend since it allows misbehavior to go through. As such, this +# should be enabled only if interoperability with misbehaving STAs is +# needed. +#ocv=1 + +# disable_pmksa_caching: Disable PMKSA caching +# This parameter can be used to disable caching of PMKSA created through EAP +# authentication. RSN preauthentication may still end up using PMKSA caching if +# it is enabled (rsn_preauth=1). +# 0 = PMKSA caching enabled (default) +# 1 = PMKSA caching disabled +#disable_pmksa_caching=0 + +# okc: Opportunistic Key Caching (aka Proactive Key Caching) +# Allow PMK cache to be shared opportunistically among configured interfaces +# and BSSes (i.e., all configurations within a single hostapd process). +# 0 = disabled (default) +# 1 = enabled +#okc=1 + +# SAE password +# This parameter can be used to set passwords for SAE. By default, the +# wpa_passphrase value is used if this separate parameter is not used, but +# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though +# SAE passwords do not have such constraints. If the BSS enabled both SAE and +# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK +# uses the wpa_passphrase value. +# +# Each sae_password entry is added to a list of available passwords. This +# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value +# starts with the password (dot11RSNAConfigPasswordCredential). That value can +# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and +# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In +# addition, an optional VLAN ID specification can be used to bind the station +# to the specified VLAN whenever the specific SAE password entry is used. +# +# If the peer MAC address is not included or is set to the wildcard address +# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a +# specific peer MAC address is included, only a station with that MAC address +# is allowed to use the entry. +# +# If the password identifier (with non-zero length) is included, the entry is +# limited to be used only with that specified identifier. + +# The last matching (based on peer MAC address and identifier) entry is used to +# select which password to use. Setting sae_password to an empty string has a +# special meaning of removing all previously added entries. +# +# sae_password uses the following encoding: +#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>] +#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>] +# Examples: +#sae_password=secret +#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff +#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier +#sae_password=example secret|vlanid=3|id=pw identifier + +# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) +# This parameter defines how many open SAE instances can be in progress at the +# same time before the anti-clogging mechanism is taken into use. +#sae_anti_clogging_threshold=5 (deprecated) +#anti_clogging_threshold=5 + +# Maximum number of SAE synchronization errors (dot11RSNASAESync) +# The offending SAE peer will be disconnected if more than this many +# synchronization errors happen. +#sae_sync=5 + +# Enabled SAE finite cyclic groups +# SAE implementation are required to support group 19 (ECC group defined over a +# 256-bit prime order field). This configuration parameter can be used to +# specify a set of allowed groups. If not included, only the mandatory group 19 +# is enabled. +# The group values are listed in the IANA registry: +# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9 +# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production +# purposes due limited security (see RFC 8247). Groups that are not as strong as +# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases +# since all implementations are required to support group 19. +#sae_groups=19 20 21 + +# Require MFP for all associations using SAE +# This parameter can be used to enforce negotiation of MFP for all associations +# that negotiate use of SAE. This is used in cases where SAE-capable devices are +# known to be MFP-capable and the BSS is configured with optional MFP +# (ieee80211w=1) for legacy support. The non-SAE stations can connect without +# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1. +#sae_require_mfp=0 + +# SAE Confirm behavior +# By default, AP will send out only SAE Commit message in response to a received +# SAE Commit message. This parameter can be set to 1 to override that behavior +# to send both SAE Commit and SAE Confirm messages without waiting for the STA +# to send its SAE Confirm message first. +#sae_confirm_immediate=0 + +# SAE mechanism for PWE derivation +# 0 = hunting-and-pecking loop only (default without password identifier) +# 1 = hash-to-element only (default with password identifier) +# 2 = both hunting-and-pecking loop and hash-to-element enabled +# Note: The default value is likely to change from 0 to 2 once the new +# hash-to-element mechanism has received more interoperability testing. +# When using SAE password identifier, the hash-to-element mechanism is used +# regardless of the sae_pwe parameter value. +#sae_pwe=0 + +# FILS Cache Identifier (16-bit value in hexdump format) +#fils_cache_id=0011 + +# FILS Realm Information +# One or more FILS realms need to be configured when FILS is enabled. This list +# of realms is used to define which realms (used in keyName-NAI by the client) +# can be used with FILS shared key authentication for ERP. +#fils_realm=example.com +#fils_realm=example.org + +# FILS DH Group for PFS +# 0 = PFS disabled with FILS shared key authentication (default) +# 1-65535 DH Group to use for FILS PFS +#fils_dh_group=0 + +# OWE DH groups +# OWE implementations are required to support group 19 (NIST P-256). All groups +# that are supported by the implementation (e.g., groups 19, 20, and 21 when +# using OpenSSL) are enabled by default. This configuration parameter can be +# used to specify a limited set of allowed groups. The group values are listed +# in the IANA registry: +# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 +#owe_groups=19 20 21 + +# OWE PTK derivation workaround +# Initial OWE implementation used SHA256 when deriving the PTK for all OWE +# groups. This was supposed to change to SHA384 for group 20 and SHA512 for +# group 21. This parameter can be used to enable workaround for interoperability +# with stations that use SHA256 with groups 20 and 21. By default (0) only the +# appropriate hash function is accepted. When workaround is enabled (1), the +# appropriate hash function is tried first and if that fails, SHA256-based PTK +# derivation is attempted. This workaround can result in reduced security for +# groups 20 and 21, but is required for interoperability with older +# implementations. There is no impact to group 19 behavior. The workaround is +# disabled by default and can be enabled by uncommenting the following line. +#owe_ptk_workaround=1 + +# OWE transition mode configuration +# Pointer to the matching open/OWE BSS +#owe_transition_bssid=<bssid> +# SSID in same format as ssid2 described above. +#owe_transition_ssid=<SSID> +# Alternatively, OWE transition mode BSSID/SSID can be configured with a +# reference to a BSS operated by this hostapd process. +#owe_transition_ifname=<ifname> + +# DHCP server for FILS HLP +# If configured, hostapd will act as a DHCP relay for all FILS HLP requests +# that include a DHCPDISCOVER message and send them to the specific DHCP +# server for processing. hostapd will then wait for a response from that server +# before replying with (Re)Association Response frame that encapsulates this +# DHCP response. own_ip_addr is used as the local address for the communication +# with the DHCP server. +#dhcp_server=127.0.0.1 + +# DHCP server UDP port +# Default: 67 +#dhcp_server_port=67 + +# DHCP relay UDP port on the local device +# Default: 67; 0 means not to bind any specific port +#dhcp_relay_port=67 + +# DHCP rapid commit proxy +# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to +# allow the rapid commit options (two message DHCP exchange) to be used with a +# server that supports only the four message DHCP exchange. This is disabled by +# default (= 0) and can be enabled by setting this to 1. +#dhcp_rapid_commit_proxy=0 + +# Wait time for FILS HLP (dot11HLPWaitTime) in TUs +# default: 30 TUs (= 30.72 milliseconds) +#fils_hlp_wait_time=30 + +# FILS Discovery frame transmission minimum and maximum interval settings. +# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery +# frame transmission. These values use TUs as the unit and have allowed range +# of 0-10000. fils_discovery_min_interval defaults to 20. +#fils_discovery_min_interval=20 +#fils_discovery_max_interval=0 + +# Transition Disable indication +# The AP can notify authenticated stations to disable transition mode in their +# network profiles when the network has completed transition steps, i.e., once +# sufficiently large number of APs in the ESS have been updated to support the +# more secure alternative. When this indication is used, the stations are +# expected to automatically disable transition mode and less secure security +# options. This includes use of WEP, TKIP (including use of TKIP as the group +# cipher), and connections without PMF. +# Bitmap bits: +# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only +# allow SAE to be used) +# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK) +# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF) +# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE) +# (default: 0 = do not include Transition Disable KDE) +#transition_disable=0x01 + +# PASN ECDH groups +# PASN implementations are required to support group 19 (NIST P-256). If this +# parameter is not set, only group 19 is supported by default. This +# configuration parameter can be used to specify a limited set of allowed +# groups. The group values are listed in the IANA registry: +# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 +#pasn_groups=19 20 21 + +# PASN comeback after time in TUs +# In case the AP is temporarily unable to handle a PASN authentication exchange +# due to a too large number of parallel operations, this value indicates to the +# peer after how many TUs it can try the PASN exchange again. +# (default: 10 TUs) +#pasn_comeback_after=10 + +##### IEEE 802.11r configuration ############################################## + +# Mobility Domain identifier (dot11FTMobilityDomainID, MDID) +# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the +# same SSID) between which a STA can use Fast BSS Transition. +# 2-octet identifier as a hex string. +#mobility_domain=a1b2 + +# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID) +# 1 to 48 octet identifier. +# This is configured with nas_identifier (see RADIUS client section above). + +# Default lifetime of the PMK-R0 in seconds; range 60..4294967295 +# (default: 14 days / 1209600 seconds; 0 = disable timeout) +# (dot11FTR0KeyLifetime) +#ft_r0_key_lifetime=1209600 + +# Maximum lifetime for PMK-R1; applied only if not zero +# PMK-R1 is removed at latest after this limit. +# Removing any PMK-R1 for expiry can be disabled by setting this to -1. +# (default: 0) +#r1_max_key_lifetime=0 + +# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) +# 6-octet identifier as a hex string. +# Defaults to BSSID. +#r1_key_holder=000102030405 + +# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) +# (dot11FTReassociationDeadline) +#reassociation_deadline=1000 + +# List of R0KHs in the same Mobility Domain +# format: <MAC address> <NAS Identifier> <256-bit key as hex string> +# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC +# address when requesting PMK-R1 key from the R0KH that the STA used during the +# Initial Mobility Domain Association. +#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f +#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +# And so on.. One line per R0KH. +# Wildcard entry: +# Upon receiving a response from R0KH, it will be added to this list, so +# subsequent requests won't be broadcast. If R0KH does not reply, it will be +# temporarily blocked (see rkh_neg_timeout). +#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff + +# List of R1KHs in the same Mobility Domain +# format: <MAC address> <R1KH-ID> <256-bit key as hex string> +# This list is used to map R1KH-ID to a destination MAC address when sending +# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD +# that can request PMK-R1 keys. +#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f +#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +# And so on.. One line per R1KH. +# Wildcard entry: +# Upon receiving a request from an R1KH not yet known, it will be added to this +# list and thus will receive push notifications. +#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff + +# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above) +# Special values: 0 -> do not expire +# Warning: do not cache implies no sequence number validation with wildcards +#rkh_pos_timeout=86400 (default = 1 day) + +# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request +# and number of retries. +#rkh_pull_timeout=1000 (default = 1 second) +#rkh_pull_retries=4 (default) + +# Timeout (seconds) for non replying R0KH (see wildcard entries above) +# Special values: 0 -> do not cache +# default: 60 seconds +#rkh_neg_timeout=60 + +# Note: The R0KH/R1KH keys used to be 128-bit in length before the message +# format was changed. That shorter key length is still supported for backwards +# compatibility of the configuration files. If such a shorter key is used, a +# 256-bit key is derived from it. For new deployments, configuring the 256-bit +# key is recommended. + +# Whether PMK-R1 push is enabled at R0KH +# 0 = do not push PMK-R1 to all configured R1KHs (default) +# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived +#pmk_r1_push=1 + +# Whether to enable FT-over-DS +# 0 = FT-over-DS disabled +# 1 = FT-over-DS enabled (default) +#ft_over_ds=1 + +# Whether to generate FT response locally for PSK networks +# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as +# the required information (PSK and other session data) is already locally +# available. +# 0 = disabled (default) +# 1 = enabled +#ft_psk_generate_local=0 + +##### Neighbor table ########################################################## +# Maximum number of entries kept in AP table (either for neighbor table or for +# detecting Overlapping Legacy BSS Condition). The oldest entry will be +# removed when adding a new entry that would make the list grow over this +# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is +# enabled, so this field should not be set to 0 when using IEEE 802.11g. +# default: 255 +#ap_table_max_size=255 + +# Number of seconds of no frames received after which entries may be deleted +# from the AP table. Since passive scanning is not usually performed frequently +# this should not be set to very small value. In addition, there is no +# guarantee that every scan cycle will receive beacon frames from the +# neighboring APs. +# default: 60 +#ap_table_expiration_time=3600 + +# Maximum number of stations to track on the operating channel +# This can be used to detect dualband capable stations before they have +# associated, e.g., to provide guidance on which colocated BSS to use. +# Default: 0 (disabled) +#track_sta_max_num=100 + +# Maximum age of a station tracking entry in seconds +# Default: 180 +#track_sta_max_age=180 + +# Do not reply to group-addressed Probe Request from a station that was seen on +# another radio. +# Default: Disabled +# +# This can be used with enabled track_sta_max_num configuration on another +# interface controlled by the same hostapd process to restrict Probe Request +# frame handling from replying to group-addressed Probe Request frames from a +# station that has been detected to be capable of operating on another band, +# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when +# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently. +# +# Note: Enabling this can cause connectivity issues and increase latency for +# discovering the AP. +#no_probe_resp_if_seen_on=wlan1 + +# Reject authentication from a station that was seen on another radio. +# Default: Disabled +# +# This can be used with enabled track_sta_max_num configuration on another +# interface controlled by the same hostapd process to reject authentication +# attempts from a station that has been detected to be capable of operating on +# another band, e.g., to try to reduce likelihood of the station selecting a +# 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz BSS concurrently. +# +# Note: Enabling this can cause connectivity issues and increase latency for +# connecting with the AP. +#no_auth_if_seen_on=wlan1 + +##### Wi-Fi Protected Setup (WPS) ############################################# + +# WPS state +# 0 = WPS disabled (default) +# 1 = WPS enabled, not configured +# 2 = WPS enabled, configured +#wps_state=2 + +# Whether to manage this interface independently from other WPS interfaces +# By default, a single hostapd process applies WPS operations to all configured +# interfaces. This parameter can be used to disable that behavior for a subset +# of interfaces. If this is set to non-zero for an interface, WPS commands +# issued on that interface do not apply to other interfaces and WPS operations +# performed on other interfaces do not affect this interface. +#wps_independent=0 + +# AP can be configured into a locked state where new WPS Registrar are not +# accepted, but previously authorized Registrars (including the internal one) +# can continue to add new Enrollees. +#ap_setup_locked=1 + +# Universally Unique IDentifier (UUID; see RFC 4122) of the device +# This value is used as the UUID for the internal WPS Registrar. If the AP +# is also using UPnP, this value should be set to the device's UPnP UUID. +# If not configured, UUID will be generated based on the local MAC address. +#uuid=12345678-9abc-def0-1234-56789abcdef0 + +# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs +# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the +# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of +# per-device PSKs is recommended as the more secure option (i.e., make sure to +# set wpa_psk_file when using WPS with WPA-PSK). + +# When an Enrollee requests access to the network with PIN method, the Enrollee +# PIN will need to be entered for the Registrar. PIN request notifications are +# sent to hostapd ctrl_iface monitor. In addition, they can be written to a +# text file that could be used, e.g., to populate the AP administration UI with +# pending PIN requests. If the following variable is set, the PIN requests will +# be written to the configured file. +#wps_pin_requests=/var/run/hostapd_wps_pin_requests + +# Device Name +# User-friendly description of device; up to 32 octets encoded in UTF-8 +#device_name=Wireless AP + +# Manufacturer +# The manufacturer of the device (up to 64 ASCII characters) +#manufacturer=Company + +# Model Name +# Model of the device (up to 32 ASCII characters) +#model_name=WAP + +# Model Number +# Additional device description (up to 32 ASCII characters) +#model_number=123 + +# Serial Number +# Serial number of the device (up to 32 characters) +#serial_number=12345 + +# Primary Device Type +# Used format: <categ>-<OUI>-<subcateg> +# categ = Category as an integer value +# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for +# default WPS OUI +# subcateg = OUI-specific Sub Category as an integer value +# Examples: +# 1-0050F204-1 (Computer / PC) +# 1-0050F204-2 (Computer / Server) +# 5-0050F204-1 (Storage / NAS) +# 6-0050F204-1 (Network Infrastructure / AP) +#device_type=6-0050F204-1 + +# OS Version +# 4-octet operating system version number (hex string) +#os_version=01020300 + +# Config Methods +# List of the supported configuration methods +# Available methods: usba ethernet label display ext_nfc_token int_nfc_token +# nfc_interface push_button keypad virtual_display physical_display +# virtual_push_button physical_push_button +#config_methods=label virtual_display virtual_push_button keypad + +# WPS capability discovery workaround for PBC with Windows 7 +# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting +# as a Registrar and using M1 from the AP. The config methods attribute in that +# message is supposed to indicate only the configuration method supported by +# the AP in Enrollee role, i.e., to add an external Registrar. For that case, +# PBC shall not be used and as such, the PushButton config method is removed +# from M1 by default. If pbc_in_m1=1 is included in the configuration file, +# the PushButton config method is left in M1 (if included in config_methods +# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label +# in the AP). +#pbc_in_m1=1 + +# Static access point PIN for initial configuration and adding Registrars +# If not set, hostapd will not allow external WPS Registrars to control the +# access point. The AP PIN can also be set at runtime with hostapd_cli +# wps_ap_pin command. Use of temporary (enabled by user action) and random +# AP PIN is much more secure than configuring a static AP PIN here. As such, +# use of the ap_pin parameter is not recommended if the AP device has means for +# displaying a random PIN. +#ap_pin=12345670 + +# Skip building of automatic WPS credential +# This can be used to allow the automatically generated Credential attribute to +# be replaced with pre-configured Credential(s). +#skip_cred_build=1 + +# Additional Credential attribute(s) +# This option can be used to add pre-configured Credential attributes into M8 +# message when acting as a Registrar. If skip_cred_build=1, this data will also +# be able to override the Credential attribute that would have otherwise been +# automatically generated based on network configuration. This configuration +# option points to an external file that much contain the WPS Credential +# attribute(s) as binary data. +#extra_cred=hostapd.cred + +# Credential processing +# 0 = process received credentials internally (default) +# 1 = do not process received credentials; just pass them over ctrl_iface to +# external program(s) +# 2 = process received credentials internally and pass them over ctrl_iface +# to external program(s) +# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and +# extra_cred be used to provide the Credential data for Enrollees. +# +# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file +# both for Credential processing and for marking AP Setup Locked based on +# validation failures of AP PIN. An external program is responsible on updating +# the configuration appropriately in this case. +#wps_cred_processing=0 + +# Whether to enable SAE (WPA3-Personal transition mode) automatically for +# WPA2-PSK credentials received using WPS. +# 0 = only add the explicitly listed WPA2-PSK configuration (default) +# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the +# AP gets configured in WPA3-Personal transition mode (supports both +# WPA2-Personal (PSK) and WPA3-Personal (SAE) clients). +#wps_cred_add_sae=0 + +# AP Settings Attributes for M7 +# By default, hostapd generates the AP Settings Attributes for M7 based on the +# current configuration. It is possible to override this by providing a file +# with pre-configured attributes. This is similar to extra_cred file format, +# but the AP Settings attributes are not encapsulated in a Credential +# attribute. +#ap_settings=hostapd.ap_settings + +# Multi-AP backhaul BSS config +# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials. +# These are passed in WPS M8 instead of the normal (fronthaul) credentials +# if the Enrollee has the Multi-AP subelement set. Backhaul SSID is formatted +# like ssid2. The key is set like wpa_psk or wpa_passphrase. +#multi_ap_backhaul_ssid="backhaul" +#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +#multi_ap_backhaul_wpa_passphrase=secret passphrase + +# WPS UPnP interface +# If set, support for external Registrars is enabled. +#upnp_iface=br0 + +# Friendly Name (required for UPnP) +# Short description for end use. Should be less than 64 characters. +#friendly_name=WPS Access Point + +# Manufacturer URL (optional for UPnP) +#manufacturer_url=http://www.example.com/ + +# Model Description (recommended for UPnP) +# Long description for end user. Should be less than 128 characters. +#model_description=Wireless Access Point + +# Model URL (optional for UPnP) +#model_url=http://www.example.com/model/ + +# Universal Product Code (optional for UPnP) +# 12-digit, all-numeric code that identifies the consumer package. +#upc=123456789012 + +# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band, ad = 60 GHz) +# This value should be set according to RF band(s) supported by the AP if +# hw_mode is not set. For dual band dual concurrent devices, this needs to be +# set to ag to allow both RF bands to be advertized. +#wps_rf_bands=ag + +# NFC password token for WPS +# These parameters can be used to configure a fixed NFC password token for the +# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When +# these parameters are used, the AP is assumed to be deployed with a NFC tag +# that includes the matching NFC password token (e.g., written based on the +# NDEF record from nfc_pw_token). +# +#wps_nfc_dev_pw_id: Device Password ID (16..65535) +#wps_nfc_dh_pubkey: Hexdump of DH Public Key +#wps_nfc_dh_privkey: Hexdump of DH Private Key +#wps_nfc_dev_pw: Hexdump of Device Password + +# Application Extension attribute for Beacon and Probe Response frames +# This parameter can be used to add application extension into WPS IE. The +# contents of this parameter starts with 16-octet (32 hexdump characters) of +# UUID to identify the specific application and that is followed by the actual +# application specific data. +#wps_application_ext=<hexdump> + +##### Wi-Fi Direct (P2P) ###################################################### + +# Enable P2P Device management +#manage_p2p=1 + +# Allow cross connection +#allow_cross_connection=1 + +##### Device Provisioning Protocol (DPP) ###################################### + +# Name for Enrollee's DPP Configuration Request +#dpp_name=Test + +# MUD URL for Enrollee's DPP Configuration Request (optional) +#dpp_mud_url=https://example.com/mud + +#dpp_connector +#dpp_netaccesskey +#dpp_netaccesskey_expiry +#dpp_csign +#dpp_controller + +# Configurator Connectivity indication +# 0: no Configurator is currently connected (default) +# 1: advertise that a Configurator is available +#dpp_configurator_connectivity=0 + +# DPP PFS +# 0: allow PFS to be used or not used (default) +# 1: require PFS to be used (note: not compatible with DPP R1) +# 2: do not allow PFS to be used +#dpp_pfs=0 + +#### TDLS (IEEE 802.11z-2010) ################################################# + +# Prohibit use of TDLS in this BSS +#tdls_prohibit=1 + +# Prohibit use of TDLS Channel Switching in this BSS +#tdls_prohibit_chan_switch=1 + +##### IEEE 802.11v-2011 ####################################################### + +# Time advertisement +# 0 = disabled (default) +# 2 = UTC time at which the TSF timer is 0 +#time_advertisement=2 + +# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004: +# stdoffset[dst[offset][,start[/time],end[/time]]] +#time_zone=EST5 + +# WNM-Sleep Mode (extended sleep mode for stations) +# 0 = disabled (default) +# 1 = enabled (allow stations to use WNM-Sleep Mode) +#wnm_sleep_mode=1 + +# WNM-Sleep Mode GTK/IGTK workaround +# Normally, WNM-Sleep Mode exit with management frame protection negotiated +# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode +# Response frame. Some station implementations may have a vulnerability that +# results in GTK/IGTK reinstallation based on this frame being replayed. This +# configuration parameter can be used to disable that behavior and use EAPOL-Key +# frames for GTK/IGTK update instead. This would likely be only used with +# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues +# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087 +# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1. +#wnm_sleep_mode_no_keys=0 + +# BSS Transition Management +# 0 = disabled (default) +# 1 = enabled +#bss_transition=1 + +# Proxy ARP +# 0 = disabled (default) +# 1 = enabled +#proxy_arp=1 + +# IPv6 Neighbor Advertisement multicast-to-unicast conversion +# This can be used with Proxy ARP to allow multicast NAs to be forwarded to +# associated STAs using link layer unicast delivery. +# 0 = disabled (default) +# 1 = enabled +#na_mcast_to_ucast=0 + +##### IEEE 802.11u-2011 ####################################################### + +# Enable Interworking service +#interworking=1 + +# Access Network Type +# 0 = Private network +# 1 = Private network with guest access +# 2 = Chargeable public network +# 3 = Free public network +# 4 = Personal device network +# 5 = Emergency services only network +# 14 = Test or experimental +# 15 = Wildcard +#access_network_type=0 + +# Whether the network provides connectivity to the Internet +# 0 = Unspecified +# 1 = Network provides connectivity to the Internet +#internet=1 + +# Additional Step Required for Access +# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if +# RSN is used. +#asra=0 + +# Emergency services reachable +#esr=0 + +# Unauthenticated emergency service accessible +#uesa=0 + +# Venue Info (optional) +# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34. +# Example values (group,type): +# 0,0 = Unspecified +# 1,7 = Convention Center +# 1,13 = Coffee Shop +# 2,0 = Unspecified Business +# 7,1 Private Residence +#venue_group=7 +#venue_type=1 + +# Homogeneous ESS identifier (optional; dot11HESSID) +# If set, this shall be identifical to one of the BSSIDs in the homogeneous +# ESS and this shall be set to the same value across all BSSs in homogeneous +# ESS. +#hessid=02:03:04:05:06:07 + +# Roaming Consortium List +# Arbitrary number of Roaming Consortium OIs can be configured with each line +# adding a new OI to the list. The first three entries are available through +# Beacon and Probe Response frames. Any additional entry will be available only +# through ANQP queries. Each OI is between 3 and 15 octets and is configured as +# a hexstring. +#roaming_consortium=021122 +#roaming_consortium=2233445566 + +# Venue Name information +# This parameter can be used to configure one or more Venue Name Duples for +# Venue Name ANQP information. Each entry has a two or three character language +# code (ISO-639) separated by colon from the venue name string. +# Note that venue_group and venue_type have to be set for Venue Name +# information to be complete. +#venue_name=eng:Example venue +#venue_name=fin:Esimerkkipaikka +# Alternative format for language:value strings: +# (double quoted string, printf-escaped string) +#venue_name=P"eng:Example\nvenue" + +# Venue URL information +# This parameter can be used to configure one or more Venue URL Duples to +# provide additional information corresponding to Venue Name information. +# Each entry has a Venue Number value separated by colon from the Venue URL +# string. Venue Number indicates the corresponding venue_name entry (1 = 1st +# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name) +#venue_url=1:http://www.example.com/info-eng +#venue_url=2:http://www.example.com/info-fin + +# Network Authentication Type +# This parameter indicates what type of network authentication is used in the +# network. +# format: <network auth type indicator (1-octet hex str)> [redirect URL] +# Network Authentication Type Indicator values: +# 00 = Acceptance of terms and conditions +# 01 = On-line enrollment supported +# 02 = http/https redirection +# 03 = DNS redirection +#network_auth_type=00 +#network_auth_type=02http://www.example.com/redirect/me/here/ + +# IP Address Type Availability +# format: <1-octet encoded value as hex str> +# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3) +# ipv4_type: +# 0 = Address type not available +# 1 = Public IPv4 address available +# 2 = Port-restricted IPv4 address available +# 3 = Single NATed private IPv4 address available +# 4 = Double NATed private IPv4 address available +# 5 = Port-restricted IPv4 address and single NATed IPv4 address available +# 6 = Port-restricted IPv4 address and double NATed IPv4 address available +# 7 = Availability of the address type is not known +# ipv6_type: +# 0 = Address type not available +# 1 = Address type available +# 2 = Availability of the address type not known +#ipaddr_type_availability=14 + +# Domain Name +# format: <variable-octet str>[,<variable-octet str>] +#domain_name=example.com,another.example.com,yet-another.example.com + +# 3GPP Cellular Network information +# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] +#anqp_3gpp_cell_net=244,91;310,026;234,56 + +# NAI Realm information +# One or more realm can be advertised. Each nai_realm line adds a new realm to +# the set. These parameters provide information for stations using Interworking +# network selection to allow automatic connection to a network based on +# credentials. +# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...] +# encoding: +# 0 = Realm formatted in accordance with IETF RFC 4282 +# 1 = UTF-8 formatted character string that is not formatted in +# accordance with IETF RFC 4282 +# NAI Realm(s): Semi-colon delimited NAI Realm(s) +# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...] +# EAP Method types, see: +# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4 +# AuthParam (Table 8-188 in IEEE Std 802.11-2012): +# ID 2 = Non-EAP Inner Authentication Type +# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2 +# ID 3 = Inner authentication EAP Method Type +# ID 5 = Credential Type +# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token, +# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous, +# 10 = Vendor Specific +#nai_realm=0,example.com;example.net +# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with +# username/password +#nai_realm=0,example.org,13[5:6],21[2:4][5:7] + +# Arbitrary ANQP-element configuration +# Additional ANQP-elements with arbitrary values can be defined by specifying +# their contents in raw format as a hexdump of the payload. Note that these +# values will override ANQP-element contents that may have been specified in the +# more higher layer configuration parameters listed above. +# format: anqp_elem=<InfoID>:<hexdump of payload> +# For example, AP Geospatial Location ANQP-element with unknown location: +#anqp_elem=265:0000 +# For example, AP Civic Location ANQP-element with unknown location: +#anqp_elem=266:000000 + +# GAS Address 3 behavior +# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default +# based on GAS request Address3 +# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3 +# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases) +#gas_address3=0 + +# QoS Map Set configuration +# +# Comma delimited QoS Map Set in decimal values +# (see IEEE Std 802.11-2012, 8.4.2.97) +# +# format: +# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]> +# +# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value +# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range +# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for +# each UP starting from 0. If both low and high value are set to 255, the +# corresponding UP is not used. +# +# default: not set +#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255 + +##### Hotspot 2.0 ############################################################# + +# Enable Hotspot 2.0 support +#hs20=1 + +# Disable Downstream Group-Addressed Forwarding (DGAF) +# This can be used to configure a network where no group-addressed frames are +# allowed. The AP will not forward any group-address frames to the stations and +# random GTKs are issued for each station to prevent associated stations from +# forging such frames to other stations in the BSS. +#disable_dgaf=1 + +# OSU Server-Only Authenticated L2 Encryption Network +#osen=1 + +# ANQP Domain ID (0..65535) +# An identifier for a set of APs in an ESS that share the same common ANQP +# information. 0 = Some of the ANQP information is unique to this AP (default). +#anqp_domain_id=1234 + +# Deauthentication request timeout +# If the RADIUS server indicates that the station is not allowed to connect to +# the BSS/ESS, the AP can allow the station some time to download a +# notification page (URL included in the message). This parameter sets that +# timeout in seconds. +#hs20_deauth_req_timeout=60 + +# Operator Friendly Name +# This parameter can be used to configure one or more Operator Friendly Name +# Duples. Each entry has a two or three character language code (ISO-639) +# separated by colon from the operator friendly name string. +#hs20_oper_friendly_name=eng:Example operator +#hs20_oper_friendly_name=fin:Esimerkkioperaattori + +# Connection Capability +# This can be used to advertise what type of IP traffic can be sent through the +# hotspot (e.g., due to firewall allowing/blocking protocols/ports). +# format: <IP Protocol>:<Port Number>:<Status> +# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP +# Port Number: 0..65535 +# Status: 0 = Closed, 1 = Open, 2 = Unknown +# Each hs20_conn_capab line is added to the list of advertised tuples. +#hs20_conn_capab=1:0:2 +#hs20_conn_capab=6:22:1 +#hs20_conn_capab=17:5060:0 + +# WAN Metrics +# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> +# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity +# (encoded as two hex digits) +# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state +# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps; +# 1..4294967295; 0 = unknown +# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps +# 1..4294967295; 0 = unknown +# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%) +# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%) +# Load Measurement Duration: Duration for measuring downlink/uplink load in +# tenths of a second (1..65535); 0 if load cannot be determined +#hs20_wan_metrics=01:8000:1000:80:240:3000 + +# Operating Class Indication +# List of operating classes the BSSes in this ESS use. The Global operating +# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that +# can be used in this. +# format: hexdump of operating class octets +# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz +# channels 36-48): +#hs20_operating_class=5173 + +# Terms and Conditions information +# +# hs20_t_c_filename contains the Terms and Conditions filename that the AP +# indicates in RADIUS Access-Request messages. +#hs20_t_c_filename=terms-and-conditions +# +# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP +# indicates in RADIUS Access-Request messages. Usually, this contains the number +# of seconds since January 1, 1970 00:00 UTC showing the time when the file was +# last modified. +#hs20_t_c_timestamp=1234567 +# +# hs20_t_c_server_url contains a template for the Terms and Conditions server +# URL. This template is used to generate the URL for a STA that needs to +# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this +# parameter is used on the authentication server, not the AP. +# Macros: +# @1@ = MAC address of the STA (colon separated hex octets) +#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123 + +# OSU and Operator icons +# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path> +#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png +#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png + +# OSU SSID (see ssid2 for format description) +# This is the SSID used for all OSU connections to all the listed OSU Providers. +#osu_ssid="example" + +# OSU Providers +# One or more sets of following parameter. Each OSU provider is started by the +# mandatory osu_server_uri item. The other parameters add information for the +# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN +# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI +# value for OSEN authentication when using a shared BSS (Single SSID) for OSU. +# +#osu_server_uri=https://example.com/osu/ +#osu_friendly_name=eng:Example operator +#osu_friendly_name=fin:Esimerkkipalveluntarjoaja +#osu_nai=anonymous@example.com +#osu_nai2=anonymous@example.com +#osu_method_list=1 0 +#osu_icon=icon32 +#osu_icon=icon64 +#osu_service_desc=eng:Example services +#osu_service_desc=fin:Esimerkkipalveluja +# +#osu_server_uri=... + +# Operator Icons +# Operator icons are specified using references to the hs20_icon entries +# (Name subfield). This information, if present, is advertsised in the +# Operator Icon Metadata ANQO-element. +#operator_icon=icon32 +#operator_icon=icon64 + +##### Multiband Operation (MBO) ############################################### +# +# MBO enabled +# 0 = disabled (default) +# 1 = enabled +#mbo=1 +# +# Cellular data connection preference +# 0 = Excluded - AP does not want STA to use the cellular data connection +# 1 = AP prefers the STA not to use cellular data connection +# 255 = AP prefers the STA to use cellular data connection +#mbo_cell_data_conn_pref=1 + +##### Optimized Connectivity Experience (OCE) ################################# +# +# Enable OCE specific features (bitmap) +# BIT(0) - Reserved +# Set BIT(1) (= 2) to enable OCE in STA-CFON mode +# Set BIT(2) (= 4) to enable OCE in AP mode +# Default is 0 = OCE disabled +#oce=0 + +# RSSI-based association rejection +# +# Reject STA association if RSSI is below given threshold (in dBm) +# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled) +# Note: This rejection happens based on a signal strength detected while +# receiving a single frame and as such, there is significant risk of the value +# not being accurate and this resulting in valid stations being rejected. As +# such, this functionality is not recommended to be used for purposes other than +# testing. +#rssi_reject_assoc_rssi=-75 +# +# Association retry delay in seconds allowed by the STA if RSSI has not met the +# threshold (range: 0..255, default=30). +#rssi_reject_assoc_timeout=30 + +# Ignore Probe Request frames if RSSI is below given threshold (in dBm) +# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled) +#rssi_ignore_probe_request=-75 + +##### Fast Session Transfer (FST) support ##################################### +# +# The options in this section are only available when the build configuration +# option CONFIG_FST is set while compiling hostapd. They allow this interface +# to be a part of FST setup. +# +# FST is the transfer of a session from a channel to another channel, in the +# same or different frequency bands. +# +# For detals, see IEEE Std 802.11ad-2012. + +# Identifier of an FST Group the interface belongs to. +#fst_group_id=bond0 + +# Interface priority within the FST Group. +# Announcing a higher priority for an interface means declaring it more +# preferable for FST switch. +# fst_priority is in 1..255 range with 1 being the lowest priority. +#fst_priority=100 + +# Default LLT value for this interface in milliseconds. The value used in case +# no value provided during session setup. Default is 50 ms. +# fst_llt is in 1..4294967 range (due to spec limitation, see 10.32.2.2 +# Transitioning between states). +#fst_llt=100 + +##### Radio measurements / location ########################################### + +# The content of a LCI measurement subelement +#lci=<Hexdump of binary data of the LCI report> + +# The content of a location civic measurement subelement +#civic=<Hexdump of binary data of the location civic report> + +# Enable neighbor report via radio measurements +#rrm_neighbor_report=1 + +# Enable beacon report via radio measurements +#rrm_beacon_report=1 + +# Publish fine timing measurement (FTM) responder functionality +# This parameter only controls publishing via Extended Capabilities element. +# Actual functionality is managed outside hostapd. +#ftm_responder=0 + +# Publish fine timing measurement (FTM) initiator functionality +# This parameter only controls publishing via Extended Capabilities element. +# Actual functionality is managed outside hostapd. +#ftm_initiator=0 +# +# Stationary AP config indicates that the AP doesn't move hence location data +# can be considered as always up to date. If configured, LCI data will be sent +# as a radio measurement even if the request doesn't contain a max age element +# that allows sending of such data. Default: 0. +#stationary_ap=0 + +# Enable reduced neighbor reporting (RNR) +#rnr=0 + +##### Airtime policy configuration ########################################### + +# Set the airtime policy operating mode: +# 0 = disabled (default) +# 1 = static config +# 2 = per-BSS dynamic config +# 3 = per-BSS limit mode +#airtime_mode=0 + +# Interval (in milliseconds) to poll the kernel for updated station activity in +# dynamic and limit modes +#airtime_update_interval=200 + +# Static configuration of station weights (when airtime_mode=1). Kernel default +# weight is 256; set higher for larger airtime share, lower for smaller share. +# Each entry is a MAC address followed by a weight. +#airtime_sta_weight=02:01:02:03:04:05 256 +#airtime_sta_weight=02:01:02:03:04:06 512 + +# Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will +# configure station weights to enforce the correct ratio between BSS weights +# depending on the number of active stations. The *ratios* between different +# BSSes is what's important, not the absolute numbers. +# Must be set for all BSSes if airtime_mode=2 or 3, has no effect otherwise. +#airtime_bss_weight=1 + +# Whether the current BSS should be limited (when airtime_mode=3). +# +# If set, the BSS weight ratio will be applied in the case where the current BSS +# would exceed the share defined by the BSS weight ratio. E.g., if two BSSes are +# set to the same weights, and one is set to limited, the limited BSS will get +# no more than half the available airtime, but if the non-limited BSS has more +# stations active, that *will* be allowed to exceed its half of the available +# airtime. +#airtime_bss_limit=1 + +##### EDMG support ############################################################ +# +# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false. +# To configure channel bonding for an EDMG AP use edmg_channel below. +# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be +# configured. +#enable_edmg=1 +# +# Configure channel bonding for AP mode in the 60 GHz band. +# This parameter is relevant only if enable_edmg is set. +# Default value is 0 (no channel bonding). +#edmg_channel=9 + +##### TESTING OPTIONS ######################################################### +# +# The options in this section are only available when the build configuration +# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow +# testing some scenarios that are otherwise difficult to reproduce. +# +# Ignore probe requests sent to hostapd with the given probability, must be a +# floating point number in the range [0, 1). +#ignore_probe_probability=0.0 +# +# Ignore authentication frames with the given probability +#ignore_auth_probability=0.0 +# +# Ignore association requests with the given probability +#ignore_assoc_probability=0.0 +# +# Ignore reassociation requests with the given probability +#ignore_reassoc_probability=0.0 +# +# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability +#corrupt_gtk_rekey_mic_probability=0.0 +# +# Include only ECSA IE without CSA IE where possible +# (channel switch operating class is needed) +#ecsa_ie_only=0 + +##### Multiple BSSID support ################################################## +# +# Above configuration is using the default interface (wlan#, or multi-SSID VLAN +# interfaces). Other BSSIDs can be added by using separator 'bss' with +# default interface name to be allocated for the data packets of the new BSS. +# +# hostapd will generate BSSID mask based on the BSSIDs that are +# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is +# not the case, the MAC address of the radio must be changed before starting +# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for +# every secondary BSS, this limitation is not applied at hostapd and other +# masks may be used if the driver supports them (e.g., swap the locally +# administered bit) +# +# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is +# specified using the 'bssid' parameter. +# If an explicit BSSID is specified, it must be chosen such that it: +# - results in a valid MASK that covers it and the dev_addr +# - is not the same as the MAC address of the radio +# - is not the same as any other explicitly specified BSSID +# +# Alternatively, the 'use_driver_iface_addr' parameter can be used to request +# hostapd to use the driver auto-generated interface address (e.g., to use the +# exact MAC addresses allocated to the device). +# +# Not all drivers support multiple BSSes. The exact mechanism for determining +# the driver capabilities is driver specific. With the current (i.e., a recent +# kernel) drivers using nl80211, this information can be checked with "iw list" +# (search for "valid interface combinations"). +# +# Please note that hostapd uses some of the values configured for the first BSS +# as the defaults for the following BSSes. However, it is recommended that all +# BSSes include explicit configuration of all relevant configuration items. +# +#bss=wlan0_0 +#ssid=test2 +# most of the above items can be used here (apart from radio interface specific +# items, like channel) + +#bss=wlan0_1 +#bssid=00:13:10:95:fe:0b +# ... +#} diff --git a/debian/control b/debian/control index 2e99bdc28..883e08649 100644 --- a/debian/control +++ b/debian/control @@ -19,12 +19,18 @@ Build-Depends: python3-xmltodict, # For running tests python3-coverage, + python3-hurry.filesize, + python3-netaddr, python3-netifaces, python3-nose, python3-jinja2, + python3-paramiko, + python3-passlib, python3-psutil, python3-requests, python3-setuptools, + python3-tabulate, + python3-zmq, quilt, whois Standards-Version: 3.9.6 diff --git a/interface-definitions/interfaces_wireless.xml.in b/interface-definitions/interfaces_wireless.xml.in index b3fc2302d..0a62b3255 100644 --- a/interface-definitions/interfaces_wireless.xml.in +++ b/interface-definitions/interfaces_wireless.xml.in @@ -27,7 +27,7 @@ <children> <node name="ht"> <properties> - <help>HT (High Throughput) settings</help> + <help>High Throughput (HT) settings</help> </properties> <children> <leafNode name="40mhz-incapable"> @@ -38,7 +38,7 @@ </leafNode> <leafNode name="auto-powersave"> <properties> - <help>Enable WMM-PS unscheduled automatic power aave delivery [U-APSD]</help> + <help>Enable WMM-PS unscheduled automatic power save delivery [U-APSD]</help> <valueless/> </properties> </leafNode> @@ -184,25 +184,13 @@ </node> <leafNode name="require-ht"> <properties> - <help>Require stations to support HT PHY (reject association if they do not)</help> - <completionHelp> - <script>echo If you reject non-HT, you also disable 802.11g</script> - </completionHelp> - <valueless/> - </properties> - </leafNode> - <leafNode name="require-vht"> - <properties> - <help>Require stations to support VHT PHY (reject association if they do not)</help> - <completionHelp> - <script>echo If you reject non-VHT, you also disable 802.11n</script> - </completionHelp> + <help>Require stations to support HT PHY</help> <valueless/> </properties> </leafNode> <node name="vht"> <properties> - <help>VHT (Very High Throughput) settings</help> + <help>Very High Throughput (VHT) settings</help> </properties> <children> <leafNode name="antenna-count"> @@ -225,7 +213,7 @@ </leafNode> <leafNode name="beamform"> <properties> - <help>Beamforming capabilities</help> + <help>VHT beamforming capabilities</help> <completionHelp> <list>single-user-beamformer single-user-beamformee multi-user-beamformer multi-user-beamformee</list> </completionHelp> @@ -274,7 +262,7 @@ <help>VHT operating channel center frequency - center freq 2 (for use with the 80+80 mode)</help> <valueHelp> <format>u32:34-173</format> - <description>5Ghz (802.11 a/h/j/n/ac) center channel index (use 58 for primary 80MHz channel 52)</description> + <description>5Ghz (802.11 ac) center channel index (use 58 for secondary 80MHz channel 52)</description> </valueHelp> <constraint> <validator name="numeric" argument="--range 34-173"/> @@ -428,6 +416,133 @@ </leafNode> </children> </node> + <leafNode name="require-vht"> + <properties> + <help>Require stations to support VHT PHY</help> + <valueless/> + </properties> + </leafNode> + <node name="he"> + <properties> + <help>High Efficiency (HE) settings</help> + </properties> + <children> + <leafNode name="channel-set-width"> + <properties> + <help>HE operating channel width</help> + <completionHelp> + <!-- + op_modes drawn from: + https://w1.fi/cgit/hostap/tree/src/common/ieee802_11_common.c?id=195cc3d919503fb0d699d9a56a58a72602b25f51#n1525 + 802.11ax (WiFi-6e - HE) can use up to 160MHz bandwidth channels + --> + <list>131 132 133 134 135</list> + </completionHelp> + <valueHelp> + <format>131</format> + <description>20 MHz channel width</description> + </valueHelp> + <valueHelp> + <format>132</format> + <description>40 MHz channel width</description> + </valueHelp> + <valueHelp> + <format>133</format> + <description>80 MHz channel width</description> + </valueHelp> + <valueHelp> + <format>134</format> + <description>160 MHz channel width</description> + </valueHelp> + <valueHelp> + <format>135</format> + <description>80+80 MHz channel width</description> + </valueHelp> + <constraint> + <regex>(131|132|133|134|135)</regex> + </constraint> + </properties> + </leafNode> + <node name="center-channel-freq"> + <properties> + <help>HE operating channel center frequency</help> + </properties> + <children> + <leafNode name="freq-1"> + <properties> + <help>HE operating channel center frequency - center freq 1 (for use with 80, 80+80 and 160 modes)</help> + <valueHelp> + <format>u32:1-233</format> + <description>6Ghz (802.11 ax) center channel index (use 3 (at 40MHz), 7 (at 80MHz) or 15 (at 160MHz) for primary channel 1)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-233"/> + </constraint> + <constraintErrorMessage>Channel center value must be between 1 and 233</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="freq-2"> + <properties> + <help>HE operating channel center frequency - center freq 2 (for use with the 80+80 mode)</help> + <valueHelp> + <format>u32:1-233</format> + <description>6Ghz (802.11 ax) center channel index (use 23 (at 80MHz) for secondary channel 17)</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-233"/> + </constraint> + <constraintErrorMessage>Channel center value must be between 1 and 233</constraintErrorMessage> + </properties> + </leafNode> + </children> + </node> + <leafNode name="antenna-pattern-fixed"> + <properties> + <help>Tell the AP that antenna positions are fixed and will not change during the lifetime of an association</help> + <valueless/> + </properties> + </leafNode> + <node name="beamform"> + <properties> + <help>HE beamforming capabilities</help> + </properties> + <children> + <leafNode name="single-user-beamformer"> + <properties> + <help>Support for operation as single user beamformer</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="single-user-beamformee"> + <properties> + <help>Support for operation as single user beamformee</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="multi-user-beamformer"> + <properties> + <help>Support for operation as multi user beamformer</help> + <valueless/> + </properties> + </leafNode> + </children> + </node> + <leafNode name="bss-color"> + <properties> + <help>BSS coloring helps to prevent channel jamming when multiple APs use the same channels</help> + <constraint> + <validator name="numeric" argument="--range 1-63"/> + </constraint> + </properties> + </leafNode> + </children> + </node> + <leafNode name="require-he"> + <properties> + <help>Require stations to support HE PHY</help> + <valueless/> + </properties> + </leafNode> </children> </node> <leafNode name="channel"> @@ -445,8 +560,12 @@ <format>u32:34-173</format> <description>5Ghz (802.11 a/h/j/n/ac) Channel</description> </valueHelp> + <valueHelp> + <format>u32:1-233</format> + <description>6Ghz (802.11 ax) Channel</description> + </valueHelp> <constraint> - <validator name="numeric" argument="--range 0-0 --range 1-14 --range 34-173"/> + <validator name="numeric" argument="--range 0-0 --range 1-14 --range 34-173 --range 1-233"/> </constraint> </properties> <defaultValue>0</defaultValue> @@ -492,6 +611,12 @@ <constraintErrorMessage>Number of stations must be between 1 and 2007</constraintErrorMessage> </properties> </leafNode> + <leafNode name="stationary-ap"> + <properties> + <help>Stationary AP config indicates that the AP doesn't move.</help> + <valueless/> + </properties> + </leafNode> <leafNode name="mgmt-frame-protection"> <properties> <help>Management Frame Protection (MFP) according to IEEE 802.11w</help> @@ -508,7 +633,7 @@ </valueHelp> <valueHelp> <format>required</format> - <description>MFP enforced</description> + <description>MFP enforced (mandatory for WPA3)</description> </valueHelp> <constraint> <regex>(disabled|optional|required)</regex> @@ -516,11 +641,18 @@ </properties> <defaultValue>disabled</defaultValue> </leafNode> + <leafNode name="enable-bf-protection"> + <properties> + <help>Beacon Protection: management frame protection for Beacon frames, requires Management Frame Protection (MFP)</help> + <valueless/> + </properties> + <defaultValue>disabled</defaultValue> + </leafNode> <leafNode name="mode"> <properties> <help>Wireless radio mode</help> <completionHelp> - <list>a b g n ac</list> + <list>a b g n ac ax</list> </completionHelp> <valueHelp> <format>a</format> @@ -542,12 +674,24 @@ <format>ac</format> <description>802.11ac - 1300 Mbits/sec</description> </valueHelp> + <valueHelp> + <format>ax</format> + <description>802.11ax (6GHz only for now)</description> + </valueHelp> <constraint> - <regex>(a|b|g|n|ac)</regex> + <regex>(a|b|g|n|ac|ax)</regex> </constraint> </properties> <defaultValue>g</defaultValue> </leafNode> + <!-- background_radar_detection not yet supported by VyOS's hostapd + <leafNode name="background-radar-detection"> + <properties> + <help>Enabling background radar detection feature allows CAC to be run on dedicated radio RF chains while the radio(s) are otherwise running normal AP activities on other channels.</help> + <valueless/> + </properties> + </leafNode> + --> #include <include/interface/mirror.xml.i> <leafNode name="physical-device"> <properties> @@ -711,9 +855,21 @@ <regex>(GCMP-256|GCMP|CCMP-256|CCMP|TKIP)</regex> </constraint> <constraintErrorMessage>Invalid group cipher selection</constraintErrorMessage> - <multi/> </properties> </leafNode> + <leafNode name="group-mgmt-cipher"> + <properties> + <help>Group management cipher suite. All the stations connecting to the BSS will also need to support the selected cipher</help> + <completionHelp> + <list>AES-128-CMAC BIP-CMAC-256 BIP-GMAC-128 BIP-GMAC-256</list> + </completionHelp> + <constraint> + <regex>(AES-128-CMAC|BIP-CMAC-256|BIP-GMAC-128|BIP-GMAC-256)</regex> + </constraint> + <constraintErrorMessage>Invalid group management cipher selection</constraintErrorMessage> + </properties> + <defaultValue>AES-128-CMAC</defaultValue> + </leafNode> <leafNode name="mode"> <properties> <help>WPA mode</help> @@ -732,6 +888,10 @@ <format>wpa+wpa2</format> <description>Allow both WPA and WPA2</description> </valueHelp> + <valueHelp> + <format>wpa3</format> + <description>WPA3 (required for 802.11ax, you must also set mgmt-frame-protection as required)</description> + </valueHelp> <constraint> <regex>(wpa|wpa2|wpa\+wpa2|wpa3)</regex> </constraint> diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in index 81228938f..7cb1ec06e 100644 --- a/interface-definitions/service_pppoe-server.xml.in +++ b/interface-definitions/service_pppoe-server.xml.in @@ -47,6 +47,12 @@ </leafNode> </children> </node> + <leafNode name="any-login"> + <properties> + <help>Authentication with any login</help> + <valueless/> + </properties> + </leafNode> </children> </node> <tagNode name="interface"> diff --git a/op-mode-definitions/generate_firewall_rule-resequence.xml.in b/op-mode-definitions/generate_firewall_rule-resequence.xml.in index 66078deb9..ef81579fa 100644 --- a/op-mode-definitions/generate_firewall_rule-resequence.xml.in +++ b/op-mode-definitions/generate_firewall_rule-resequence.xml.in @@ -7,34 +7,7 @@ <help>Firewall</help> </properties> <children> - <node name="rule-resequence"> - <properties> - <help>Resequence the firewall rules</help> - </properties> - <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py</command> - <children> - <tagNode name="start"> - <properties> - <help>Set the first sequence number</help> - <completionHelp> - <list>1-1000</list> - </completionHelp> - </properties> - <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py --start $5</command> - <children> - <tagNode name="step"> - <properties> - <help>Step between rules</help> - <completionHelp> - <list>1-1000</list> - </completionHelp> - </properties> - <command>${vyos_op_scripts_dir}/generate_firewall_rule-resequence.py --start $5 --step $7</command> - </tagNode> - </children> - </tagNode> - </children> - </node> + #include <include/rule-resequence.xml.i> </children> </node> </children> diff --git a/op-mode-definitions/generate_nat64_rule-resequence.xml.in b/op-mode-definitions/generate_nat64_rule-resequence.xml.in new file mode 100644 index 000000000..399253b37 --- /dev/null +++ b/op-mode-definitions/generate_nat64_rule-resequence.xml.in @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="generate"> + <children> + <node name="nat64"> + <properties> + <help>Network Address Translation (NAT64)</help> + </properties> + <children> + #include <include/rule-resequence.xml.i> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/generate_nat66_rule-resequence.xml.in b/op-mode-definitions/generate_nat66_rule-resequence.xml.in new file mode 100644 index 000000000..d7159cf60 --- /dev/null +++ b/op-mode-definitions/generate_nat66_rule-resequence.xml.in @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="generate"> + <children> + <node name="nat66"> + <properties> + <help>Network Prefix Translation (NAT66/NPTv6)</help> + </properties> + <children> + #include <include/rule-resequence.xml.i> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/generate_nat_rule-resequence.xml.in b/op-mode-definitions/generate_nat_rule-resequence.xml.in new file mode 100644 index 000000000..e32a89e08 --- /dev/null +++ b/op-mode-definitions/generate_nat_rule-resequence.xml.in @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="generate"> + <children> + <node name="nat"> + <properties> + <help>Network Address Translation (NAT)</help> + </properties> + <children> + #include <include/rule-resequence.xml.i> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/op-mode-definitions/include/rule-resequence.xml.i b/op-mode-definitions/include/rule-resequence.xml.i new file mode 100644 index 000000000..987bf634e --- /dev/null +++ b/op-mode-definitions/include/rule-resequence.xml.i @@ -0,0 +1,30 @@ +<!-- included start from show-nht.xml.i --> +<node name="rule-resequence"> + <properties> + <help>Resequence rules</help> + </properties> + <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2</command> + <children> + <tagNode name="start"> + <properties> + <help>Set the first sequence number</help> + <completionHelp> + <list>1-1000</list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2 --start $5</command> + <children> + <tagNode name="step"> + <properties> + <help>Step between rules</help> + <completionHelp> + <list>1-1000</list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/generate_service_rule-resequence.py --service $2 --start $5 --step $7</command> + </tagNode> + </children> + </tagNode> + </children> +</node> +<!-- included end --> diff --git a/python/vyos/base.py b/python/vyos/base.py index 054b1d837..ca96d96ce 100644 --- a/python/vyos/base.py +++ b/python/vyos/base.py @@ -63,3 +63,10 @@ class ConfigError(Exception): message = fill(message, width=72) # Call the base class constructor with the parameters it needs super().__init__(message) + +class MigrationError(Exception): + def __init__(self, message): + # Reformat the message and trim it to 72 characters in length + message = fill(message, width=72) + # Call the base class constructor with the parameters it needs + super().__init__(message) diff --git a/python/vyos/component_version.py b/python/vyos/component_version.py index 9662ebfcf..0c305e5e0 100644 --- a/python/vyos/component_version.py +++ b/python/vyos/component_version.py @@ -1,4 +1,4 @@ -# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2022-2024 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 @@ -35,133 +35,173 @@ VyOS 1.2: import os import re import sys -import fileinput +from dataclasses import dataclass +from dataclasses import replace +from typing import Optional from vyos.xml_ref import component_version +from vyos.utils.file import write_file from vyos.version import get_version from vyos.defaults import directories DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot') -def from_string(string_line, vintage='vyos'): - """ - Get component version dictionary from string. - Return empty dictionary if string contains no config information - or raise error if component version string malformed. - """ - version_dict = {} - - if vintage == 'vyos': - if re.match(r'// vyos-config-version:.+', string_line): - if not re.match(r'// vyos-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s*', string_line): - raise ValueError(f"malformed configuration string: {string_line}") +REGEX_WARN_VYOS = r'(// Warning: Do not remove the following line.)' +REGEX_WARN_VYATTA = r'(/\* Warning: Do not remove the following line. \*/)' +REGEX_COMPONENT_VERSION_VYOS = r'// vyos-config-version:\s+"([\w@:-]+)"\s*' +REGEX_COMPONENT_VERSION_VYATTA = r'/\* === vyatta-config-version:\s+"([\w@:-]+)"\s+=== \*/' +REGEX_RELEASE_VERSION_VYOS = r'// Release version:\s+(\S*)\s*' +REGEX_RELEASE_VERSION_VYATTA = r'/\* Release version:\s+(\S*)\s*\*/' - for pair in re.findall(r'([\w,-]+)@(\d+)', string_line): - version_dict[pair[0]] = int(pair[1]) - - elif vintage == 'vyatta': - if re.match(r'/\* === vyatta-config-version:.+=== \*/$', string_line): - if not re.match(r'/\* === vyatta-config-version:\s+"([\w,-]+@\d+:)+([\w,-]+@\d+)"\s+=== \*/$', string_line): - raise ValueError(f"malformed configuration string: {string_line}") +CONFIG_FILE_VERSION = """\ +// Warning: Do not remove the following line. +// vyos-config-version: "{}" +// Release version: {} +""" - for pair in re.findall(r'([\w,-]+)@(\d+)', string_line): - version_dict[pair[0]] = int(pair[1]) +warn_filter_vyos = re.compile(REGEX_WARN_VYOS) +warn_filter_vyatta = re.compile(REGEX_WARN_VYATTA) + +regex_filter = { 'vyos': dict(zip(['component', 'release'], + [re.compile(REGEX_COMPONENT_VERSION_VYOS), + re.compile(REGEX_RELEASE_VERSION_VYOS)])), + 'vyatta': dict(zip(['component', 'release'], + [re.compile(REGEX_COMPONENT_VERSION_VYATTA), + re.compile(REGEX_RELEASE_VERSION_VYATTA)])) } + +@dataclass +class VersionInfo: + component: Optional[dict[str,int]] = None + release: str = get_version() + vintage: str = 'vyos' + config_body: Optional[str] = None + footer_lines: Optional[list[str]] = None + + def component_is_none(self) -> bool: + return bool(self.component is None) + + def config_body_is_none(self) -> bool: + return bool(self.config_body is None) + + def update_footer(self): + f = CONFIG_FILE_VERSION.format(component_to_string(self.component), + self.release) + self.footer_lines = f.splitlines() + + def update_syntax(self): + self.vintage = 'vyos' + self.update_footer() + + def update_release(self, release: str): + self.release = release + self.update_footer() + + def update_component(self, key: str, version: int): + if not isinstance(version, int): + raise ValueError('version must be int') + if self.component is None: + self.component = {} + self.component[key] = version + self.component = dict(sorted(self.component.items(), key=lambda x: x[0])) + self.update_footer() + + def update_config_body(self, config_str: str): + self.config_body = config_str + + def write_string(self) -> str: + config_body = '' if self.config_body is None else self.config_body + footer_lines = [] if self.footer_lines is None else self.footer_lines + + return config_body + '\n' + '\n'.join(footer_lines) + '\n' + + def write(self, config_file): + string = self.write_string() + try: + write_file(config_file, string) + except Exception as e: + raise ValueError(e) from e + +def component_to_string(component: dict) -> str: + l = [f'{k}@{v}' for k, v in sorted(component.items(), key=lambda x: x[0])] + return ':'.join(l) + +def component_from_string(string: str) -> dict: + return {k: int(v) for k, v in re.findall(r'([\w,-]+)@(\d+)', string)} + +def version_info_from_file(config_file) -> VersionInfo: + version_info = VersionInfo() + try: + with open(config_file) as f: + config_str = f.read() + except OSError: + return None + + if len(parts := warn_filter_vyos.split(config_str)) > 1: + vintage = 'vyos' + elif len(parts := warn_filter_vyatta.split(config_str)) > 1: + vintage = 'vyatta' else: - raise ValueError("Unknown config string vintage") + version_info.config_body = parts[0] if parts else None + return version_info - return version_dict + version_info.vintage = vintage + version_info.config_body = parts[0] + version_lines = ''.join(parts[1:]).splitlines() + version_lines = [k for k in version_lines if k] + if len(version_lines) != 3: + raise ValueError(f'Malformed version strings: {version_lines}') -def from_file(config_file_name=DEFAULT_CONFIG_PATH, vintage='vyos'): - """ - Get component version dictionary parsing config file line by line - """ - with open(config_file_name, 'r') as f: - for line_in_config in f: - version_dict = from_string(line_in_config, vintage=vintage) - if version_dict: - return version_dict + m = regex_filter[vintage]['component'].match(version_lines[1]) + if not m: + raise ValueError(f'Malformed component string: {version_lines[1]}') + version_info.component = component_from_string(m.group(1)) - # no version information - return {} + m = regex_filter[vintage]['release'].match(version_lines[2]) + if not m: + raise ValueError(f'Malformed component string: {version_lines[2]}') + version_info.release = m.group(1) -def from_system(): - """ - Get system component version dict. - """ - return component_version() + version_info.footer_lines = version_lines -def format_string(ver: dict) -> str: - """ - Version dict to string. - """ - keys = list(ver) - keys.sort() - l = [] - for k in keys: - v = ver[k] - l.append(f'{k}@{v}') - sep = ':' - return sep.join(l) - -def version_footer(ver: dict, vintage='vyos') -> str: - """ - Version footer as string. - """ - ver_str = format_string(ver) - release = get_version() - if vintage == 'vyos': - ret_str = (f'// Warning: Do not remove the following line.\n' - + f'// vyos-config-version: "{ver_str}"\n' - + f'// Release version: {release}\n') - elif vintage == 'vyatta': - ret_str = (f'/* Warning: Do not remove the following line. */\n' - + f'/* === vyatta-config-version: "{ver_str}" === */\n' - + f'/* Release version: {release} */\n') - else: - raise ValueError("Unknown config string vintage") + return version_info - return ret_str - -def system_footer(vintage='vyos') -> str: +def version_info_from_system() -> VersionInfo: """ - System version footer as string. + Return system component versions. """ - ver_d = from_system() - return version_footer(ver_d, vintage=vintage) + d = component_version() + sort_d = dict(sorted(d.items(), key=lambda x: x[0])) + version_info = VersionInfo( + component = sort_d, + release = get_version(), + vintage = 'vyos' + ) + + return version_info -def write_version_footer(ver: dict, file_name, vintage='vyos'): +def version_info_copy(v: VersionInfo) -> VersionInfo: """ - Write version footer to file. + Make a copy of dataclass. """ - footer = version_footer(ver=ver, vintage=vintage) - if file_name: - with open(file_name, 'a') as f: - f.write(footer) - else: - sys.stdout.write(footer) + return replace(v) -def write_system_footer(file_name, vintage='vyos'): +def version_info_prune_component(x: VersionInfo, y: VersionInfo) -> VersionInfo: """ - Write system version footer to file. + In place pruning of component keys of x not in y. """ - ver_d = from_system() - return write_version_footer(ver_d, file_name=file_name, vintage=vintage) + x.component = { k: v for k,v in x.component.items() if k in y.component } -def remove_footer(file_name): +def add_system_version(config_str: str = None, out_file: str = None): """ - Remove old version footer. + Wrap config string with system version and write to out_file. + For convenience, calling with no argument will write system version + string to stdout, for use in bash scripts. """ - for line in fileinput.input(file_name, inplace=True): - if re.match(r'/\* Warning:.+ \*/$', line): - continue - if re.match(r'/\* === vyatta-config-version:.+=== \*/$', line): - continue - if re.match(r'/\* Release version:.+ \*/$', line): - continue - if re.match('// vyos-config-version:.+', line): - continue - if re.match('// Warning:.+', line): - continue - if re.match('// Release version:.+', line): - continue - sys.stdout.write(line) + version_info = version_info_from_system() + if config_str is not None: + version_info.update_config_body(config_str) + version_info.update_footer() + if out_file is not None: + version_info.write(out_file) + else: + sys.stdout.write(version_info.write_string()) diff --git a/python/vyos/compose_config.py b/python/vyos/compose_config.py index efa28babe..79a8718c5 100644 --- a/python/vyos/compose_config.py +++ b/python/vyos/compose_config.py @@ -17,12 +17,13 @@ config. """ +import traceback from pathlib import Path from typing import TypeAlias, Union, Callable from vyos.configtree import ConfigTree from vyos.configtree import deep_copy as ct_deep_copy -from vyos.utils.system import load_as_module +from vyos.utils.system import load_as_module_source ConfigObj: TypeAlias = Union[str, ConfigTree] @@ -54,7 +55,8 @@ class ComposeConfig: try: func(self.config_tree) except Exception as e: - self.config_tree = self.checkpoint + if self.checkpoint_file is not None: + self.config_tree = self.checkpoint raise ComposeConfigError(e) from e def apply_file(self, func_file: str, func_name: str): @@ -62,7 +64,7 @@ class ComposeConfig: """ try: mod_name = Path(func_file).stem.replace('-', '_') - mod = load_as_module(mod_name, func_file) + mod = load_as_module_source(mod_name, func_file) func = getattr(mod, func_name) except Exception as e: raise ComposeConfigError(f'Error with {func_file}: {e}') from e @@ -70,7 +72,9 @@ class ComposeConfig: try: self.apply_func(func) except ComposeConfigError as e: - raise ComposeConfigError(f'Error in {func_file}: {e}') from e + msg = str(e) + tb = f'{traceback.format_exc()}' + raise ComposeConfigError(f'Error in {func_file}: {msg}\n{tb}') from e def to_string(self, with_version=False) -> str: """Return the rendered config tree. diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py index afd6e030b..5775070e2 100644 --- a/python/vyos/configtree.py +++ b/python/vyos/configtree.py @@ -15,6 +15,7 @@ import os import re import json +import logging from ctypes import cdll, c_char_p, c_void_p, c_int, c_bool @@ -161,6 +162,8 @@ class ConfigTree(object): self.__version = '' self.__migration = os.environ.get('VYOS_MIGRATION') + if self.__migration: + self.migration_log = logging.getLogger('vyos.migrate') def __del__(self): if self.__config is not None: @@ -215,7 +218,7 @@ class ConfigTree(object): self.__set_add_value(self.__config, path_str, str(value).encode()) if self.__migration: - print(f"- op: set path: {path} value: {value} replace: {replace}") + self.migration_log.info(f"- op: set path: {path} value: {value} replace: {replace}") def delete(self, path): check_path(path) @@ -226,7 +229,7 @@ class ConfigTree(object): raise ConfigTreeError(f"Path doesn't exist: {path}") if self.__migration: - print(f"- op: delete path: {path}") + self.migration_log.info(f"- op: delete path: {path}") def delete_value(self, path, value): check_path(path) @@ -242,7 +245,7 @@ class ConfigTree(object): raise ConfigTreeError() if self.__migration: - print(f"- op: delete_value path: {path} value: {value}") + self.migration_log.info(f"- op: delete_value path: {path} value: {value}") def rename(self, path, new_name): check_path(path) @@ -258,7 +261,7 @@ class ConfigTree(object): raise ConfigTreeError("Path [{}] doesn't exist".format(path)) if self.__migration: - print(f"- op: rename old_path: {path} new_path: {new_path}") + self.migration_log.info(f"- op: rename old_path: {path} new_path: {new_path}") def copy(self, old_path, new_path): check_path(old_path) @@ -275,7 +278,7 @@ class ConfigTree(object): raise ConfigTreeError(msg) if self.__migration: - print(f"- op: copy old_path: {old_path} new_path: {new_path}") + self.migration_log.info(f"- op: copy old_path: {old_path} new_path: {new_path}") def exists(self, path): check_path(path) diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py index d45c9c272..80bb56fa2 100644 --- a/python/vyos/ethtool.py +++ b/python/vyos/ethtool.py @@ -16,6 +16,7 @@ import re from json import loads +from vyos.utils.network import interface_exists from vyos.utils.process import popen # These drivers do not support using ethtool to change the speed, duplex, or @@ -64,6 +65,9 @@ class Ethtool: def __init__(self, ifname): # Get driver used for interface + if not interface_exists(ifname): + raise ValueError(f'Interface "{ifname}" does not exist!') + out, _ = popen(f'ethtool --driver {ifname}') driver = re.search(r'driver:\s(\w+)', out) if driver: diff --git a/python/vyos/load_config.py b/python/vyos/load_config.py index af563614d..b910a2f92 100644 --- a/python/vyos/load_config.py +++ b/python/vyos/load_config.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-2024 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 @@ -28,9 +28,7 @@ from typing import Union, Literal, TypeAlias, get_type_hints, get_args from vyos.config import Config from vyos.configtree import ConfigTree, DiffTree from vyos.configsource import ConfigSourceSession, VyOSError -from vyos.component_version import from_string as version_from_string -from vyos.component_version import from_system as version_from_system -from vyos.migrator import Migrator, VirtualMigrator, MigratorError +from vyos.migrate import ConfigMigrate, ConfigMigrateError from vyos.utils.process import popen, DEVNULL Variety: TypeAlias = Literal['explicit', 'batch', 'tree', 'legacy'] @@ -51,20 +49,6 @@ def get_proposed_config(config_file: str = None) -> ConfigTree: config_str = Path(config_file).read_text() return ConfigTree(config_str) -def migration_needed(config_obj: ConfigObj) -> bool: - """Check if a migration is needed for the config object. - """ - if not isinstance(config_obj, ConfigTree): - atree = get_proposed_config(config_obj) - else: - atree = config_obj - version_str = atree.get_version_string() - if not version_str: - return True - aversion = version_from_string(version_str.splitlines()[1]) - bversion = version_from_system() - return aversion != bversion - def check_session(strict: bool, switch: Variety) -> None: """Check if we are in a config session, with no uncommitted changes, if strict. This is not needed for legacy load, as these checks are @@ -128,12 +112,10 @@ def migrate(config_obj: ConfigObj) -> ConfigObj: else: config_file = config_obj - virtual_migration = VirtualMigrator(config_file) - migration = Migrator(config_file) + config_migrate = ConfigMigrate(config_file) try: - virtual_migration.run() - migration.run() - except MigratorError as e: + config_migrate.run() + except ConfigMigrateError as e: raise LoadConfigError(e) from e else: if isinstance(config_obj, ConfigTree): @@ -193,8 +175,7 @@ def load(config_obj: ConfigObj, strict: bool = True, check_session(strict, switch) - if migration_needed(config_obj): - config_obj = migrate(config_obj) + config_obj = migrate(config_obj) func = getattr(thismod, f'load_{switch}') func(config_obj) diff --git a/python/vyos/migrate.py b/python/vyos/migrate.py new file mode 100644 index 000000000..9d1613676 --- /dev/null +++ b/python/vyos/migrate.py @@ -0,0 +1,283 @@ +# Copyright 2019-2024 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/>. + +import os +import re +import json +import logging +from pathlib import Path +from grp import getgrnam + +from vyos.component_version import VersionInfo +from vyos.component_version import version_info_from_system +from vyos.component_version import version_info_from_file +from vyos.component_version import version_info_copy +from vyos.component_version import version_info_prune_component +from vyos.compose_config import ComposeConfig +from vyos.compose_config import ComposeConfigError +from vyos.configtree import ConfigTree +from vyos.defaults import directories as default_dir +from vyos.defaults import component_version_json + + +log_file = Path(default_dir['config']).joinpath('vyos-migrate.log') + +class ConfigMigrateError(Exception): + """Raised on error in config migration.""" + +class ConfigMigrate: + # pylint: disable=too-many-instance-attributes + # the number is reasonable in this case + def __init__(self, config_file: str, force=False, + output_file: str = None, checkpoint_file: str = None): + self.config_file: str = config_file + self.force: bool = force + self.system_version: VersionInfo = version_info_from_system() + self.file_version: VersionInfo = version_info_from_file(self.config_file) + self.compose = None + self.output_file = output_file + self.checkpoint_file = checkpoint_file + self.logger = None + self.config_modified = True + + if self.file_version is None: + raise ConfigMigrateError(f'failed to read config file {self.config_file}') + + def migration_needed(self) -> bool: + return self.system_version.component != self.file_version.component + + def release_update_needed(self) -> bool: + return self.system_version.release != self.file_version.release + + def syntax_update_needed(self) -> bool: + return self.system_version.vintage != self.file_version.vintage + + def update_release(self): + """ + Update config file release version. + """ + self.file_version.update_release(self.system_version.release) + + def update_syntax(self): + """ + Update config file syntax. + """ + self.file_version.update_syntax() + + @staticmethod + def normalize_config_body(version_info: VersionInfo): + """ + This is an interim workaround for the cosmetic issue of node + ordering when composing operations on the internal config_tree: + ordering is performed on parsing, hence was maintained in the old + system which would parse/write on each application of a migration + script (~200). Here, we will take the cost of one extra parsing to + reorder before save, for easier review. + """ + if not version_info.config_body_is_none(): + ct = ConfigTree(version_info.config_body) + version_info.update_config_body(ct.to_string()) + + def write_config(self): + if self.output_file is not None: + config_file = self.output_file + else: + config_file = self.config_file + + try: + self.file_version.write(config_file) + except ValueError as e: + raise ConfigMigrateError(f'failed to write {config_file}: {e}') from e + + def init_logger(self): + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.DEBUG) + + fh = ConfigMigrate.group_perm_file_handler(log_file, + group='vyattacfg', + mode='w') + fh.setLevel(logging.INFO) + fh_formatter = logging.Formatter('%(message)s') + fh.setFormatter(fh_formatter) + self.logger.addHandler(fh) + ch = logging.StreamHandler() + ch.setLevel(logging.WARNING) + ch_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') + ch.setFormatter(ch_formatter) + self.logger.addHandler(ch) + + @staticmethod + def group_perm_file_handler(filename, group=None, mode='a'): + # pylint: disable=consider-using-with + if group is None: + return logging.FileHandler(filename, mode) + gid = getgrnam(group).gr_gid + if not os.path.exists(filename): + open(filename, 'a').close() + os.chown(filename, -1, gid) + os.chmod(filename, 0o664) + return logging.FileHandler(filename, mode) + + @staticmethod + def sort_function(): + """ + Define sort function for migration files as tuples (n, m) for file + n-to-m. + """ + numbers = re.compile(r'(\d+)') + def func(p: Path): + parts = numbers.split(p.stem) + return list(map(int, parts[1::2])) + return func + + @staticmethod + def file_ext(file_path: Path) -> str: + """ + Return an identifier from file name for checkpoint file extension. + """ + return f'{file_path.parent.stem}_{file_path.stem}' + + def run_migration_scripts(self): + """ + Call migration files iteratively. + """ + os.environ['VYOS_MIGRATION'] = '1' + + self.init_logger() + self.logger.info("List of applied migration modules:") + + components = list(self.system_version.component) + components.sort() + + # T4382: 'bgp' needs to follow 'quagga': + if 'bgp' in components and 'quagga' in components: + components.insert(components.index('quagga'), + components.pop(components.index('bgp'))) + + revision: VersionInfo = version_info_copy(self.file_version) + # prune retired, for example, zone-policy + version_info_prune_component(revision, self.system_version) + + migrate_dir = Path(default_dir['migrate']) + sort_func = ConfigMigrate.sort_function() + + for key in components: + p = migrate_dir.joinpath(key) + script_list = list(p.glob('*-to-*')) + script_list = sorted(script_list, key=sort_func) + + if not self.file_version.component_is_none() and not self.force: + start = self.file_version.component.get(key, 0) + script_list = list(filter(lambda x, st=start: sort_func(x)[0] >= st, + script_list)) + + if not script_list: # no applicable migration scripts + revision.update_component(key, self.system_version.component[key]) + continue + + for file in script_list: + f = file.as_posix() + self.logger.info(f'applying {f}') + try: + self.compose.apply_file(f, func_name='migrate') + except ComposeConfigError as e: + self.logger.error(e) + if self.checkpoint_file: + check = f'{self.checkpoint_file}_{ConfigMigrate.file_ext(file)}' + revision.update_config_body(self.compose.to_string()) + ConfigMigrate.normalize_config_body(revision) + revision.write(check) + break + else: + revision.update_component(key, sort_func(file)[1]) + + revision.update_config_body(self.compose.to_string()) + ConfigMigrate.normalize_config_body(revision) + self.file_version = version_info_copy(revision) + + if revision.component != self.system_version.component: + raise ConfigMigrateError(f'incomplete migration: check {log_file} for error') + + del os.environ['VYOS_MIGRATION'] + + def save_json_record(self): + """ + Write component versions to a json file + """ + version_file = component_version_json + + try: + with open(version_file, 'w') as f: + f.write(json.dumps(self.system_version.component, + indent=2, sort_keys=True)) + except OSError: + pass + + def load_config(self): + """ + Instantiate a ComposeConfig object with the config string. + """ + + self.compose = ComposeConfig(self.file_version.config_body, self.checkpoint_file) + + def run(self): + """ + If migration needed, run migration scripts and update config file. + If only release version update needed, update release version. + """ + # save system component versions in json file for reference + self.save_json_record() + + if not self.migration_needed(): + if self.release_update_needed(): + self.update_release() + self.write_config() + else: + self.config_modified = False + return + + if self.syntax_update_needed(): + self.update_syntax() + self.write_config() + + self.load_config() + + self.run_migration_scripts() + + self.update_release() + self.write_config() + + def run_script(self, test_script: str): + """ + Run a single migration script. For testing this simply provides the + body for loading and writing the result; the component string is not + updated. + """ + + self.load_config() + self.init_logger() + + os.environ['VYOS_MIGRATION'] = '1' + + try: + self.compose.apply_file(test_script, func_name='migrate') + except ComposeConfigError as e: + self.logger.error(f'config-migration error in {test_script}: {e}') + else: + self.file_version.update_config_body(self.compose.to_string()) + + del os.environ['VYOS_MIGRATION'] + + self.write_config() diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py deleted file mode 100644 index 872682bc0..000000000 --- a/python/vyos/migrator.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2019-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/>. - -import sys -import os -import json -import logging - -import vyos.defaults -import vyos.component_version as component_version -from vyos.utils.process import cmd - -log_file = os.path.join(vyos.defaults.directories['config'], 'vyos-migrate.log') - -class MigratorError(Exception): - pass - -class Migrator(object): - def __init__(self, config_file, force=False, set_vintage='vyos'): - self._config_file = config_file - self._force = force - self._set_vintage = set_vintage - self._config_file_vintage = None - self._changed = False - - def init_logger(self): - self.logger = logging.getLogger(__name__) - self.logger.setLevel(logging.DEBUG) - - # on adding the file handler, allow write permission for cfg_group; - # restore original umask on exit - mask = os.umask(0o113) - fh = logging.FileHandler(log_file) - formatter = logging.Formatter('%(message)s') - fh.setFormatter(formatter) - self.logger.addHandler(fh) - os.umask(mask) - - def read_config_file_versions(self): - """ - Get component versions from config file footer and set vintage; - return empty dictionary if config string is missing. - """ - cfg_file = self._config_file - component_versions = {} - - cfg_versions = component_version.from_file(cfg_file, vintage='vyatta') - - if cfg_versions: - self._config_file_vintage = 'vyatta' - component_versions = cfg_versions - - cfg_versions = component_version.from_file(cfg_file, vintage='vyos') - - if cfg_versions: - self._config_file_vintage = 'vyos' - component_versions = cfg_versions - - return component_versions - - def update_vintage(self): - old_vintage = self._config_file_vintage - - if self._set_vintage: - self._config_file_vintage = self._set_vintage - - if self._config_file_vintage not in ['vyatta', 'vyos']: - raise MigratorError("Unknown vintage.") - - if self._config_file_vintage == old_vintage: - return False - else: - return True - - def run_migration_scripts(self, config_file_versions, system_versions): - """ - Run migration scripts iteratively, until config file version equals - system component version. - """ - os.environ['VYOS_MIGRATION'] = '1' - self.init_logger() - - self.logger.info("List of executed migration scripts:") - - cfg_versions = config_file_versions - sys_versions = system_versions - - sys_keys = list(sys_versions.keys()) - sys_keys.sort() - - # XXX 'bgp' needs to follow 'quagga': - if 'bgp' in sys_keys and 'quagga' in sys_keys: - sys_keys.insert(sys_keys.index('quagga'), - sys_keys.pop(sys_keys.index('bgp'))) - - rev_versions = {} - - for key in sys_keys: - sys_ver = sys_versions[key] - if key in cfg_versions: - cfg_ver = cfg_versions[key] - else: - cfg_ver = 0 - - migrate_script_dir = os.path.join( - vyos.defaults.directories['migrate'], key) - - while cfg_ver < sys_ver: - next_ver = cfg_ver + 1 - - migrate_script = os.path.join(migrate_script_dir, - '{}-to-{}'.format(cfg_ver, next_ver)) - - try: - out = cmd([migrate_script, self._config_file]) - self.logger.info(f'{migrate_script}') - if out: self.logger.info(out) - except FileNotFoundError: - pass - except Exception as err: - print("\nMigration script error: {0}: {1}." - "".format(migrate_script, err)) - sys.exit(1) - - cfg_ver = next_ver - rev_versions[key] = cfg_ver - - del os.environ['VYOS_MIGRATION'] - return rev_versions - - def write_config_file_versions(self, cfg_versions): - """ - Write new versions string. - """ - if self._config_file_vintage == 'vyatta': - component_version.write_version_footer(cfg_versions, - self._config_file, - vintage='vyatta') - - if self._config_file_vintage == 'vyos': - component_version.write_version_footer(cfg_versions, - self._config_file, - vintage='vyos') - - def save_json_record(self, component_versions: dict): - """ - Write component versions to a json file - """ - mask = os.umask(0o113) - version_file = vyos.defaults.component_version_json - try: - with open(version_file, 'w') as f: - f.write(json.dumps(component_versions, indent=2, sort_keys=True)) - except OSError: - pass - finally: - os.umask(mask) - - def run(self): - """ - Gather component versions from config file and system. - Run migration scripts. - Update vintage ('vyatta' or 'vyos'), if needed. - If changed, remove old versions string from config file, and - write new versions string. - """ - cfg_file = self._config_file - - cfg_versions = self.read_config_file_versions() - if self._force: - # This will force calling all migration scripts: - cfg_versions = {} - - sys_versions = component_version.from_system() - - # save system component versions in json file for easy reference - self.save_json_record(sys_versions) - - rev_versions = self.run_migration_scripts(cfg_versions, sys_versions) - - if rev_versions != cfg_versions: - self._changed = True - - if self.update_vintage(): - self._changed = True - - if not self._changed: - return - - component_version.remove_footer(cfg_file) - - self.write_config_file_versions(rev_versions) - - def config_changed(self): - return self._changed - -class VirtualMigrator(Migrator): - def run(self): - cfg_file = self._config_file - - cfg_versions = self.read_config_file_versions() - if not cfg_versions: - return - - if self.update_vintage(): - self._changed = True - - if not self._changed: - return - - component_version.remove_footer(cfg_file) - - self.write_config_file_versions(cfg_versions) - diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py index 062ab9c81..1eb6abcd5 100644 --- a/python/vyos/utils/dict.py +++ b/python/vyos/utils/dict.py @@ -34,7 +34,7 @@ def colon_separated_to_dict(data_string, uniquekeys=False): otherwise they are always lists of strings. """ import re - key_value_re = re.compile('([^:]+)\s*\:\s*(.*)') + key_value_re = re.compile(r'([^:]+)\s*\:\s*(.*)') data_raw = re.split('\n', data_string) diff --git a/python/vyos/utils/system.py b/python/vyos/utils/system.py index f427032a4..fca93d118 100644 --- a/python/vyos/utils/system.py +++ b/python/vyos/utils/system.py @@ -99,6 +99,18 @@ def load_as_module(name: str, path: str): spec.loader.exec_module(mod) return mod +def load_as_module_source(name: str, path: str): + """ Necessary modification of load_as_module for files without *.py + extension """ + import importlib.util + from importlib.machinery import SourceFileLoader + + loader = SourceFileLoader(name, path) + spec = importlib.util.spec_from_loader(name, loader) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + def get_uptime_seconds(): """ Returns system uptime in seconds """ from re import search @@ -127,4 +139,3 @@ def get_load_averages(): res[15] = float(matches["fifteen"]) / core_count return res - diff --git a/scripts/generate-configd-include-json.py b/scripts/generate-configd-include-json.py new file mode 100755 index 000000000..b4b627fce --- /dev/null +++ b/scripts/generate-configd-include-json.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# Copyright (C) 2024 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +from jinja2 import Template + +conf_scripts = 'src/conf_mode' +configd_include = 'data/configd-include.json' + +configd_template = Template("""[ +{% for file in files %} +"{{ file }}"{{ "," if not loop.last else "" }} +{% endfor %} +] +""", trim_blocks=True) + +files = [f for f in os.listdir(conf_scripts) if os.path.isfile(f'{conf_scripts}/{f}')] +files = sorted(files) + +tmp = {'files' : files} +with open(configd_include, 'w') as f: + f.write(configd_template.render(tmp)) diff --git a/smoketest/bin/vyos-configtest b/smoketest/bin/vyos-configtest index c1b602737..fbf4055ad 100755 --- a/smoketest/bin/vyos-configtest +++ b/smoketest/bin/vyos-configtest @@ -55,7 +55,7 @@ def make_test_function(filename, test_path=None): if test_path: config_commands = self.session.show(['configuration', 'commands']) - + with open(test_path, 'r') as f: for line in f.readlines(): if not line or line.startswith("#"): @@ -83,9 +83,10 @@ if __name__ == '__main__': test_path = os.path.join(config_test_dir, config) if not os.path.exists(test_path): - test_path = None - else: - log.info(f'Loaded migration result test for config "{config}"') + log.error(f'Missing migration result test for config "{config}"') + sys.exit(1) + + log.info(f'Loaded migration result test for config "{config}"') test_func = make_test_function(config, test_path) diff --git a/smoketest/bin/vyos-configtest-pki b/smoketest/bin/vyos-configtest-pki index e753193e9..0f9ecdd41 100755 --- a/smoketest/bin/vyos-configtest-pki +++ b/smoketest/bin/vyos-configtest-pki @@ -25,9 +25,9 @@ from vyos.pki import encode_dh_parameters from vyos.pki import encode_private_key from vyos.utils.file import write_file -subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos'} -ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos CA'} -subca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos SubCA'} +subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS'} +ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS CA'} +subca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'VyOS SubCA'} ca_cert = '/config/auth/ovpn_test_ca.pem' ca_key = '/config/auth/ovpn_test_ca.key' diff --git a/smoketest/config-tests/basic-api-service b/smoketest/config-tests/basic-api-service index dc54929b9..3f796f35d 100644 --- a/smoketest/config-tests/basic-api-service +++ b/smoketest/config-tests/basic-api-service @@ -1,16 +1,28 @@ set interfaces ethernet eth0 address '192.0.2.1/31' set interfaces ethernet eth0 address '2001:db8::1234/64' +set interfaces ethernet eth0 offload gro set interfaces loopback lo -set service ntp server time1.vyos.net -set service ntp server time2.vyos.net -set service ntp server time3.vyos.net set service https allow-client address '172.16.0.0/12' set service https allow-client address '192.168.0.0/16' set service https allow-client address '10.0.0.0/8' set service https allow-client address '2001:db8::/32' set service https api keys id 1 key 'S3cur3' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' set system host-name 'vyos' set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' set system login user vyos authentication plaintext-password '' -set system console device ttyS0 speed '115200' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos index d676c663d..6ff28ec2e 100644 --- a/smoketest/config-tests/basic-vyos +++ b/smoketest/config-tests/basic-vyos @@ -1,5 +1,14 @@ set interfaces ethernet eth0 address '192.168.0.1/24' set interfaces ethernet eth0 address 'fe88::1/56' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth2 duplex 'auto' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth2 speed 'auto' set interfaces ethernet eth2 vif 100 address '100.100.0.1/24' set interfaces ethernet eth2 vif-s 200 address '100.64.200.254/24' set interfaces ethernet eth2 vif-s 200 vif-c 201 address '100.64.201.254/24' @@ -19,17 +28,6 @@ set protocols static arp interface eth2.200.201 address 100.64.201.20 mac '00:50 set protocols static arp interface eth2.200.202 address 100.64.202.30 mac '00:50:00:00:00:30' set protocols static arp interface eth2.200.202 address 100.64.202.40 mac '00:50:00:00:00:40' set protocols static route 0.0.0.0/0 next-hop 100.64.0.1 -set service ssh ciphers 'aes128-ctr' -set service ssh ciphers 'aes192-ctr' -set service ssh ciphers 'aes256-ctr' -set service ssh ciphers 'chacha20-poly1305@openssh.com' -set service ssh ciphers 'rijndael-cbc@lysator.liu.se' -set service ssh key-exchange 'curve25519-sha256@libssh.org' -set service ssh key-exchange 'diffie-hellman-group1-sha1' -set service ssh key-exchange 'diffie-hellman-group-exchange-sha1' -set service ssh key-exchange 'diffie-hellman-group-exchange-sha256' -set service ssh listen-address '192.168.0.1' -set service ssh port '22' set service dhcp-server shared-network-name LAN authoritative set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option default-router '192.168.0.1' set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 option domain-name 'vyos.net' @@ -66,19 +64,40 @@ set service dns forwarding allow-from '192.168.0.0/16' set service dns forwarding cache-size '10000' set service dns forwarding dnssec 'off' set service dns forwarding listen-address '192.168.0.1' +set service ssh ciphers 'aes128-ctr' +set service ssh ciphers 'aes192-ctr' +set service ssh ciphers 'aes256-ctr' +set service ssh ciphers 'chacha20-poly1305@openssh.com' +set service ssh ciphers 'rijndael-cbc@lysator.liu.se' +set service ssh key-exchange 'curve25519-sha256@libssh.org' +set service ssh key-exchange 'diffie-hellman-group1-sha1' +set service ssh key-exchange 'diffie-hellman-group-exchange-sha1' +set service ssh key-exchange 'diffie-hellman-group-exchange-sha256' +set service ssh listen-address '192.168.0.1' +set service ssh port '22' set system config-management commit-revisions '100' set system conntrack ignore ipv4 rule 1 destination address '192.0.2.2' set system conntrack ignore ipv4 rule 1 source address '192.0.2.1' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' set system host-name 'vyos' set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' set system login user vyos authentication plaintext-password '' set system name-server '192.168.0.1' -set system syslog global facility auth level 'info' -set system syslog global preserve-fqdn set system syslog console facility all level 'emerg' set system syslog console facility mail level 'info' +set system syslog global facility all level 'info' +set system syslog global facility auth level 'info' +set system syslog global facility local7 level 'debug' +set system syslog global preserve-fqdn set system syslog host syslog.vyos.net facility auth level 'warning' set system syslog host syslog.vyos.net facility local7 level 'notice' set system syslog host syslog.vyos.net format octet-counted set system syslog host syslog.vyos.net port '8000' -set system console device ttyS0 speed '115200' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/bgp-azure-ipsec-gateway b/smoketest/config-tests/bgp-azure-ipsec-gateway new file mode 100644 index 000000000..bbd7b961f --- /dev/null +++ b/smoketest/config-tests/bgp-azure-ipsec-gateway @@ -0,0 +1,231 @@ +set firewall global-options all-ping 'enable' +set firewall global-options broadcast-ping 'disable' +set firewall global-options ip-src-route 'disable' +set firewall global-options ipv6-receive-redirects 'disable' +set firewall global-options ipv6-src-route 'disable' +set firewall global-options log-martians 'disable' +set firewall global-options receive-redirects 'disable' +set firewall global-options send-redirects 'enable' +set firewall global-options source-validation 'disable' +set firewall global-options syn-cookies 'enable' +set firewall global-options twa-hazards-protection 'disable' +set high-availability vrrp group DMZ-VLAN-3962 address 192.168.34.36/27 +set high-availability vrrp group DMZ-VLAN-3962 interface 'eth1' +set high-availability vrrp group DMZ-VLAN-3962 preempt-delay '180' +set high-availability vrrp group DMZ-VLAN-3962 priority '200' +set high-availability vrrp group DMZ-VLAN-3962 vrid '62' +set interfaces ethernet eth0 address '192.0.2.189/27' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 address '192.168.34.37/27' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth1 speed 'auto' +set interfaces loopback lo +set interfaces vti vti31 ip adjust-mss '1350' +set interfaces vti vti32 ip adjust-mss '1350' +set interfaces vti vti41 ip adjust-mss '1350' +set interfaces vti vti42 ip adjust-mss '1350' +set interfaces vti vti51 ip adjust-mss '1350' +set interfaces vti vti52 ip adjust-mss '1350' +set policy prefix-list AZURE-BGP-IPv4-in description 'Prefixes received from Azure' +set policy prefix-list AZURE-BGP-IPv4-in rule 100 action 'permit' +set policy prefix-list AZURE-BGP-IPv4-in rule 100 le '32' +set policy prefix-list AZURE-BGP-IPv4-in rule 100 prefix '100.64.0.0/10' +set policy prefix-list ONPREM-BGP-IPv4-out description 'Prefixes allowed to be announced into Azure' +set policy prefix-list ONPREM-BGP-IPv4-out rule 100 action 'permit' +set policy prefix-list ONPREM-BGP-IPv4-out rule 100 prefix '10.0.0.0/8' +set policy prefix-list ONPREM-BGP-IPv4-out rule 200 action 'permit' +set policy prefix-list ONPREM-BGP-IPv4-out rule 200 prefix '172.16.0.0/12' +set policy prefix-list ONPREM-BGP-IPv4-out rule 300 action 'permit' +set policy prefix-list ONPREM-BGP-IPv4-out rule 300 prefix '192.168.0.0/16' +set protocols bgp address-family ipv4-unicast network 10.0.0.0/8 +set protocols bgp address-family ipv4-unicast network 172.16.0.0/12 +set protocols bgp address-family ipv4-unicast network 192.168.0.0/16 +set protocols bgp neighbor 100.66.8.36 peer-group 'AZURE' +set protocols bgp neighbor 100.66.8.36 remote-as '64517' +set protocols bgp neighbor 100.66.8.37 peer-group 'AZURE' +set protocols bgp neighbor 100.66.8.37 remote-as '64517' +set protocols bgp neighbor 100.66.24.36 peer-group 'AZURE' +set protocols bgp neighbor 100.66.24.36 remote-as '64513' +set protocols bgp neighbor 100.66.24.37 peer-group 'AZURE' +set protocols bgp neighbor 100.66.24.37 remote-as '64513' +set protocols bgp neighbor 100.66.40.36 peer-group 'AZURE' +set protocols bgp neighbor 100.66.40.36 remote-as '64515' +set protocols bgp neighbor 100.66.40.37 peer-group 'AZURE' +set protocols bgp neighbor 100.66.40.37 remote-as '64515' +set protocols bgp neighbor 192.168.34.38 address-family ipv4-unicast nexthop-self +set protocols bgp neighbor 192.168.34.38 address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp neighbor 192.168.34.38 capability dynamic +set protocols bgp neighbor 192.168.34.38 password 'VyOSR0xx123' +set protocols bgp neighbor 192.168.34.38 remote-as '65522' +set protocols bgp neighbor 192.168.34.38 update-source 'eth1' +set protocols bgp peer-group AZURE address-family ipv4-unicast maximum-prefix '50' +set protocols bgp peer-group AZURE address-family ipv4-unicast prefix-list export 'ONPREM-BGP-IPv4-out' +set protocols bgp peer-group AZURE address-family ipv4-unicast prefix-list import 'AZURE-BGP-IPv4-in' +set protocols bgp peer-group AZURE ebgp-multihop '2' +set protocols bgp peer-group AZURE update-source 'eth1' +set protocols bgp system-as '65522' +set protocols bgp timers holdtime '30' +set protocols bgp timers keepalive '5' +set protocols static route 0.0.0.0/0 next-hop 192.168.34.33 +set protocols static route 51.105.0.0/16 next-hop 192.0.2.161 +set protocols static route 52.143.0.0/16 next-hop 192.0.2.161 +set protocols static route 100.66.8.36/32 interface vti31 +set protocols static route 100.66.8.36/32 interface vti32 +set protocols static route 100.66.8.37/32 interface vti31 +set protocols static route 100.66.8.37/32 interface vti32 +set protocols static route 100.66.24.36/32 interface vti41 +set protocols static route 100.66.24.36/32 interface vti42 +set protocols static route 100.66.24.37/32 interface vti41 +set protocols static route 100.66.24.37/32 interface vti42 +set protocols static route 100.66.40.36/32 interface vti51 +set protocols static route 100.66.40.36/32 interface vti52 +set protocols static route 100.66.40.37/32 interface vti51 +set protocols static route 100.66.40.37/32 interface vti52 +set protocols static route 195.137.175.0/24 next-hop 192.0.2.161 +set protocols static route 212.23.159.0/26 next-hop 192.0.2.161 +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 192.0.2.254 +set service snmp v3 engineid 'ff42' +set service snmp v3 group default mode 'ro' +set service snmp v3 group default seclevel 'priv' +set service snmp v3 group default view 'default' +set service snmp v3 user VyOS auth encrypted-password '1ad73f4620b8c0dd2de066622f875b161a14adad' +set service snmp v3 user VyOS auth type 'sha' +set service snmp v3 user VyOS group 'default' +set service snmp v3 user VyOS privacy encrypted-password '1ad73f4620b8c0dd2de066622f875b16' +set service snmp v3 user VyOS privacy type 'aes' +set service snmp v3 view default oid 1 +set service ssh disable-host-validation +set service ssh port '22' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system flow-accounting interface 'eth1' +set system flow-accounting interface 'vti31' +set system flow-accounting interface 'vti32' +set system flow-accounting interface 'vti41' +set system flow-accounting interface 'vti42' +set system flow-accounting interface 'vti51' +set system flow-accounting interface 'vti52' +set system flow-accounting netflow server 10.0.1.1 port '2055' +set system flow-accounting netflow source-address '192.168.34.37' +set system flow-accounting netflow version '10' +set system flow-accounting syslog-facility 'daemon' +set system host-name 'azure-gw-01' +set system login radius server 192.0.2.253 key 'secret1234' +set system login radius server 192.0.2.253 port '1812' +set system login radius server 192.0.2.253 timeout '2' +set system login radius server 192.0.2.254 key 'secret1234' +set system login radius server 192.0.2.254 port '1812' +set system login radius server 192.0.2.254 timeout '2' +set system login radius source-address '192.168.34.37' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system logs logrotate messages max-size '20' +set system logs logrotate messages rotate '10' +set system name-server '192.0.2.254' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system syslog host 10.0.9.188 facility all level 'info' +set system syslog host 10.0.9.188 protocol 'udp' +set system time-zone 'Europe/Berlin' +set vpn ipsec authentication psk peer_51-105-0-1 id '51.105.0.1' +set vpn ipsec authentication psk peer_51-105-0-1 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-1 secret 'averysecretpsktowardsazure' +set vpn ipsec authentication psk peer_51-105-0-2 id '51.105.0.2' +set vpn ipsec authentication psk peer_51-105-0-2 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-2 secret 'averysecretpsktowardsazure' +set vpn ipsec authentication psk peer_51-105-0-3 id '51.105.0.3' +set vpn ipsec authentication psk peer_51-105-0-3 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-3 secret 'averysecretpsktowardsazure' +set vpn ipsec authentication psk peer_51-105-0-4 id '51.105.0.4' +set vpn ipsec authentication psk peer_51-105-0-4 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-4 secret 'averysecretpsktowardsazure' +set vpn ipsec authentication psk peer_51-105-0-5 id '51.105.0.5' +set vpn ipsec authentication psk peer_51-105-0-5 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-5 secret 'averysecretpsktowardsazure' +set vpn ipsec authentication psk peer_51-105-0-6 id '51.105.0.6' +set vpn ipsec authentication psk peer_51-105-0-6 id '192.0.2.189' +set vpn ipsec authentication psk peer_51-105-0-6 secret 'averysecretpsktowardsazure' +set vpn ipsec esp-group ESP-AZURE lifetime '27000' +set vpn ipsec esp-group ESP-AZURE mode 'tunnel' +set vpn ipsec esp-group ESP-AZURE pfs 'disable' +set vpn ipsec esp-group ESP-AZURE proposal 1 encryption 'aes256' +set vpn ipsec esp-group ESP-AZURE proposal 1 hash 'sha1' +set vpn ipsec ike-group IKE-AZURE close-action 'none' +set vpn ipsec ike-group IKE-AZURE dead-peer-detection action 'restart' +set vpn ipsec ike-group IKE-AZURE dead-peer-detection interval '2' +set vpn ipsec ike-group IKE-AZURE dead-peer-detection timeout '15' +set vpn ipsec ike-group IKE-AZURE key-exchange 'ikev2' +set vpn ipsec ike-group IKE-AZURE lifetime '27000' +set vpn ipsec ike-group IKE-AZURE proposal 1 dh-group '2' +set vpn ipsec ike-group IKE-AZURE proposal 1 encryption 'aes256' +set vpn ipsec ike-group IKE-AZURE proposal 1 hash 'sha1' +set vpn ipsec interface 'eth0' +set vpn ipsec log level '2' +set vpn ipsec log subsystem 'ike' +set vpn ipsec site-to-site peer peer_51-105-0-1 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-1 authentication remote-id '51.105.0.1' +set vpn ipsec site-to-site peer peer_51-105-0-1 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-1 default-esp-group 'ESP-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-1 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-1 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-1 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-1 remote-address '51.105.0.1' +set vpn ipsec site-to-site peer peer_51-105-0-1 vti bind 'vti51' +set vpn ipsec site-to-site peer peer_51-105-0-2 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-2 authentication remote-id '51.105.0.2' +set vpn ipsec site-to-site peer peer_51-105-0-2 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-2 default-esp-group 'ESP-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-2 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-2 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-2 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-2 remote-address '51.105.0.2' +set vpn ipsec site-to-site peer peer_51-105-0-2 vti bind 'vti52' +set vpn ipsec site-to-site peer peer_51-105-0-3 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-3 authentication remote-id '51.105.0.3' +set vpn ipsec site-to-site peer peer_51-105-0-3 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-3 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-3 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-3 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-3 remote-address '51.105.0.3' +set vpn ipsec site-to-site peer peer_51-105-0-3 vti bind 'vti32' +set vpn ipsec site-to-site peer peer_51-105-0-3 vti esp-group 'ESP-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-4 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-4 authentication remote-id '51.105.0.4' +set vpn ipsec site-to-site peer peer_51-105-0-4 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-4 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-4 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-4 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-4 remote-address '51.105.0.4' +set vpn ipsec site-to-site peer peer_51-105-0-4 vti bind 'vti31' +set vpn ipsec site-to-site peer peer_51-105-0-4 vti esp-group 'ESP-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-5 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-5 authentication remote-id '51.105.0.5' +set vpn ipsec site-to-site peer peer_51-105-0-5 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-5 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-5 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-5 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-5 remote-address '51.105.0.5' +set vpn ipsec site-to-site peer peer_51-105-0-5 vti bind 'vti42' +set vpn ipsec site-to-site peer peer_51-105-0-5 vti esp-group 'ESP-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-6 authentication mode 'pre-shared-secret' +set vpn ipsec site-to-site peer peer_51-105-0-6 authentication remote-id '51.105.0.6' +set vpn ipsec site-to-site peer peer_51-105-0-6 connection-type 'respond' +set vpn ipsec site-to-site peer peer_51-105-0-6 ike-group 'IKE-AZURE' +set vpn ipsec site-to-site peer peer_51-105-0-6 ikev2-reauth 'inherit' +set vpn ipsec site-to-site peer peer_51-105-0-6 local-address '192.0.2.189' +set vpn ipsec site-to-site peer peer_51-105-0-6 remote-address '51.105.0.6' +set vpn ipsec site-to-site peer peer_51-105-0-6 vti bind 'vti41' +set vpn ipsec site-to-site peer peer_51-105-0-6 vti esp-group 'ESP-AZURE' diff --git a/smoketest/config-tests/bgp-bfd-communities b/smoketest/config-tests/bgp-bfd-communities new file mode 100644 index 000000000..6eee0137e --- /dev/null +++ b/smoketest/config-tests/bgp-bfd-communities @@ -0,0 +1,201 @@ +set interfaces ethernet eth0 address '192.0.2.100/25' +set interfaces ethernet eth0 address '2001:db8::ffff/64' +set interfaces ethernet eth0 offload gro +set interfaces loopback lo +set policy large-community-list ANYCAST_ALL rule 10 action 'permit' +set policy large-community-list ANYCAST_ALL rule 10 description 'Allow all anycast from anywhere' +set policy large-community-list ANYCAST_ALL rule 10 regex '4242420696:100:.*' +set policy large-community-list ANYCAST_INT rule 10 action 'permit' +set policy large-community-list ANYCAST_INT rule 10 description 'Allow all anycast from int' +set policy large-community-list ANYCAST_INT rule 10 regex '4242420696:100:1' +set policy prefix-list BGP-BACKBONE-IN description 'Inbound backbone routes from other sites' +set policy prefix-list BGP-BACKBONE-IN rule 10 action 'deny' +set policy prefix-list BGP-BACKBONE-IN rule 10 description 'Block default route' +set policy prefix-list BGP-BACKBONE-IN rule 10 prefix '0.0.0.0/0' +set policy prefix-list BGP-BACKBONE-IN rule 20 action 'deny' +set policy prefix-list BGP-BACKBONE-IN rule 20 description 'Block int primary' +set policy prefix-list BGP-BACKBONE-IN rule 20 ge '21' +set policy prefix-list BGP-BACKBONE-IN rule 20 prefix '192.168.0.0/20' +set policy prefix-list BGP-BACKBONE-IN rule 30 action 'deny' +set policy prefix-list BGP-BACKBONE-IN rule 30 description 'Block loopbacks' +set policy prefix-list BGP-BACKBONE-IN rule 30 ge '25' +set policy prefix-list BGP-BACKBONE-IN rule 30 prefix '192.168.253.0/24' +set policy prefix-list BGP-BACKBONE-IN rule 40 action 'deny' +set policy prefix-list BGP-BACKBONE-IN rule 40 description 'Block backbone peering' +set policy prefix-list BGP-BACKBONE-IN rule 40 ge '25' +set policy prefix-list BGP-BACKBONE-IN rule 40 prefix '192.168.254.0/24' +set policy prefix-list BGP-BACKBONE-IN rule 999 action 'permit' +set policy prefix-list BGP-BACKBONE-IN rule 999 description 'Allow everything else' +set policy prefix-list BGP-BACKBONE-IN rule 999 ge '1' +set policy prefix-list BGP-BACKBONE-IN rule 999 prefix '0.0.0.0/0' +set policy prefix-list BGP-BACKBONE-OUT description 'Outbound backbone routes to other sites' +set policy prefix-list BGP-BACKBONE-OUT rule 10 action 'permit' +set policy prefix-list BGP-BACKBONE-OUT rule 10 description 'Int primary' +set policy prefix-list BGP-BACKBONE-OUT rule 10 ge '23' +set policy prefix-list BGP-BACKBONE-OUT rule 10 prefix '192.168.0.0/20' +set policy prefix-list GLOBAL description 'Globally redistributed routes' +set policy prefix-list GLOBAL rule 10 action 'permit' +set policy prefix-list GLOBAL rule 10 prefix '192.168.100.1/32' +set policy prefix-list GLOBAL rule 20 action 'permit' +set policy prefix-list GLOBAL rule 20 prefix '192.168.7.128/25' +set policy prefix-list6 BGP-BACKBONE-IN-V6 description 'Inbound backbone routes from other sites' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 action 'deny' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 description 'Block default route' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 10 prefix '::/0' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 action 'deny' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 description 'Block int primary' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 ge '53' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 20 prefix 'fd52:d62e:8011::/52' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 action 'deny' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 description 'Block peering and stuff' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 ge '53' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 30 prefix 'fd52:d62e:8011:f000::/52' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 action 'permit' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 description 'Allow everything else' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 ge '1' +set policy prefix-list6 BGP-BACKBONE-IN-V6 rule 999 prefix '::/0' +set policy prefix-list6 BGP-BACKBONE-OUT-V6 description 'Outbound backbone routes to other sites' +set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 action 'permit' +set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 ge '64' +set policy prefix-list6 BGP-BACKBONE-OUT-V6 rule 10 prefix 'fd52:d62e:8011::/52' +set policy prefix-list6 GLOBAL-V6 description 'Globally redistributed routes' +set policy prefix-list6 GLOBAL-V6 rule 10 action 'permit' +set policy prefix-list6 GLOBAL-V6 rule 10 ge '64' +set policy prefix-list6 GLOBAL-V6 rule 10 prefix 'fd52:d62e:8011:2::/63' +set policy route-map BGP-BACKBONE-IN rule 10 action 'permit' +set policy route-map BGP-BACKBONE-IN rule 10 match ip address prefix-list 'BGP-BACKBONE-IN' +set policy route-map BGP-BACKBONE-IN rule 20 action 'permit' +set policy route-map BGP-BACKBONE-IN rule 20 match ipv6 address prefix-list 'BGP-BACKBONE-IN-V6' +set policy route-map BGP-BACKBONE-IN rule 30 action 'permit' +set policy route-map BGP-BACKBONE-IN rule 30 match large-community large-community-list 'ANYCAST_ALL' +set policy route-map BGP-BACKBONE-OUT rule 10 action 'permit' +set policy route-map BGP-BACKBONE-OUT rule 10 match ip address prefix-list 'BGP-BACKBONE-OUT' +set policy route-map BGP-BACKBONE-OUT rule 20 action 'permit' +set policy route-map BGP-BACKBONE-OUT rule 20 match ipv6 address prefix-list 'BGP-BACKBONE-OUT-V6' +set policy route-map BGP-BACKBONE-OUT rule 30 action 'permit' +set policy route-map BGP-BACKBONE-OUT rule 30 match large-community large-community-list 'ANYCAST_INT' +set policy route-map BGP-BACKBONE-OUT rule 30 set as-path prepend '4242420666' +set policy route-map BGP-REDISTRIBUTE rule 10 action 'permit' +set policy route-map BGP-REDISTRIBUTE rule 10 description 'Prepend AS and allow VPN and modem' +set policy route-map BGP-REDISTRIBUTE rule 10 match ip address prefix-list 'GLOBAL' +set policy route-map BGP-REDISTRIBUTE rule 10 set as-path prepend '4242420666' +set policy route-map BGP-REDISTRIBUTE rule 20 action 'permit' +set policy route-map BGP-REDISTRIBUTE rule 20 description 'Allow VPN' +set policy route-map BGP-REDISTRIBUTE rule 20 match ipv6 address prefix-list 'GLOBAL-V6' +set protocols bfd peer 192.168.253.1 interval receive '50' +set protocols bfd peer 192.168.253.1 interval transmit '50' +set protocols bfd peer 192.168.253.1 multihop +set protocols bfd peer 192.168.253.1 source address '192.168.253.3' +set protocols bfd peer 192.168.253.2 interval receive '50' +set protocols bfd peer 192.168.253.2 interval transmit '50' +set protocols bfd peer 192.168.253.2 multihop +set protocols bfd peer 192.168.253.2 source address '192.168.253.3' +set protocols bfd peer 192.168.253.6 interval receive '50' +set protocols bfd peer 192.168.253.6 interval transmit '50' +set protocols bfd peer 192.168.253.6 multihop +set protocols bfd peer 192.168.253.6 source address '192.168.253.3' +set protocols bfd peer 192.168.253.7 interval receive '50' +set protocols bfd peer 192.168.253.7 interval transmit '50' +set protocols bfd peer 192.168.253.7 multihop +set protocols bfd peer 192.168.253.7 source address '192.168.253.3' +set protocols bfd peer 192.168.253.12 interval receive '100' +set protocols bfd peer 192.168.253.12 interval transmit '100' +set protocols bfd peer 192.168.253.12 multihop +set protocols bfd peer 192.168.253.12 source address '192.168.253.3' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 interval receive '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 interval transmit '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 multihop +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:1 source address 'fd52:d62e:8011:fffe:192:168:253:3' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 interval receive '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 interval transmit '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 multihop +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:2 source address 'fd52:d62e:8011:fffe:192:168:253:3' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 interval receive '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 interval transmit '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 multihop +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:6 source address 'fd52:d62e:8011:fffe:192:168:253:3' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 interval receive '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 interval transmit '50' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 multihop +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:7 source address 'fd52:d62e:8011:fffe:192:168:253:3' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 interval receive '100' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 interval transmit '100' +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 multihop +set protocols bfd peer fd52:d62e:8011:fffe:192:168:253:12 source address 'fd52:d62e:8011:fffe:192:168:253:3' +set protocols bgp address-family ipv4-unicast redistribute connected route-map 'BGP-REDISTRIBUTE' +set protocols bgp address-family ipv4-unicast redistribute static route-map 'BGP-REDISTRIBUTE' +set protocols bgp address-family ipv6-unicast redistribute connected route-map 'BGP-REDISTRIBUTE' +set protocols bgp neighbor 192.168.253.1 peer-group 'INT' +set protocols bgp neighbor 192.168.253.2 peer-group 'INT' +set protocols bgp neighbor 192.168.253.6 peer-group 'DAL13' +set protocols bgp neighbor 192.168.253.7 peer-group 'DAL13' +set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast route-map export 'BGP-BACKBONE-OUT' +set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast route-map import 'BGP-BACKBONE-IN' +set protocols bgp neighbor 192.168.253.12 address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp neighbor 192.168.253.12 bfd +set protocols bgp neighbor 192.168.253.12 ebgp-multihop '2' +set protocols bgp neighbor 192.168.253.12 remote-as '4242420669' +set protocols bgp neighbor 192.168.253.12 update-source 'dum0' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:1 peer-group 'INTv6' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:2 peer-group 'INTv6' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:6 peer-group 'DAL13v6' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:7 peer-group 'DAL13v6' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast route-map export 'BGP-BACKBONE-OUT' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast route-map import 'BGP-BACKBONE-IN' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 address-family ipv6-unicast soft-reconfiguration inbound +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 bfd +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 ebgp-multihop '2' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 remote-as '4242420669' +set protocols bgp neighbor fd52:d62e:8011:fffe:192:168:253:12 update-source 'dum0' +set protocols bgp parameters confederation identifier '4242420696' +set protocols bgp parameters confederation peers '4242420668' +set protocols bgp parameters confederation peers '4242420669' +set protocols bgp parameters distance global external '220' +set protocols bgp parameters distance global internal '220' +set protocols bgp parameters distance global local '220' +set protocols bgp parameters graceful-restart +set protocols bgp peer-group DAL13 address-family ipv4-unicast route-map export 'BGP-BACKBONE-OUT' +set protocols bgp peer-group DAL13 address-family ipv4-unicast route-map import 'BGP-BACKBONE-IN' +set protocols bgp peer-group DAL13 address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp peer-group DAL13 bfd +set protocols bgp peer-group DAL13 ebgp-multihop '2' +set protocols bgp peer-group DAL13 remote-as '4242420668' +set protocols bgp peer-group DAL13 update-source 'dum0' +set protocols bgp peer-group DAL13v6 address-family ipv6-unicast route-map export 'BGP-BACKBONE-OUT' +set protocols bgp peer-group DAL13v6 address-family ipv6-unicast route-map import 'BGP-BACKBONE-IN' +set protocols bgp peer-group DAL13v6 address-family ipv6-unicast soft-reconfiguration inbound +set protocols bgp peer-group DAL13v6 bfd +set protocols bgp peer-group DAL13v6 ebgp-multihop '2' +set protocols bgp peer-group DAL13v6 remote-as '4242420668' +set protocols bgp peer-group DAL13v6 update-source 'dum0' +set protocols bgp peer-group INT address-family ipv4-unicast default-originate +set protocols bgp peer-group INT address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp peer-group INT bfd +set protocols bgp peer-group INT remote-as '4242420666' +set protocols bgp peer-group INT update-source 'dum0' +set protocols bgp peer-group INTv6 address-family ipv6-unicast default-originate +set protocols bgp peer-group INTv6 address-family ipv6-unicast soft-reconfiguration inbound +set protocols bgp peer-group INTv6 bfd +set protocols bgp peer-group INTv6 remote-as '4242420666' +set protocols bgp peer-group INTv6 update-source 'dum0' +set protocols bgp system-as '4242420666' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/bgp-big-as-cloud b/smoketest/config-tests/bgp-big-as-cloud new file mode 100644 index 000000000..8de0cdb02 --- /dev/null +++ b/smoketest/config-tests/bgp-big-as-cloud @@ -0,0 +1,850 @@ +set firewall global-options all-ping 'enable' +set firewall global-options broadcast-ping 'disable' +set firewall global-options ip-src-route 'disable' +set firewall global-options ipv6-receive-redirects 'disable' +set firewall global-options ipv6-src-route 'disable' +set firewall global-options log-martians 'enable' +set firewall global-options receive-redirects 'disable' +set firewall global-options send-redirects 'enable' +set firewall global-options source-validation 'disable' +set firewall global-options syn-cookies 'enable' +set firewall global-options twa-hazards-protection 'disable' +set firewall group address-group bgp-peers-4 address '192.0.68.3' +set firewall group address-group bgp-peers-4 address '192.0.68.2' +set firewall group address-group bgp-peers-4 address '192.0.176.193' +set firewall group address-group bgp-peers-4 address '192.0.52.0-192.0.52.255' +set firewall group address-group bgp-peers-4 address '192.0.53.0-192.0.53.255' +set firewall group address-group bgp-peers-4 address '192.0.16.209' +set firewall group address-group bgp-peers-4 address '192.0.192.0-192.0.192.255' +set firewall group address-group bgp-peers-4 address '192.0.193.0-192.0.193.255' +set firewall group address-group bgp-peers-4 address '192.0.194.0-192.0.194.255' +set firewall group address-group bgp-peers-4 address '192.0.195.0-192.0.195.255' +set firewall group address-group bgp-peers-4 address '192.0.196.0-192.0.196.255' +set firewall group address-group bgp-peers-4 address '192.0.197.0-192.0.197.255' +set firewall group address-group bgp-peers-4 address '192.0.198.0-192.0.198.255' +set firewall group address-group bgp-peers-4 address '192.0.199.0-192.0.199.255' +set firewall group address-group vrrp-peers-4 address '192.0.68.3' +set firewall group address-group vrrp-peers-4 address '192.0.160.3' +set firewall group address-group vrrp-peers-4 address '192.0.98.3' +set firewall group address-group vrrp-peers-4 address '192.0.71.131' +set firewall group address-group vrrp-peers-4 address '192.0.84.67' +set firewall group address-group vrrp-peers-4 address '192.0.71.195' +set firewall group address-group vrrp-peers-4 address '192.0.71.115' +set firewall group address-group vrrp-peers-4 address '192.0.70.195' +set firewall group address-group vrrp-peers-4 address '192.0.70.179' +set firewall group address-group vrrp-peers-4 address '192.0.70.163' +set firewall group address-group vrrp-peers-4 address '192.0.70.147' +set firewall group address-group vrrp-peers-4 address '192.0.70.131' +set firewall group address-group vrrp-peers-4 address '192.0.70.19' +set firewall group address-group vrrp-peers-4 address '192.0.70.3' +set firewall group address-group vrrp-peers-4 address '192.0.71.99' +set firewall group address-group vrrp-peers-4 address '192.0.68.67' +set firewall group address-group vrrp-peers-4 address '192.0.71.67' +set firewall group address-group vrrp-peers-4 address '192.0.71.3' +set firewall group address-group vrrp-peers-4 address '192.0.68.35' +set firewall group address-group vrrp-peers-4 address '192.0.68.131' +set firewall group address-group vrrp-peers-4 address '192.0.69.2' +set firewall group address-group vrrp-peers-4 address '192.0.70.35' +set firewall group address-group vrrp-peers-4 address '192.0.70.67' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:c::3' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:1000::2e9' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fb' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fc' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::fd' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::2e' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::3d' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::4a' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::5e' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::7' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::11' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::18' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::20' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::22' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::31' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::58' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::64' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::a5' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::aa' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::ab' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::b0' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::b3' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::bd' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::c' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::d2' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:24::d3' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8:838::1' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::1a27:5051:c09d' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::1a27:5051:c19d' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::20ad:0:1' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2306:0:1' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:1' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:2' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:3' +set firewall group ipv6-address-group bgp-peers-6 address '2001:db8::2ca:0:4' +set firewall group ipv6-address-group vrrp-peers-6 address 'fe80::fe89:15cf' +set firewall group ipv6-network-group AS64512-6 network '2001::/29' +set firewall group network-group AS64512-4 network '192.0.68.0/22' +set firewall group network-group AS64512-4 network '192.0.98.0/24' +set firewall group network-group AS64512-4 network '192.0.160.0/24' +set firewall group network-group AS64512-4 network '192.0.84.0/22' +set firewall ipv4 name management-to-local-4 default-action 'reject' +set firewall ipv4 name management-to-local-4 default-log +set firewall ipv4 name management-to-local-4 rule 500 action 'return' +set firewall ipv4 name management-to-local-4 rule 500 protocol 'icmp' +set firewall ipv4 name management-to-local-4 rule 501 action 'return' +set firewall ipv4 name management-to-local-4 rule 501 destination port '22' +set firewall ipv4 name management-to-local-4 rule 501 protocol 'tcp' +set firewall ipv4 name management-to-local-4 rule 502 action 'return' +set firewall ipv4 name management-to-local-4 rule 502 destination port 'snmp' +set firewall ipv4 name management-to-local-4 rule 502 protocol 'udp' +set firewall ipv4 name management-to-peers-4 default-action 'reject' +set firewall ipv4 name management-to-peers-4 default-log +set firewall ipv4 name management-to-servers-4 default-action 'reject' +set firewall ipv4 name management-to-servers-4 default-log +set firewall ipv4 name peers-to-local-4 default-action 'reject' +set firewall ipv4 name peers-to-local-4 default-log +set firewall ipv4 name peers-to-local-4 rule 500 action 'return' +set firewall ipv4 name peers-to-local-4 rule 500 protocol 'icmp' +set firewall ipv4 name peers-to-local-4 rule 501 action 'return' +set firewall ipv4 name peers-to-local-4 rule 501 protocol 'vrrp' +set firewall ipv4 name peers-to-local-4 rule 501 source group address-group 'vrrp-peers-4' +set firewall ipv4 name peers-to-local-4 rule 502 action 'return' +set firewall ipv4 name peers-to-local-4 rule 502 destination port 'bgp' +set firewall ipv4 name peers-to-local-4 rule 502 protocol 'tcp' +set firewall ipv4 name peers-to-local-4 rule 502 source group address-group 'bgp-peers-4' +set firewall ipv4 name peers-to-local-4 rule 503 action 'return' +set firewall ipv4 name peers-to-local-4 rule 503 protocol 'tcp' +set firewall ipv4 name peers-to-local-4 rule 503 source group address-group 'bgp-peers-4' +set firewall ipv4 name peers-to-local-4 rule 503 source port 'bgp' +set firewall ipv4 name peers-to-management-4 default-action 'reject' +set firewall ipv4 name peers-to-management-4 default-log +set firewall ipv4 name peers-to-servers-4 default-action 'reject' +set firewall ipv4 name peers-to-servers-4 default-log +set firewall ipv4 name peers-to-servers-4 rule 9990 action 'reject' +set firewall ipv4 name peers-to-servers-4 rule 9990 source group network-group 'AS64512-4' +set firewall ipv4 name peers-to-servers-4 rule 9999 action 'return' +set firewall ipv4 name peers-to-servers-4 rule 9999 destination group network-group 'AS64512-4' +set firewall ipv4 name servers-to-local-4 default-action 'reject' +set firewall ipv4 name servers-to-local-4 default-log +set firewall ipv4 name servers-to-local-4 rule 500 action 'return' +set firewall ipv4 name servers-to-local-4 rule 500 protocol 'icmp' +set firewall ipv4 name servers-to-local-4 rule 501 action 'return' +set firewall ipv4 name servers-to-local-4 rule 501 protocol 'vrrp' +set firewall ipv4 name servers-to-local-4 rule 501 source group address-group 'vrrp-peers-4' +set firewall ipv4 name servers-to-local-4 rule 511 action 'return' +set firewall ipv4 name servers-to-local-4 rule 511 protocol 'tcp_udp' +set firewall ipv4 name servers-to-local-4 rule 511 source port '53' +set firewall ipv4 name servers-to-management-4 default-action 'reject' +set firewall ipv4 name servers-to-management-4 default-log +set firewall ipv4 name servers-to-peers-4 default-action 'reject' +set firewall ipv4 name servers-to-peers-4 default-log +set firewall ipv4 name servers-to-peers-4 rule 51 action 'return' +set firewall ipv4 name servers-to-peers-4 rule 51 source group network-group 'AS64512-4' +set firewall ipv6 name management-to-local-6 default-action 'reject' +set firewall ipv6 name management-to-local-6 default-log +set firewall ipv6 name management-to-peers-6 default-action 'reject' +set firewall ipv6 name management-to-peers-6 default-log +set firewall ipv6 name management-to-servers-6 default-action 'reject' +set firewall ipv6 name management-to-servers-6 default-log +set firewall ipv6 name peers-to-local-6 default-action 'reject' +set firewall ipv6 name peers-to-local-6 default-log +set firewall ipv6 name peers-to-local-6 rule 500 action 'return' +set firewall ipv6 name peers-to-local-6 rule 500 protocol 'ipv6-icmp' +set firewall ipv6 name peers-to-local-6 rule 501 action 'return' +set firewall ipv6 name peers-to-local-6 rule 501 protocol 'vrrp' +set firewall ipv6 name peers-to-local-6 rule 501 source group address-group 'vrrp-peers-6' +set firewall ipv6 name peers-to-local-6 rule 502 action 'return' +set firewall ipv6 name peers-to-local-6 rule 502 destination port 'bgp' +set firewall ipv6 name peers-to-local-6 rule 502 protocol 'tcp' +set firewall ipv6 name peers-to-local-6 rule 502 source group address-group 'bgp-peers-6' +set firewall ipv6 name peers-to-local-6 rule 503 action 'return' +set firewall ipv6 name peers-to-local-6 rule 503 protocol 'tcp' +set firewall ipv6 name peers-to-local-6 rule 503 source group address-group 'bgp-peers-6' +set firewall ipv6 name peers-to-local-6 rule 503 source port 'bgp' +set firewall ipv6 name peers-to-management-6 default-action 'reject' +set firewall ipv6 name peers-to-management-6 default-log +set firewall ipv6 name peers-to-servers-6 default-action 'reject' +set firewall ipv6 name peers-to-servers-6 default-log +set firewall ipv6 name peers-to-servers-6 rule 9990 action 'reject' +set firewall ipv6 name peers-to-servers-6 rule 9990 source group network-group 'AS64512-6' +set firewall ipv6 name peers-to-servers-6 rule 9999 action 'return' +set firewall ipv6 name peers-to-servers-6 rule 9999 destination group network-group 'AS64512-6' +set firewall ipv6 name servers-to-local-6 default-action 'reject' +set firewall ipv6 name servers-to-local-6 default-log +set firewall ipv6 name servers-to-local-6 rule 500 action 'return' +set firewall ipv6 name servers-to-local-6 rule 500 protocol 'ipv6-icmp' +set firewall ipv6 name servers-to-local-6 rule 501 action 'return' +set firewall ipv6 name servers-to-local-6 rule 501 protocol 'vrrp' +set firewall ipv6 name servers-to-local-6 rule 501 source group address-group 'vrrp-peers-6' +set firewall ipv6 name servers-to-local-6 rule 511 action 'return' +set firewall ipv6 name servers-to-local-6 rule 511 protocol 'tcp_udp' +set firewall ipv6 name servers-to-local-6 rule 511 source port '53' +set firewall ipv6 name servers-to-management-6 default-action 'reject' +set firewall ipv6 name servers-to-management-6 default-log +set firewall ipv6 name servers-to-peers-6 default-action 'reject' +set firewall ipv6 name servers-to-peers-6 default-log +set firewall ipv6 name servers-to-peers-6 rule 51 action 'return' +set firewall ipv6 name servers-to-peers-6 rule 51 source group network-group 'AS64512-6' +set firewall zone local default-action 'drop' +set firewall zone local from management firewall ipv6-name 'management-to-local-6' +set firewall zone local from management firewall name 'management-to-local-4' +set firewall zone local from peers firewall ipv6-name 'peers-to-local-6' +set firewall zone local from peers firewall name 'peers-to-local-4' +set firewall zone local from servers firewall ipv6-name 'servers-to-local-6' +set firewall zone local from servers firewall name 'servers-to-local-4' +set firewall zone local local-zone +set firewall zone management default-action 'reject' +set firewall zone management from peers firewall ipv6-name 'peers-to-management-6' +set firewall zone management from peers firewall name 'peers-to-management-4' +set firewall zone management from servers firewall ipv6-name 'servers-to-management-6' +set firewall zone management from servers firewall name 'servers-to-management-4' +set firewall zone management interface 'eth0' +set firewall zone peers default-action 'reject' +set firewall zone peers from management firewall ipv6-name 'management-to-peers-6' +set firewall zone peers from management firewall name 'management-to-peers-4' +set firewall zone peers from servers firewall ipv6-name 'servers-to-peers-6' +set firewall zone peers from servers firewall name 'servers-to-peers-4' +set firewall zone peers interface 'eth0.4088' +set firewall zone peers interface 'eth0.4089' +set firewall zone peers interface 'eth0.11' +set firewall zone peers interface 'eth0.838' +set firewall zone peers interface 'eth0.886' +set firewall zone servers default-action 'reject' +set firewall zone servers from management firewall ipv6-name 'management-to-servers-6' +set firewall zone servers from management firewall name 'management-to-servers-4' +set firewall zone servers from peers firewall ipv6-name 'peers-to-servers-6' +set firewall zone servers from peers firewall name 'peers-to-servers-4' +set firewall zone servers interface 'eth0.1001' +set firewall zone servers interface 'eth0.105' +set firewall zone servers interface 'eth0.102' +set firewall zone servers interface 'eth0.1019' +set firewall zone servers interface 'eth0.1014' +set firewall zone servers interface 'eth0.1020' +set firewall zone servers interface 'eth0.1018' +set firewall zone servers interface 'eth0.1013' +set firewall zone servers interface 'eth0.1012' +set firewall zone servers interface 'eth0.1011' +set firewall zone servers interface 'eth0.1010' +set firewall zone servers interface 'eth0.1009' +set firewall zone servers interface 'eth0.1006' +set firewall zone servers interface 'eth0.1005' +set firewall zone servers interface 'eth0.1017' +set firewall zone servers interface 'eth0.1016' +set firewall zone servers interface 'eth0.1002' +set firewall zone servers interface 'eth0.1015' +set firewall zone servers interface 'eth0.1003' +set firewall zone servers interface 'eth0.1004' +set firewall zone servers interface 'eth0.1007' +set firewall zone servers interface 'eth0.1008' +set high-availability vrrp group 11-4 address 192.0.68.1/27 +set high-availability vrrp group 11-4 interface 'eth0.11' +set high-availability vrrp group 11-4 priority '200' +set high-availability vrrp group 11-4 vrid '4' +set high-availability vrrp group 11-6 address 2001:db8:c::1/64 +set high-availability vrrp group 11-6 interface 'eth0.11' +set high-availability vrrp group 11-6 priority '200' +set high-availability vrrp group 11-6 vrid '6' +set high-availability vrrp group 102-4 address 192.0.98.1/24 +set high-availability vrrp group 102-4 interface 'eth0.102' +set high-availability vrrp group 102-4 priority '200' +set high-availability vrrp group 102-4 vrid '4' +set high-availability vrrp group 102-6 address 2001:db8:0:102::1/64 +set high-availability vrrp group 102-6 interface 'eth0.102' +set high-availability vrrp group 102-6 priority '200' +set high-availability vrrp group 102-6 vrid '6' +set high-availability vrrp group 105-4 address 192.0.160.1/24 +set high-availability vrrp group 105-4 interface 'eth0.105' +set high-availability vrrp group 105-4 priority '200' +set high-availability vrrp group 105-4 vrid '4' +set high-availability vrrp group 105-6 address 2001:db8:0:105::1/64 +set high-availability vrrp group 105-6 interface 'eth0.105' +set high-availability vrrp group 105-6 priority '200' +set high-availability vrrp group 105-6 vrid '6' +set high-availability vrrp group 1001-4 address 192.0.68.33/27 +set high-availability vrrp group 1001-4 interface 'eth0.1001' +set high-availability vrrp group 1001-4 priority '200' +set high-availability vrrp group 1001-4 vrid '4' +set high-availability vrrp group 1001-6 address 2001:db8:0:1001::1/64 +set high-availability vrrp group 1001-6 interface 'eth0.1001' +set high-availability vrrp group 1001-6 priority '200' +set high-availability vrrp group 1001-6 vrid '6' +set high-availability vrrp group 1002-4 address 192.0.68.65/26 +set high-availability vrrp group 1002-4 interface 'eth0.1002' +set high-availability vrrp group 1002-4 priority '200' +set high-availability vrrp group 1002-4 vrid '4' +set high-availability vrrp group 1002-6 address 2001:db8:0:1002::1/64 +set high-availability vrrp group 1002-6 interface 'eth0.1002' +set high-availability vrrp group 1002-6 priority '200' +set high-availability vrrp group 1002-6 vrid '6' +set high-availability vrrp group 1003-4 address 192.0.68.129/25 +set high-availability vrrp group 1003-4 interface 'eth0.1003' +set high-availability vrrp group 1003-4 priority '200' +set high-availability vrrp group 1003-4 vrid '4' +set high-availability vrrp group 1003-6 address 2001:db8:0:1003::1/64 +set high-availability vrrp group 1003-6 interface 'eth0.1003' +set high-availability vrrp group 1003-6 priority '200' +set high-availability vrrp group 1003-6 vrid '6' +set high-availability vrrp group 1004-4 address 192.0.69.1/24 +set high-availability vrrp group 1004-4 interface 'eth0.1004' +set high-availability vrrp group 1004-4 priority '200' +set high-availability vrrp group 1004-4 vrid '4' +set high-availability vrrp group 1004-6 address 2001:db8:0:1004::1/64 +set high-availability vrrp group 1004-6 interface 'eth0.1004' +set high-availability vrrp group 1004-6 priority '200' +set high-availability vrrp group 1004-6 vrid '6' +set high-availability vrrp group 1005-4 address 192.0.70.1/28 +set high-availability vrrp group 1005-4 interface 'eth0.1005' +set high-availability vrrp group 1005-4 priority '200' +set high-availability vrrp group 1005-4 vrid '4' +set high-availability vrrp group 1005-6 address 2001:db8:0:1005::1/64 +set high-availability vrrp group 1005-6 interface 'eth0.1005' +set high-availability vrrp group 1005-6 priority '200' +set high-availability vrrp group 1005-6 vrid '6' +set high-availability vrrp group 1006-4 address 192.0.70.17/28 +set high-availability vrrp group 1006-4 interface 'eth0.1006' +set high-availability vrrp group 1006-4 priority '200' +set high-availability vrrp group 1006-4 vrid '4' +set high-availability vrrp group 1006-6 address 2001:db8:0:1006::1/64 +set high-availability vrrp group 1006-6 interface 'eth0.1006' +set high-availability vrrp group 1006-6 priority '200' +set high-availability vrrp group 1006-6 vrid '6' +set high-availability vrrp group 1007-4 address 192.0.70.33/27 +set high-availability vrrp group 1007-4 interface 'eth0.1007' +set high-availability vrrp group 1007-4 priority '200' +set high-availability vrrp group 1007-4 vrid '4' +set high-availability vrrp group 1007-6 address 2001:db8:0:1007::1/64 +set high-availability vrrp group 1007-6 interface 'eth0.1007' +set high-availability vrrp group 1007-6 priority '200' +set high-availability vrrp group 1007-6 vrid '6' +set high-availability vrrp group 1008-4 address 192.0.70.65/26 +set high-availability vrrp group 1008-4 interface 'eth0.1008' +set high-availability vrrp group 1008-4 priority '200' +set high-availability vrrp group 1008-4 vrid '4' +set high-availability vrrp group 1008-6 address 2001:db8:0:1008::1/64 +set high-availability vrrp group 1008-6 interface 'eth0.1008' +set high-availability vrrp group 1008-6 priority '200' +set high-availability vrrp group 1008-6 vrid '6' +set high-availability vrrp group 1009-4 address 192.0.70.129/28 +set high-availability vrrp group 1009-4 interface 'eth0.1009' +set high-availability vrrp group 1009-4 priority '200' +set high-availability vrrp group 1009-4 vrid '4' +set high-availability vrrp group 1009-6 address 2001:db8:0:1009::1/64 +set high-availability vrrp group 1009-6 interface 'eth0.1009' +set high-availability vrrp group 1009-6 priority '200' +set high-availability vrrp group 1009-6 vrid '6' +set high-availability vrrp group 1010-4 address 192.0.70.145/28 +set high-availability vrrp group 1010-4 interface 'eth0.1010' +set high-availability vrrp group 1010-4 priority '200' +set high-availability vrrp group 1010-4 vrid '4' +set high-availability vrrp group 1010-6 address 2001:db8:0:1010::1/64 +set high-availability vrrp group 1010-6 interface 'eth0.1010' +set high-availability vrrp group 1010-6 priority '200' +set high-availability vrrp group 1010-6 vrid '6' +set high-availability vrrp group 1011-4 address 192.0.70.161/28 +set high-availability vrrp group 1011-4 interface 'eth0.1011' +set high-availability vrrp group 1011-4 priority '200' +set high-availability vrrp group 1011-4 vrid '4' +set high-availability vrrp group 1011-6 address 2001:db8:0:1011::1/64 +set high-availability vrrp group 1011-6 interface 'eth0.1011' +set high-availability vrrp group 1011-6 priority '200' +set high-availability vrrp group 1011-6 vrid '6' +set high-availability vrrp group 1012-4 address 192.0.70.177/28 +set high-availability vrrp group 1012-4 interface 'eth0.1012' +set high-availability vrrp group 1012-4 priority '200' +set high-availability vrrp group 1012-4 vrid '4' +set high-availability vrrp group 1012-6 address 2001:db8:0:1012::1/64 +set high-availability vrrp group 1012-6 interface 'eth0.1012' +set high-availability vrrp group 1012-6 priority '200' +set high-availability vrrp group 1012-6 vrid '6' +set high-availability vrrp group 1013-4 address 192.0.70.193/27 +set high-availability vrrp group 1013-4 interface 'eth0.1013' +set high-availability vrrp group 1013-4 priority '200' +set high-availability vrrp group 1013-4 vrid '4' +set high-availability vrrp group 1013-6 address 2001:db8:0:1013::1/64 +set high-availability vrrp group 1013-6 interface 'eth0.1013' +set high-availability vrrp group 1013-6 priority '200' +set high-availability vrrp group 1013-6 vrid '6' +set high-availability vrrp group 1014-4 address 192.0.84.65/26 +set high-availability vrrp group 1014-4 interface 'eth0.1014' +set high-availability vrrp group 1014-4 priority '200' +set high-availability vrrp group 1014-4 vrid '4' +set high-availability vrrp group 1014-6 address 2001:db8:0:1014::1/64 +set high-availability vrrp group 1014-6 interface 'eth0.1014' +set high-availability vrrp group 1014-6 priority '200' +set high-availability vrrp group 1014-6 vrid '6' +set high-availability vrrp group 1015-4 address 192.0.71.1/26 +set high-availability vrrp group 1015-4 interface 'eth0.1015' +set high-availability vrrp group 1015-4 priority '200' +set high-availability vrrp group 1015-4 vrid '4' +set high-availability vrrp group 1015-6 address 2001:db8:0:1015::1/64 +set high-availability vrrp group 1015-6 interface 'eth0.1015' +set high-availability vrrp group 1015-6 priority '200' +set high-availability vrrp group 1015-6 vrid '6' +set high-availability vrrp group 1016-4 address 192.0.71.65/27 +set high-availability vrrp group 1016-4 interface 'eth0.1016' +set high-availability vrrp group 1016-4 priority '200' +set high-availability vrrp group 1016-4 vrid '4' +set high-availability vrrp group 1016-6 address 2001:db8:0:1016::1/64 +set high-availability vrrp group 1016-6 interface 'eth0.1016' +set high-availability vrrp group 1016-6 priority '200' +set high-availability vrrp group 1016-6 vrid '6' +set high-availability vrrp group 1017-4 address 192.0.71.97/28 +set high-availability vrrp group 1017-4 interface 'eth0.1017' +set high-availability vrrp group 1017-4 priority '200' +set high-availability vrrp group 1017-4 vrid '4' +set high-availability vrrp group 1017-6 address 2001:db8:0:1017::1/64 +set high-availability vrrp group 1017-6 interface 'eth0.1017' +set high-availability vrrp group 1017-6 priority '200' +set high-availability vrrp group 1017-6 vrid '6' +set high-availability vrrp group 1018-4 address 192.0.71.113/28 +set high-availability vrrp group 1018-4 interface 'eth0.1018' +set high-availability vrrp group 1018-4 priority '200' +set high-availability vrrp group 1018-4 vrid '4' +set high-availability vrrp group 1018-6 address 2001:db8:0:1018::1/64 +set high-availability vrrp group 1018-6 interface 'eth0.1018' +set high-availability vrrp group 1018-6 priority '200' +set high-availability vrrp group 1018-6 vrid '6' +set high-availability vrrp group 1019-4 address 192.0.71.129/26 +set high-availability vrrp group 1019-4 interface 'eth0.1019' +set high-availability vrrp group 1019-4 priority '200' +set high-availability vrrp group 1019-4 vrid '4' +set high-availability vrrp group 1019-6 address 2001:db8:0:1019::1/64 +set high-availability vrrp group 1019-6 interface 'eth0.1019' +set high-availability vrrp group 1019-6 priority '200' +set high-availability vrrp group 1019-6 vrid '6' +set high-availability vrrp group 1020-4 address 192.0.71.193/26 +set high-availability vrrp group 1020-4 interface 'eth0.1020' +set high-availability vrrp group 1020-4 priority '200' +set high-availability vrrp group 1020-4 vrid '4' +set high-availability vrrp group 1020-6 address 2001:db8:0:1020::1/64 +set high-availability vrrp group 1020-6 interface 'eth0.1020' +set high-availability vrrp group 1020-6 priority '200' +set high-availability vrrp group 1020-6 vrid '6' +set interfaces ethernet eth0 address '192.0.0.11/16' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 vif 11 address '192.0.68.2/27' +set interfaces ethernet eth0 vif 11 address '2001:db8:c::2/64' +set interfaces ethernet eth0 vif 102 address '192.0.98.2/24' +set interfaces ethernet eth0 vif 102 address '2001:db8:0:102::2/64' +set interfaces ethernet eth0 vif 105 address '192.0.160.2/24' +set interfaces ethernet eth0 vif 105 address '2001:db8:0:105::2/64' +set interfaces ethernet eth0 vif 838 address '192.0.16.210/30' +set interfaces ethernet eth0 vif 838 address '2001:db8:838::2/64' +set interfaces ethernet eth0 vif 886 address '192.0.193.224/21' +set interfaces ethernet eth0 vif 886 address '2001:db8::3:669:0:1/64' +set interfaces ethernet eth0 vif 1001 address '192.0.68.34/27' +set interfaces ethernet eth0 vif 1001 address '2001:db8:0:1001::2/64' +set interfaces ethernet eth0 vif 1002 address '192.0.68.66/26' +set interfaces ethernet eth0 vif 1002 address '2001:db8:0:1002::2/64' +set interfaces ethernet eth0 vif 1003 address '192.0.68.130/25' +set interfaces ethernet eth0 vif 1003 address '2001:db8:0:1003::2/64' +set interfaces ethernet eth0 vif 1004 address '192.0.69.2/24' +set interfaces ethernet eth0 vif 1004 address '2001:db8:0:1004::2/64' +set interfaces ethernet eth0 vif 1005 address '192.0.70.2/28' +set interfaces ethernet eth0 vif 1005 address '2001:db8:0:1005::2/64' +set interfaces ethernet eth0 vif 1006 address '192.0.70.18/28' +set interfaces ethernet eth0 vif 1006 address '2001:db8:0:1006::2/64' +set interfaces ethernet eth0 vif 1007 address '192.0.70.34/27' +set interfaces ethernet eth0 vif 1007 address '2001:db8:0:1007::2/64' +set interfaces ethernet eth0 vif 1008 address '192.0.70.66/26' +set interfaces ethernet eth0 vif 1008 address '2001:db8:0:1008::2/64' +set interfaces ethernet eth0 vif 1009 address '192.0.70.130/28' +set interfaces ethernet eth0 vif 1009 address '2001:db8:0:1009::2/64' +set interfaces ethernet eth0 vif 1010 address '192.0.70.146/28' +set interfaces ethernet eth0 vif 1010 address '2001:db8:0:1010::2/64' +set interfaces ethernet eth0 vif 1011 address '192.0.70.162/28' +set interfaces ethernet eth0 vif 1011 address '2001:db8:0:1011::2/64' +set interfaces ethernet eth0 vif 1012 address '192.0.70.178/28' +set interfaces ethernet eth0 vif 1012 address '2001:db8:0:1012::2/64' +set interfaces ethernet eth0 vif 1013 address '192.0.70.194/27' +set interfaces ethernet eth0 vif 1013 address '2001:db8:0:1013::3/64' +set interfaces ethernet eth0 vif 1014 address '192.0.84.66/26' +set interfaces ethernet eth0 vif 1014 address '2001:db8:0:1014::2/64' +set interfaces ethernet eth0 vif 1015 address '192.0.71.2/26' +set interfaces ethernet eth0 vif 1015 address '2001:db8:0:1015::2/64' +set interfaces ethernet eth0 vif 1016 address '192.0.71.66/27' +set interfaces ethernet eth0 vif 1016 address '2001:db8:0:1016::2/64' +set interfaces ethernet eth0 vif 1017 address '192.0.71.98/28' +set interfaces ethernet eth0 vif 1017 address '2001:db8:0:1017::2/64' +set interfaces ethernet eth0 vif 1018 address '192.0.71.114/28' +set interfaces ethernet eth0 vif 1018 address '2001:db8:0:1018::2/64' +set interfaces ethernet eth0 vif 1019 address '192.0.71.130/26' +set interfaces ethernet eth0 vif 1019 address '2001:db8:0:1019::2/64' +set interfaces ethernet eth0 vif 1020 address '192.0.71.194/26' +set interfaces ethernet eth0 vif 1020 address '2001:db8:0:1020::2/64' +set interfaces ethernet eth0 vif 4088 address '2001:db8:24::c7/64' +set interfaces ethernet eth0 vif 4088 address '192.0.52.199/23' +set interfaces ethernet eth0 vif 4089 address '192.0.176.194/30' +set interfaces ethernet eth0 vif 4089 address '2001:db8:1000::2ea/126' +set interfaces loopback lo +set policy as-path-list AS64512 rule 10 action 'permit' +set policy as-path-list AS64512 rule 10 regex '^$' +set policy as-path-list AS64513-AS64514 rule 10 action 'permit' +set policy as-path-list AS64513-AS64514 rule 10 regex '^64513 64514$' +set policy prefix-list defaultV4 rule 10 action 'permit' +set policy prefix-list defaultV4 rule 10 prefix '0.0.0.0/0' +set policy prefix-list hostrouteV4 rule 10 action 'permit' +set policy prefix-list hostrouteV4 rule 10 ge '32' +set policy prefix-list hostrouteV4 rule 10 prefix '192.0.160.0/24' +set policy prefix-list hostrouteV4 rule 20 action 'permit' +set policy prefix-list hostrouteV4 rule 20 ge '32' +set policy prefix-list hostrouteV4 rule 20 prefix '192.0.98.0/24' +set policy prefix-list hostrouteV4 rule 30 action 'permit' +set policy prefix-list hostrouteV4 rule 30 ge '32' +set policy prefix-list hostrouteV4 rule 30 prefix '192.0.68.0/22' +set policy prefix-list hostrouteV4 rule 40 action 'permit' +set policy prefix-list hostrouteV4 rule 40 ge '32' +set policy prefix-list hostrouteV4 rule 40 prefix '192.0.84.0/22' +set policy prefix-list privateV4 rule 10 action 'permit' +set policy prefix-list privateV4 rule 10 le '32' +set policy prefix-list privateV4 rule 10 prefix '192.0.0.0/8' +set policy prefix-list privateV4 rule 20 action 'permit' +set policy prefix-list privateV4 rule 20 le '32' +set policy prefix-list privateV4 rule 20 prefix '192.0.0.0/12' +set policy prefix-list privateV4 rule 30 action 'permit' +set policy prefix-list privateV4 rule 30 le '32' +set policy prefix-list privateV4 rule 30 prefix '192.0.0.0/16' +set policy prefix-list vyosV4 rule 10 action 'permit' +set policy prefix-list vyosV4 rule 10 prefix '192.0.160.0/24' +set policy prefix-list vyosV4 rule 20 action 'permit' +set policy prefix-list vyosV4 rule 20 prefix '192.0.98.0/24' +set policy prefix-list vyosV4 rule 30 action 'permit' +set policy prefix-list vyosV4 rule 30 prefix '192.0.68.0/22' +set policy prefix-list vyosV4 rule 40 action 'permit' +set policy prefix-list vyosV4 rule 40 prefix '192.0.84.0/22' +set policy prefix-list6 all6 rule 10 action 'permit' +set policy prefix-list6 all6 rule 10 ge '4' +set policy prefix-list6 all6 rule 10 prefix '2000::/3' +set policy prefix-list6 hostrouteV6 rule 20 action 'permit' +set policy prefix-list6 hostrouteV6 rule 20 ge '128' +set policy prefix-list6 hostrouteV6 rule 20 prefix '2001:db8::/29' +set policy prefix-list6 privateV6 rule 10 action 'permit' +set policy prefix-list6 privateV6 rule 10 prefix 'fc00::/7' +set policy prefix-list6 vyosV6 rule 20 action 'permit' +set policy prefix-list6 vyosV6 rule 20 prefix '2001:db8::/29' +set policy route-map ExportRouteMap rule 5 action 'permit' +set policy route-map ExportRouteMap rule 5 match as-path 'AS64512' +set policy route-map ExportRouteMap rule 5 match ip address prefix-list 'hostrouteV4' +set policy route-map ExportRouteMap rule 5 set community replace '65000:666' +set policy route-map ExportRouteMap rule 10 action 'permit' +set policy route-map ExportRouteMap rule 10 match as-path 'AS64512' +set policy route-map ExportRouteMap rule 10 match ip address prefix-list 'vyosV4' +set policy route-map ExportRouteMap rule 15 action 'permit' +set policy route-map ExportRouteMap rule 15 match as-path 'AS64512' +set policy route-map ExportRouteMap rule 15 match ipv6 address prefix-list 'hostrouteV6' +set policy route-map ExportRouteMap rule 15 set community replace '65000:666' +set policy route-map ExportRouteMap rule 20 action 'permit' +set policy route-map ExportRouteMap rule 20 match as-path 'AS64512' +set policy route-map ExportRouteMap rule 20 match ipv6 address prefix-list 'vyosV6' +set policy route-map ExportRouteMap rule 100 action 'deny' +set policy route-map ExportRouteMapAS64513 rule 5 action 'permit' +set policy route-map ExportRouteMapAS64513 rule 5 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64513 rule 5 match ip address prefix-list 'hostrouteV4' +set policy route-map ExportRouteMapAS64513 rule 5 set community replace '64513:666' +set policy route-map ExportRouteMapAS64513 rule 10 action 'permit' +set policy route-map ExportRouteMapAS64513 rule 10 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64513 rule 10 match ip address prefix-list 'vyosV4' +set policy route-map ExportRouteMapAS64513 rule 15 action 'permit' +set policy route-map ExportRouteMapAS64513 rule 15 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64513 rule 15 match ipv6 address prefix-list 'hostrouteV6' +set policy route-map ExportRouteMapAS64513 rule 15 set community replace '64513:666' +set policy route-map ExportRouteMapAS64513 rule 20 action 'permit' +set policy route-map ExportRouteMapAS64513 rule 20 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64513 rule 20 match ipv6 address prefix-list 'vyosV6' +set policy route-map ExportRouteMapAS64513 rule 100 action 'deny' +set policy route-map ExportRouteMapAS64515 rule 10 action 'permit' +set policy route-map ExportRouteMapAS64515 rule 10 match ipv6 address prefix-list 'all6' +set policy route-map ExportRouteMapAS64515 rule 20 action 'deny' +set policy route-map ExportRouteMapAS64515 rule 20 match ip address prefix-list 'defaultV4' +set policy route-map ExportRouteMapAS64515 rule 100 action 'deny' +set policy route-map ExportRouteMapAS64516 rule 5 action 'permit' +set policy route-map ExportRouteMapAS64516 rule 5 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64516 rule 5 match ip address prefix-list 'hostrouteV4' +set policy route-map ExportRouteMapAS64516 rule 5 set community replace '65000:666' +set policy route-map ExportRouteMapAS64516 rule 10 action 'permit' +set policy route-map ExportRouteMapAS64516 rule 10 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64516 rule 10 match ip address prefix-list 'vyosV4' +set policy route-map ExportRouteMapAS64516 rule 15 action 'permit' +set policy route-map ExportRouteMapAS64516 rule 15 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64516 rule 15 match ipv6 address prefix-list 'hostrouteV6' +set policy route-map ExportRouteMapAS64516 rule 15 set community replace '65000:666' +set policy route-map ExportRouteMapAS64516 rule 20 action 'permit' +set policy route-map ExportRouteMapAS64516 rule 20 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64516 rule 20 match ipv6 address prefix-list 'vyosV6' +set policy route-map ExportRouteMapAS64516 rule 20 set as-path exclude '100 200 300' +set policy route-map ExportRouteMapAS64516 rule 20 set as-path prepend '64512 64512 64512' +set policy route-map ExportRouteMapAS64516 rule 100 action 'deny' +set policy route-map ExportRouteMapAS64517 rule 5 action 'permit' +set policy route-map ExportRouteMapAS64517 rule 5 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64517 rule 5 match ip address prefix-list 'hostrouteV4' +set policy route-map ExportRouteMapAS64517 rule 5 set community replace '64517:666' +set policy route-map ExportRouteMapAS64517 rule 10 action 'permit' +set policy route-map ExportRouteMapAS64517 rule 10 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64517 rule 10 match ip address prefix-list 'vyosV4' +set policy route-map ExportRouteMapAS64517 rule 15 action 'permit' +set policy route-map ExportRouteMapAS64517 rule 15 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64517 rule 15 match ipv6 address prefix-list 'hostrouteV6' +set policy route-map ExportRouteMapAS64517 rule 15 set community replace '64517:666' +set policy route-map ExportRouteMapAS64517 rule 20 action 'permit' +set policy route-map ExportRouteMapAS64517 rule 20 match as-path 'AS64512' +set policy route-map ExportRouteMapAS64517 rule 20 match ipv6 address prefix-list 'vyosV6' +set policy route-map ExportRouteMapAS64517 rule 100 action 'deny' +set policy route-map ImportRouteMap rule 10 action 'deny' +set policy route-map ImportRouteMap rule 10 match ip address prefix-list 'privateV4' +set policy route-map ImportRouteMap rule 15 action 'deny' +set policy route-map ImportRouteMap rule 15 match ipv6 address prefix-list 'privateV6' +set policy route-map ImportRouteMap rule 20 action 'deny' +set policy route-map ImportRouteMap rule 20 match ip address prefix-list 'vyosV4' +set policy route-map ImportRouteMap rule 30 action 'deny' +set policy route-map ImportRouteMap rule 30 match ipv6 address prefix-list 'vyosV6' +set policy route-map ImportRouteMap rule 40 action 'deny' +set policy route-map ImportRouteMap rule 40 match as-path 'AS64512' +set policy route-map ImportRouteMap rule 50 action 'permit' +set policy route-map ImportRouteMap rule 50 match as-path 'AS64513-AS64514' +set policy route-map ImportRouteMap rule 50 set weight '10001' +set policy route-map ImportRouteMap rule 65535 action 'permit' +set protocols bgp address-family ipv4-unicast maximum-paths ebgp '8' +set protocols bgp address-family ipv4-unicast maximum-paths ibgp '16' +set protocols bgp address-family ipv4-unicast network 192.0.68.0/22 +set protocols bgp address-family ipv4-unicast network 192.0.84.0/22 +set protocols bgp address-family ipv4-unicast network 192.0.98.0/24 +set protocols bgp address-family ipv4-unicast network 192.0.160.0/24 +set protocols bgp address-family ipv4-unicast redistribute static route-map 'ExportRouteMap' +set protocols bgp address-family ipv6-unicast network 2001:db8::/29 +set protocols bgp address-family ipv6-unicast redistribute static route-map 'ExportRouteMap' +set protocols bgp neighbor 192.0.16.209 address-family ipv4-unicast route-map export 'ExportRouteMapAS64516' +set protocols bgp neighbor 192.0.16.209 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.16.209 remote-as '64501' +set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast maximum-prefix '300' +set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.12 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.12 remote-as '64511' +set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast maximum-prefix '75' +set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.17 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.17 password 'vyosvyos' +set protocols bgp neighbor 192.0.52.17 remote-as '64512' +set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast maximum-prefix '300' +set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.24 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.24 remote-as '64513' +set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast maximum-prefix '50' +set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.32 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.32 password 'vyosfoooo' +set protocols bgp neighbor 192.0.52.32 remote-as '64514' +set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast maximum-prefix '10' +set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.34 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.34 remote-as '64515' +set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast maximum-prefix '10' +set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.46 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.46 remote-as '64516' +set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast maximum-prefix '75' +set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.49 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.49 password 'secret' +set protocols bgp neighbor 192.0.52.49 remote-as '64517' +set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast maximum-prefix '15000' +set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.74 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.74 password 'secretvyos' +set protocols bgp neighbor 192.0.52.74 remote-as '64518' +set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast maximum-prefix '250' +set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.94 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.94 remote-as '64519' +set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast maximum-prefix '50' +set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.100 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.100 remote-as '64520' +set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast maximum-prefix '30' +set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.119 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.119 remote-as '64521' +set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast maximum-prefix '50' +set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.165 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.165 remote-as '64522' +set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast maximum-prefix '150000' +set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.170 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.170 remote-as '64523' +set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.171 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.171 remote-as '64524' +set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast maximum-prefix '20' +set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.179 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.179 remote-as '64525' +set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast maximum-prefix '1000' +set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.189 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.189 remote-as '64526' +set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast maximum-prefix '15' +set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.210 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.210 remote-as '64527' +set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast maximum-prefix '15' +set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.211 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.211 remote-as '64528' +set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.251 address-family ipv4-unicast weight '1010' +set protocols bgp neighbor 192.0.52.251 remote-as '64529' +set protocols bgp neighbor 192.0.52.252 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.52.252 address-family ipv4-unicast weight '1010' +set protocols bgp neighbor 192.0.52.252 remote-as '64530' +set protocols bgp neighbor 192.0.52.253 address-family ipv4-unicast route-map export 'ExportRouteMapAS64515' +set protocols bgp neighbor 192.0.52.253 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.52.253 passive +set protocols bgp neighbor 192.0.52.253 remote-as '64531' +set protocols bgp neighbor 192.0.68.3 address-family ipv4-unicast nexthop-self +set protocols bgp neighbor 192.0.68.3 address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp neighbor 192.0.68.3 remote-as '64532' +set protocols bgp neighbor 192.0.68.3 update-source '192.0.68.2' +set protocols bgp neighbor 192.0.176.193 address-family ipv4-unicast route-map export 'ExportRouteMapAS64516' +set protocols bgp neighbor 192.0.176.193 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.176.193 remote-as '64510' +set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast maximum-prefix '100' +set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.192.6 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.192.6 remote-as '64502' +set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast maximum-prefix '350000' +set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.192.157 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.192.157 remote-as '64503' +set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.192.228 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.192.228 remote-as '64504' +set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast maximum-prefix '350000' +set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.193.157 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.193.157 remote-as '64505' +set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.193.202 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.193.202 remote-as '64506' +set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.193.223 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.193.223 remote-as '64507' +set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.194.161 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.194.161 remote-as '64508' +set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast maximum-prefix '10000' +set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 192.0.194.171 address-family ipv4-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 192.0.194.171 remote-as '64509' +set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast maximum-prefix '5' +set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::2e address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::2e password 'vyossecret' +set protocols bgp neighbor 2001:db8:24::2e remote-as '64535' +set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast maximum-prefix '1000' +set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::4a address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::4a remote-as '64536' +set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast maximum-prefix '200' +set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::5e address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::5e remote-as '64537' +set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast maximum-prefix '20' +set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::11 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::11 remote-as '64538' +set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast maximum-prefix '300' +set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::18 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::18 remote-as '64539' +set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast maximum-prefix '10' +set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::20 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::20 remote-as '64540' +set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast maximum-prefix '5' +set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::22 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::22 remote-as '64541' +set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast maximum-prefix '20' +set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::31 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::31 remote-as '64542' +set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast maximum-prefix '15' +set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::58 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::58 remote-as '64543' +set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast maximum-prefix '10' +set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::64 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::64 password 'geheim' +set protocols bgp neighbor 2001:db8:24::64 remote-as '64544' +set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast maximum-prefix '10' +set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::a5 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::a5 remote-as '64545' +set protocols bgp neighbor 2001:db8:24::aa address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::aa address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::aa remote-as '64546' +set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast maximum-prefix '1800' +set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::ab address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::ab remote-as '64547' +set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast maximum-prefix '5' +set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast route-map export 'ExportRouteMap' +set protocols bgp neighbor 2001:db8:24::b0 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:24::b0 password 'secret123' +set protocols bgp neighbor 2001:db8:24::b0 remote-as '64548' +set protocols bgp neighbor 2001:db8:838::1 address-family ipv6-unicast route-map export 'ExportRouteMapAS64516' +set protocols bgp neighbor 2001:db8:838::1 address-family ipv6-unicast route-map import 'ImportRouteMap' +set protocols bgp neighbor 2001:db8:838::1 remote-as '64533' +set protocols bgp neighbor 2001:db8:c::3 address-family ipv6-unicast nexthop-self +set protocols bgp neighbor 2001:db8:c::3 address-family ipv6-unicast soft-reconfiguration inbound +set protocols bgp neighbor 2001:db8:c::3 remote-as '64534' +set protocols bgp neighbor 2001:db8:c::3 update-source '2001:db8:c::2' +set protocols bgp parameters log-neighbor-changes +set protocols bgp parameters router-id '192.0.68.2' +set protocols bgp system-as '64500' +set protocols static route 192.0.68.0/22 blackhole +set protocols static route 192.0.84.0/22 blackhole +set protocols static route 192.0.98.0/24 blackhole +set protocols static route 192.0.160.0/24 blackhole +set protocols static route6 2001:db8::/29 blackhole +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system flow-accounting disable-imt +set system flow-accounting interface 'eth0.4088' +set system flow-accounting interface 'eth0.4089' +set system flow-accounting netflow engine-id '1' +set system flow-accounting netflow server 192.0.2.55 port '2055' +set system flow-accounting netflow version '9' +set system flow-accounting sflow server 1.2.3.4 port '1234' +set system flow-accounting syslog-facility 'daemon' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '2001:db8::1' +set system name-server '2001:db8::2' +set system name-server '192.0.2.1' +set system name-server '192.0.2.2' +set system syslog global facility all level 'all' +set system syslog global preserve-fqdn +set system time-zone 'Europe/Zurich' diff --git a/smoketest/config-tests/bgp-dmvpn-hub b/smoketest/config-tests/bgp-dmvpn-hub new file mode 100644 index 000000000..30521520a --- /dev/null +++ b/smoketest/config-tests/bgp-dmvpn-hub @@ -0,0 +1,69 @@ +set interfaces ethernet eth0 address '100.64.10.1/31' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth1 duplex 'auto' +set interfaces loopback lo +set interfaces tunnel tun0 address '192.168.254.62/26' +set interfaces tunnel tun0 enable-multicast +set interfaces tunnel tun0 encapsulation 'gre' +set interfaces tunnel tun0 parameters ip key '1' +set interfaces tunnel tun0 source-address '100.64.10.1' +set protocols bgp address-family ipv4-unicast network 172.20.0.0/16 +set protocols bgp neighbor 192.168.254.1 peer-group 'DMVPN' +set protocols bgp neighbor 192.168.254.1 remote-as '65001' +set protocols bgp neighbor 192.168.254.2 peer-group 'DMVPN' +set protocols bgp neighbor 192.168.254.2 remote-as '65002' +set protocols bgp neighbor 192.168.254.3 peer-group 'DMVPN' +set protocols bgp neighbor 192.168.254.3 remote-as '65003' +set protocols bgp parameters log-neighbor-changes +set protocols bgp peer-group DMVPN address-family ipv4-unicast +set protocols bgp system-as '65000' +set protocols bgp timers holdtime '30' +set protocols bgp timers keepalive '10' +set protocols nhrp tunnel tun0 cisco-authentication 'secret' +set protocols nhrp tunnel tun0 holding-time '300' +set protocols nhrp tunnel tun0 multicast 'dynamic' +set protocols nhrp tunnel tun0 redirect +set protocols nhrp tunnel tun0 shortcut +set protocols static route 0.0.0.0/0 next-hop 100.64.10.0 +set protocols static route 172.20.0.0/16 blackhole distance '200' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'cpe-4' +set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' +set system login user vyos authentication plaintext-password '' +set system name-server '1.1.1.1' +set system name-server '8.8.8.8' +set system name-server '9.9.9.9' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vpn ipsec esp-group ESP-DMVPN lifetime '1800' +set vpn ipsec esp-group ESP-DMVPN mode 'transport' +set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2' +set vpn ipsec esp-group ESP-DMVPN proposal 1 encryption 'aes256' +set vpn ipsec esp-group ESP-DMVPN proposal 1 hash 'sha1' +set vpn ipsec ike-group IKE-DMVPN close-action 'none' +set vpn ipsec ike-group IKE-DMVPN key-exchange 'ikev1' +set vpn ipsec ike-group IKE-DMVPN lifetime '3600' +set vpn ipsec ike-group IKE-DMVPN proposal 1 dh-group '2' +set vpn ipsec ike-group IKE-DMVPN proposal 1 encryption 'aes256' +set vpn ipsec ike-group IKE-DMVPN proposal 1 hash 'sha1' +set vpn ipsec interface 'eth0' +set vpn ipsec profile NHRPVPN authentication mode 'pre-shared-secret' +set vpn ipsec profile NHRPVPN authentication pre-shared-secret 'VyOS-topsecret' +set vpn ipsec profile NHRPVPN bind tunnel 'tun0' +set vpn ipsec profile NHRPVPN esp-group 'ESP-DMVPN' +set vpn ipsec profile NHRPVPN ike-group 'IKE-DMVPN' diff --git a/smoketest/config-tests/bgp-dmvpn-spoke b/smoketest/config-tests/bgp-dmvpn-spoke new file mode 100644 index 000000000..d1c7bc7c0 --- /dev/null +++ b/smoketest/config-tests/bgp-dmvpn-spoke @@ -0,0 +1,75 @@ +set interfaces ethernet eth0 vif 7 description 'PPPoE-UPLINK' +set interfaces ethernet eth1 address '172.17.1.1/24' +set interfaces loopback lo +set interfaces pppoe pppoe1 authentication password 'cpe-1' +set interfaces pppoe pppoe1 authentication username 'cpe-1' +set interfaces pppoe pppoe1 no-peer-dns +set interfaces pppoe pppoe1 source-interface 'eth0.7' +set interfaces tunnel tun0 address '192.168.254.1/26' +set interfaces tunnel tun0 enable-multicast +set interfaces tunnel tun0 encapsulation 'gre' +set interfaces tunnel tun0 parameters ip key '1' +set interfaces tunnel tun0 source-address '0.0.0.0' +set nat source rule 10 log +set nat source rule 10 outbound-interface name 'pppoe1' +set nat source rule 10 source address '172.17.0.0/16' +set nat source rule 10 translation address 'masquerade' +set protocols bgp address-family ipv4-unicast network 172.17.0.0/16 +set protocols bgp neighbor 192.168.254.62 address-family ipv4-unicast +set protocols bgp neighbor 192.168.254.62 remote-as '65000' +set protocols bgp parameters log-neighbor-changes +set protocols bgp system-as '65001' +set protocols bgp timers holdtime '30' +set protocols bgp timers keepalive '10' +set protocols nhrp tunnel tun0 cisco-authentication 'secret' +set protocols nhrp tunnel tun0 holding-time '300' +set protocols nhrp tunnel tun0 map 192.168.254.62/26 nbma-address '100.64.10.1' +set protocols nhrp tunnel tun0 map 192.168.254.62/26 register +set protocols nhrp tunnel tun0 multicast 'nhs' +set protocols nhrp tunnel tun0 redirect +set protocols nhrp tunnel tun0 shortcut +set protocols static route 172.17.0.0/16 blackhole distance '200' +set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 option default-router '172.17.1.1' +set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 option name-server '172.17.1.1' +set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 range 0 start '172.17.1.100' +set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 range 0 stop '172.17.1.200' +set service dhcp-server shared-network-name LAN-3 subnet 172.17.1.0/24 subnet-id '1' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'cpe-1' +set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' +set system login user vyos authentication plaintext-password '' +set system name-server '1.1.1.1' +set system name-server '8.8.8.8' +set system name-server '9.9.9.9' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vpn ipsec esp-group ESP-DMVPN lifetime '1800' +set vpn ipsec esp-group ESP-DMVPN mode 'transport' +set vpn ipsec esp-group ESP-DMVPN pfs 'dh-group2' +set vpn ipsec esp-group ESP-DMVPN proposal 1 encryption 'aes256' +set vpn ipsec esp-group ESP-DMVPN proposal 1 hash 'sha1' +set vpn ipsec ike-group IKE-DMVPN close-action 'none' +set vpn ipsec ike-group IKE-DMVPN key-exchange 'ikev1' +set vpn ipsec ike-group IKE-DMVPN lifetime '3600' +set vpn ipsec ike-group IKE-DMVPN proposal 1 dh-group '2' +set vpn ipsec ike-group IKE-DMVPN proposal 1 encryption 'aes256' +set vpn ipsec ike-group IKE-DMVPN proposal 1 hash 'sha1' +set vpn ipsec interface 'pppoe1' +set vpn ipsec profile NHRPVPN authentication mode 'pre-shared-secret' +set vpn ipsec profile NHRPVPN authentication pre-shared-secret 'VyOS-topsecret' +set vpn ipsec profile NHRPVPN bind tunnel 'tun0' +set vpn ipsec profile NHRPVPN esp-group 'ESP-DMVPN' +set vpn ipsec profile NHRPVPN ike-group 'IKE-DMVPN' diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-leaf b/smoketest/config-tests/bgp-evpn-l2vpn-leaf new file mode 100644 index 000000000..315cb9e06 --- /dev/null +++ b/smoketest/config-tests/bgp-evpn-l2vpn-leaf @@ -0,0 +1,55 @@ +set interfaces bridge br100 member interface eth3 +set interfaces bridge br100 member interface vxlan100 +set interfaces dummy dum0 address '172.29.0.1/32' +set interfaces ethernet eth0 address '2001:db8::41/64' +set interfaces ethernet eth0 address '192.0.2.41/27' +set interfaces ethernet eth0 description 'Out-of-Band Managament Port' +set interfaces ethernet eth0 vrf 'MGMT' +set interfaces ethernet eth1 address '172.29.1.1/31' +set interfaces ethernet eth1 mtu '1600' +set interfaces ethernet eth2 address '172.29.2.1/31' +set interfaces ethernet eth2 mtu '1600' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth3 offload gro +set interfaces loopback lo +set interfaces vxlan vxlan100 mtu '1500' +set interfaces vxlan vxlan100 parameters nolearning +set interfaces vxlan vxlan100 port '8472' +set interfaces vxlan vxlan100 source-address '172.29.0.1' +set interfaces vxlan vxlan100 vni '100' +set protocols bgp address-family ipv4-unicast maximum-paths ibgp '4' +set protocols bgp address-family ipv4-unicast redistribute connected +set protocols bgp address-family l2vpn-evpn advertise-all-vni +set protocols bgp neighbor 172.29.1.0 peer-group 'evpn' +set protocols bgp neighbor 172.29.2.0 peer-group 'evpn' +set protocols bgp parameters log-neighbor-changes +set protocols bgp peer-group evpn address-family ipv4-unicast nexthop-self +set protocols bgp peer-group evpn address-family l2vpn-evpn nexthop-self +set protocols bgp peer-group evpn remote-as '65010' +set protocols bgp system-as '65010' +set service lldp interface all +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp listen-address '192.0.2.41' +set service ntp listen-address '2001:db8::41' +set service ntp server 0.de.pool.ntp.org prefer +set service ntp vrf 'MGMT' +set service ssh disable-host-validation +set service ssh vrf 'MGMT' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62 +set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1 +set vrf name MGMT table '1000' diff --git a/smoketest/config-tests/bgp-evpn-l2vpn-spine b/smoketest/config-tests/bgp-evpn-l2vpn-spine new file mode 100644 index 000000000..dee29e021 --- /dev/null +++ b/smoketest/config-tests/bgp-evpn-l2vpn-spine @@ -0,0 +1,48 @@ +set interfaces ethernet eth0 address '192.0.2.51/27' +set interfaces ethernet eth0 address '2001:db8::51/64' +set interfaces ethernet eth0 description 'Out-of-Band Managament Port' +set interfaces ethernet eth0 vrf 'MGMT' +set interfaces ethernet eth1 address '172.29.1.0/31' +set interfaces ethernet eth1 mtu '1600' +set interfaces ethernet eth2 address '172.29.1.2/31' +set interfaces ethernet eth2 mtu '1600' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth3 address '172.29.1.4/31' +set interfaces ethernet eth3 mtu '1600' +set interfaces ethernet eth3 offload gro +set interfaces loopback lo +set protocols bgp address-family ipv4-unicast maximum-paths ibgp '4' +set protocols bgp address-family ipv4-unicast redistribute connected +set protocols bgp listen range 172.29.1.0/24 peer-group 'evpn' +set protocols bgp parameters log-neighbor-changes +set protocols bgp peer-group evpn address-family ipv4-unicast route-reflector-client +set protocols bgp peer-group evpn address-family l2vpn-evpn route-reflector-client +set protocols bgp peer-group evpn capability dynamic +set protocols bgp peer-group evpn remote-as '65010' +set protocols bgp system-as '65010' +set service lldp interface all +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp listen-address '192.0.2.51' +set service ntp listen-address '2001:db8::51' +set service ntp server 0.de.pool.ntp.org prefer +set service ntp vrf 'MGMT' +set service ssh disable-host-validation +set service ssh vrf 'MGMT' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vrf name MGMT protocols static route 0.0.0.0/0 next-hop 192.0.2.62 +set vrf name MGMT protocols static route6 ::/0 next-hop 2001:db8::1 +set vrf name MGMT table '1000' diff --git a/smoketest/config-tests/bgp-evpn-l3vpn-pe-router b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router new file mode 100644 index 000000000..7a2ec9f91 --- /dev/null +++ b/smoketest/config-tests/bgp-evpn-l3vpn-pe-router @@ -0,0 +1,123 @@ +set interfaces bridge br2000 address '10.1.1.1/24' +set interfaces bridge br2000 description 'customer blue' +set interfaces bridge br2000 member interface eth4 +set interfaces bridge br2000 member interface vxlan2000 +set interfaces bridge br2000 vrf 'blue' +set interfaces bridge br3000 address '10.2.1.1/24' +set interfaces bridge br3000 description 'customer red' +set interfaces bridge br3000 member interface eth5 +set interfaces bridge br3000 member interface vxlan3000 +set interfaces bridge br3000 vrf 'red' +set interfaces bridge br4000 address '10.3.1.1/24' +set interfaces bridge br4000 description 'customer green' +set interfaces bridge br4000 member interface eth6 +set interfaces bridge br4000 member interface vxlan4000 +set interfaces bridge br4000 vrf 'green' +set interfaces dummy dum0 address '172.29.255.1/32' +set interfaces ethernet eth0 address '192.0.2.59/27' +set interfaces ethernet eth0 address '2001:db8:ffff::59/64' +set interfaces ethernet eth0 description 'Out-of-Band Managament Port' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 vrf 'mgmt' +set interfaces ethernet eth1 address '172.29.0.2/31' +set interfaces ethernet eth1 description 'link to pe2' +set interfaces ethernet eth1 mtu '1600' +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth2 disable +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth3 address '172.29.0.6/31' +set interfaces ethernet eth3 description 'link to pe3' +set interfaces ethernet eth3 mtu '1600' +set interfaces ethernet eth3 offload gro +set interfaces ethernet eth4 description 'customer blue' +set interfaces ethernet eth4 offload gro +set interfaces ethernet eth5 description 'customer red' +set interfaces ethernet eth5 offload gro +set interfaces ethernet eth6 description 'customer green' +set interfaces ethernet eth6 offload gro +set interfaces loopback lo +set interfaces vxlan vxlan2000 mtu '1500' +set interfaces vxlan vxlan2000 parameters nolearning +set interfaces vxlan vxlan2000 port '4789' +set interfaces vxlan vxlan2000 source-address '172.29.255.1' +set interfaces vxlan vxlan2000 vni '2000' +set interfaces vxlan vxlan3000 mtu '1500' +set interfaces vxlan vxlan3000 parameters nolearning +set interfaces vxlan vxlan3000 port '4789' +set interfaces vxlan vxlan3000 source-address '172.29.255.1' +set interfaces vxlan vxlan3000 vni '3000' +set interfaces vxlan vxlan4000 mtu '1500' +set interfaces vxlan vxlan4000 parameters nolearning +set interfaces vxlan vxlan4000 port '4789' +set interfaces vxlan vxlan4000 source-address '172.29.255.1' +set interfaces vxlan vxlan4000 vni '4000' +set protocols bgp address-family l2vpn-evpn advertise ipv4 unicast +set protocols bgp address-family l2vpn-evpn advertise-all-vni +set protocols bgp neighbor 172.29.255.2 peer-group 'ibgp' +set protocols bgp neighbor 172.29.255.3 peer-group 'ibgp' +set protocols bgp parameters log-neighbor-changes +set protocols bgp parameters router-id '172.29.255.1' +set protocols bgp peer-group ibgp address-family l2vpn-evpn +set protocols bgp peer-group ibgp remote-as '100' +set protocols bgp peer-group ibgp update-source 'dum0' +set protocols bgp system-as '100' +set protocols ospf area 0 network '172.29.0.2/31' +set protocols ospf area 0 network '172.29.0.6/31' +set protocols ospf interface eth1 network 'point-to-point' +set protocols ospf interface eth1 passive disable +set protocols ospf interface eth3 network 'point-to-point' +set protocols ospf interface eth3 passive disable +set protocols ospf log-adjacency-changes detail +set protocols ospf parameters abr-type 'cisco' +set protocols ospf parameters router-id '172.29.255.1' +set protocols ospf passive-interface 'default' +set protocols ospf redistribute connected +set service lldp interface all +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp listen-address '192.0.2.59' +set service ntp listen-address '2001:db8:ffff::59' +set service ntp server 192.0.2.251 +set service ntp server 192.0.2.252 +set service ntp server 2001:db8::251 +set service ntp server 2001:db8::252 +set service ntp vrf 'mgmt' +set service ssh disable-host-validation +set service ssh port '22' +set service ssh vrf 'mgmt' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system name-server '192.0.2.251' +set system name-server '192.0.2.252' +set system name-server '2001:db8::1' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vrf name blue protocols bgp address-family ipv4-unicast redistribute connected +set vrf name blue protocols bgp address-family l2vpn-evpn advertise ipv4 unicast +set vrf name blue protocols bgp system-as '100' +set vrf name blue table '2000' +set vrf name blue vni '2000' +set vrf name green protocols bgp address-family ipv4-unicast redistribute connected +set vrf name green protocols bgp address-family l2vpn-evpn advertise ipv4 unicast +set vrf name green protocols bgp system-as '100' +set vrf name green table '4000' +set vrf name green vni '4000' +set vrf name mgmt protocols static route 0.0.0.0/0 next-hop 192.0.2.62 +set vrf name mgmt protocols static route6 ::/0 next-hop 2001:db8:ffff::1 +set vrf name mgmt table '1000' +set vrf name red protocols bgp address-family ipv4-unicast redistribute connected +set vrf name red protocols bgp address-family l2vpn-evpn advertise ipv4 unicast +set vrf name red protocols bgp system-as '100' +set vrf name red table '3000' +set vrf name red vni '3000' diff --git a/smoketest/config-tests/bgp-medium-confederation b/smoketest/config-tests/bgp-medium-confederation index ea3c2d144..582e28047 100644 --- a/smoketest/config-tests/bgp-medium-confederation +++ b/smoketest/config-tests/bgp-medium-confederation @@ -1,7 +1,7 @@ set interfaces dummy dum0 address '1.1.1.1/32' set interfaces dummy dum0 address '2001:db8::1/128' -set interfaces ethernet eth0 address 'fd52:100:200:fffe::1/64' set interfaces ethernet eth0 address '192.168.253.1/24' +set interfaces ethernet eth0 address 'fd52:100:200:fffe::1/64' set interfaces ethernet eth1 set interfaces ethernet eth2 set policy route-map BGP-IN rule 10 action 'permit' diff --git a/smoketest/config-tests/bgp-rpki b/smoketest/config-tests/bgp-rpki new file mode 100644 index 000000000..44e95ae98 --- /dev/null +++ b/smoketest/config-tests/bgp-rpki @@ -0,0 +1,43 @@ +set interfaces ethernet eth0 address '192.0.2.100/25' +set interfaces ethernet eth0 address '2001:db8::ffff/64' +set interfaces ethernet eth1 address '100.64.0.1/24' +set interfaces loopback lo +set policy route-map ebgp-transit-rpki rule 10 action 'deny' +set policy route-map ebgp-transit-rpki rule 10 match rpki 'invalid' +set policy route-map ebgp-transit-rpki rule 20 action 'permit' +set policy route-map ebgp-transit-rpki rule 20 match rpki 'notfound' +set policy route-map ebgp-transit-rpki rule 20 set local-preference '20' +set policy route-map ebgp-transit-rpki rule 30 action 'permit' +set policy route-map ebgp-transit-rpki rule 30 match rpki 'valid' +set policy route-map ebgp-transit-rpki rule 30 set local-preference '100' +set policy route-map ebgp-transit-rpki rule 40 action 'permit' +set policy route-map ebgp-transit-rpki rule 40 set extcommunity rt '192.0.2.100:100' +set policy route-map ebgp-transit-rpki rule 40 set extcommunity soo '64500:100' +set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast nexthop-self +set protocols bgp neighbor 1.2.3.4 address-family ipv4-unicast route-map import 'ebgp-transit-rpki' +set protocols bgp neighbor 1.2.3.4 remote-as '10' +set protocols bgp system-as '64500' +set protocols rpki cache 192.0.2.10 port '3323' +set protocols rpki cache 192.0.2.10 preference '1' +set protocols static route 0.0.0.0/0 next-hop 192.0.2.1 +set protocols static route6 ::/0 next-hop 2001:db8::1 +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set service ssh +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/bgp-small-internet-exchange b/smoketest/config-tests/bgp-small-internet-exchange new file mode 100644 index 000000000..a9dce4dd5 --- /dev/null +++ b/smoketest/config-tests/bgp-small-internet-exchange @@ -0,0 +1,209 @@ +set interfaces ethernet eth0 address '192.0.2.100/25' +set interfaces ethernet eth0 address '2001:db8:aaaa::ffff/64' +set interfaces ethernet eth1 address '192.0.2.200/25' +set interfaces ethernet eth1 address '2001:db8:bbbb::ffff/64' +set interfaces loopback lo +set policy as-path-list bogon-asns rule 10 action 'permit' +set policy as-path-list bogon-asns rule 10 description 'RFC 7607' +set policy as-path-list bogon-asns rule 10 regex '_0_' +set policy as-path-list bogon-asns rule 20 action 'permit' +set policy as-path-list bogon-asns rule 20 description 'RFC 4893' +set policy as-path-list bogon-asns rule 20 regex '_23456_' +set policy as-path-list bogon-asns rule 30 action 'permit' +set policy as-path-list bogon-asns rule 30 description 'RFC 5398/6996/7300' +set policy as-path-list bogon-asns rule 30 regex '_6449[6-9]_|_65[0-4][0-9][0-9]_|_655[0-4][0-9]_|_6555[0-1]_' +set policy as-path-list bogon-asns rule 40 action 'permit' +set policy as-path-list bogon-asns rule 40 description 'IANA reserved' +set policy as-path-list bogon-asns rule 40 regex '_6555[2-9]_|_655[6-9][0-9]_|_65[6-9][0-9][0-9]_|_6[6-9][0-9][0-9][0-]_|_[7-9][0-9][0-9][0-9][0-9]_|_1[0-2][0-9][0-9][0-9][0-9]_|_130[0-9][0-9][0-9]_|_1310[0-6][0-9]_|_13107[01]_' +set policy prefix-list IX-out-v4 rule 10 action 'permit' +set policy prefix-list IX-out-v4 rule 10 prefix '10.0.0.0/23' +set policy prefix-list IX-out-v4 rule 20 action 'permit' +set policy prefix-list IX-out-v4 rule 20 prefix '10.0.128.0/23' +set policy prefix-list bogon-v4 rule 10 action 'permit' +set policy prefix-list bogon-v4 rule 10 le '32' +set policy prefix-list bogon-v4 rule 10 prefix '0.0.0.0/8' +set policy prefix-list bogon-v4 rule 20 action 'permit' +set policy prefix-list bogon-v4 rule 20 le '32' +set policy prefix-list bogon-v4 rule 20 prefix '10.0.0.0/8' +set policy prefix-list bogon-v4 rule 30 action 'permit' +set policy prefix-list bogon-v4 rule 30 le '32' +set policy prefix-list bogon-v4 rule 30 prefix '100.64.0.0/10' +set policy prefix-list bogon-v4 rule 40 action 'permit' +set policy prefix-list bogon-v4 rule 40 le '32' +set policy prefix-list bogon-v4 rule 40 prefix '127.0.0.0/8' +set policy prefix-list bogon-v4 rule 50 action 'permit' +set policy prefix-list bogon-v4 rule 50 le '32' +set policy prefix-list bogon-v4 rule 50 prefix '169.254.0.0/16' +set policy prefix-list bogon-v4 rule 60 action 'permit' +set policy prefix-list bogon-v4 rule 60 le '32' +set policy prefix-list bogon-v4 rule 60 prefix '172.16.0.0/12' +set policy prefix-list bogon-v4 rule 70 action 'permit' +set policy prefix-list bogon-v4 rule 70 le '32' +set policy prefix-list bogon-v4 rule 70 prefix '192.0.2.0/24' +set policy prefix-list bogon-v4 rule 80 action 'permit' +set policy prefix-list bogon-v4 rule 80 le '32' +set policy prefix-list bogon-v4 rule 80 prefix '192.88.99.0/24' +set policy prefix-list bogon-v4 rule 90 action 'permit' +set policy prefix-list bogon-v4 rule 90 le '32' +set policy prefix-list bogon-v4 rule 90 prefix '192.168.0.0/16' +set policy prefix-list bogon-v4 rule 100 action 'permit' +set policy prefix-list bogon-v4 rule 100 le '32' +set policy prefix-list bogon-v4 rule 100 prefix '198.18.0.0/15' +set policy prefix-list bogon-v4 rule 110 action 'permit' +set policy prefix-list bogon-v4 rule 110 le '32' +set policy prefix-list bogon-v4 rule 110 prefix '198.51.100.0/24' +set policy prefix-list bogon-v4 rule 120 action 'permit' +set policy prefix-list bogon-v4 rule 120 le '32' +set policy prefix-list bogon-v4 rule 120 prefix '203.0.113.0/24' +set policy prefix-list bogon-v4 rule 130 action 'permit' +set policy prefix-list bogon-v4 rule 130 le '32' +set policy prefix-list bogon-v4 rule 130 prefix '224.0.0.0/4' +set policy prefix-list bogon-v4 rule 140 action 'permit' +set policy prefix-list bogon-v4 rule 140 le '32' +set policy prefix-list bogon-v4 rule 140 prefix '240.0.0.0/4' +set policy prefix-list prefix-filter-v4 rule 10 action 'permit' +set policy prefix-list prefix-filter-v4 rule 10 ge '25' +set policy prefix-list prefix-filter-v4 rule 10 prefix '0.0.0.0/0' +set policy prefix-list6 IX-out-v6 rule 10 action 'permit' +set policy prefix-list6 IX-out-v6 rule 10 prefix '2001:db8:100::/40' +set policy prefix-list6 IX-out-v6 rule 20 action 'permit' +set policy prefix-list6 IX-out-v6 rule 20 prefix '2001:db8:200::/40' +set policy prefix-list6 bogon-v6 rule 10 action 'permit' +set policy prefix-list6 bogon-v6 rule 10 description 'RFC 4291 IPv4-compatible, loopback, et al' +set policy prefix-list6 bogon-v6 rule 10 le '128' +set policy prefix-list6 bogon-v6 rule 10 prefix '::/8' +set policy prefix-list6 bogon-v6 rule 20 action 'permit' +set policy prefix-list6 bogon-v6 rule 20 description 'RFC 6666 Discard-Only' +set policy prefix-list6 bogon-v6 rule 20 le '128' +set policy prefix-list6 bogon-v6 rule 20 prefix '0100::/64' +set policy prefix-list6 bogon-v6 rule 30 action 'permit' +set policy prefix-list6 bogon-v6 rule 30 description 'RFC 5180 BMWG' +set policy prefix-list6 bogon-v6 rule 30 le '128' +set policy prefix-list6 bogon-v6 rule 30 prefix '2001:2::/48' +set policy prefix-list6 bogon-v6 rule 40 action 'permit' +set policy prefix-list6 bogon-v6 rule 40 description 'RFC 4843 ORCHID' +set policy prefix-list6 bogon-v6 rule 40 le '128' +set policy prefix-list6 bogon-v6 rule 40 prefix '2001:10::/28' +set policy prefix-list6 bogon-v6 rule 50 action 'permit' +set policy prefix-list6 bogon-v6 rule 50 description 'RFC 3849 documentation' +set policy prefix-list6 bogon-v6 rule 50 le '128' +set policy prefix-list6 bogon-v6 rule 50 prefix '2001:db8::/32' +set policy prefix-list6 bogon-v6 rule 60 action 'permit' +set policy prefix-list6 bogon-v6 rule 60 description 'RFC 7526 6to4 anycast relay' +set policy prefix-list6 bogon-v6 rule 60 le '128' +set policy prefix-list6 bogon-v6 rule 60 prefix '2002::/16' +set policy prefix-list6 bogon-v6 rule 70 action 'permit' +set policy prefix-list6 bogon-v6 rule 70 description 'RFC 3701 old 6bone' +set policy prefix-list6 bogon-v6 rule 70 le '128' +set policy prefix-list6 bogon-v6 rule 70 prefix '3ffe::/16' +set policy prefix-list6 bogon-v6 rule 80 action 'permit' +set policy prefix-list6 bogon-v6 rule 80 description 'RFC 4193 unique local unicast' +set policy prefix-list6 bogon-v6 rule 80 le '128' +set policy prefix-list6 bogon-v6 rule 80 prefix 'fc00::/7' +set policy prefix-list6 bogon-v6 rule 90 action 'permit' +set policy prefix-list6 bogon-v6 rule 90 description 'RFC 4291 link local unicast' +set policy prefix-list6 bogon-v6 rule 90 le '128' +set policy prefix-list6 bogon-v6 rule 90 prefix 'fe80::/10' +set policy prefix-list6 bogon-v6 rule 100 action 'permit' +set policy prefix-list6 bogon-v6 rule 100 description 'RFC 3879 old site local unicast' +set policy prefix-list6 bogon-v6 rule 100 le '128' +set policy prefix-list6 bogon-v6 rule 100 prefix 'fec0::/10' +set policy prefix-list6 bogon-v6 rule 110 action 'permit' +set policy prefix-list6 bogon-v6 rule 110 description 'RFC 4291 multicast' +set policy prefix-list6 bogon-v6 rule 110 le '128' +set policy prefix-list6 bogon-v6 rule 110 prefix 'ff00::/8' +set policy prefix-list6 prefix-filter-v6 rule 10 action 'permit' +set policy prefix-list6 prefix-filter-v6 rule 10 ge '49' +set policy prefix-list6 prefix-filter-v6 rule 10 prefix '::/0' +set policy route-map IX-in-v4 rule 5 action 'permit' +set policy route-map IX-in-v4 rule 5 call 'eBGP-IN-v4' +set policy route-map IX-in-v4 rule 5 on-match next +set policy route-map IX-in-v4 rule 10 action 'permit' +set policy route-map IX-in-v6 rule 5 action 'permit' +set policy route-map IX-in-v6 rule 5 call 'eBGP-IN-v6' +set policy route-map IX-in-v6 rule 5 on-match next +set policy route-map IX-in-v6 rule 10 action 'permit' +set policy route-map IX-out-v4 rule 10 action 'permit' +set policy route-map IX-out-v4 rule 10 match ip address prefix-list 'IX-out-v4' +set policy route-map IX-out-v6 rule 10 action 'permit' +set policy route-map IX-out-v6 rule 10 match ipv6 address prefix-list 'IX-out-v6' +set policy route-map eBGP-IN-v4 rule 10 action 'deny' +set policy route-map eBGP-IN-v4 rule 10 match as-path 'bogon-asns' +set policy route-map eBGP-IN-v4 rule 20 action 'deny' +set policy route-map eBGP-IN-v4 rule 20 match ip address prefix-list 'bogon-v4' +set policy route-map eBGP-IN-v4 rule 30 action 'deny' +set policy route-map eBGP-IN-v4 rule 30 match ip address prefix-list 'prefix-filter-v4' +set policy route-map eBGP-IN-v4 rule 40 action 'permit' +set policy route-map eBGP-IN-v4 rule 40 set local-preference '100' +set policy route-map eBGP-IN-v4 rule 40 set metric '0' +set policy route-map eBGP-IN-v6 rule 10 action 'deny' +set policy route-map eBGP-IN-v6 rule 10 match as-path 'bogon-asns' +set policy route-map eBGP-IN-v6 rule 20 action 'deny' +set policy route-map eBGP-IN-v6 rule 20 match ipv6 address prefix-list 'bogon-v6' +set policy route-map eBGP-IN-v6 rule 30 action 'deny' +set policy route-map eBGP-IN-v6 rule 30 match ipv6 address prefix-list 'prefix-filter-v6' +set policy route-map eBGP-IN-v6 rule 31 action 'deny' +set policy route-map eBGP-IN-v6 rule 31 match ipv6 nexthop address '2001:db8::1' +set policy route-map eBGP-IN-v6 rule 40 action 'permit' +set policy route-map eBGP-IN-v6 rule 40 set local-preference '100' +set policy route-map eBGP-IN-v6 rule 40 set metric '0' +set protocols bgp address-family ipv4-unicast network 10.0.0.0/23 +set protocols bgp address-family ipv4-unicast network 10.0.128.0/23 +set protocols bgp address-family ipv6-unicast network 2001:db8:100::/40 +set protocols bgp address-family ipv6-unicast network 2001:db8:200::/40 +set protocols bgp neighbor 192.0.2.1 description 'Peering: IX-1 (Route Server)' +set protocols bgp neighbor 192.0.2.1 peer-group 'IXPeeringIPv4' +set protocols bgp neighbor 192.0.2.1 remote-as '65020' +set protocols bgp neighbor 192.0.2.2 description 'Peering: IX-1 (Route Server)' +set protocols bgp neighbor 192.0.2.2 peer-group 'IXPeeringIPv4' +set protocols bgp neighbor 192.0.2.2 remote-as '65020' +set protocols bgp neighbor 192.0.2.3 description 'Peering: IX-1 (Route Server)' +set protocols bgp neighbor 192.0.2.3 peer-group 'IXPeeringIPv4' +set protocols bgp neighbor 192.0.2.3 remote-as '65020' +set protocols bgp neighbor 192.0.2.129 description 'Peering: IX-2 (Route Server)' +set protocols bgp neighbor 192.0.2.129 peer-group 'IXPeeringIPv4' +set protocols bgp neighbor 192.0.2.129 remote-as '65030' +set protocols bgp neighbor 192.0.2.130 description 'Peering: IX-2 (Route Server)' +set protocols bgp neighbor 192.0.2.130 peer-group 'IXPeeringIPv4' +set protocols bgp neighbor 192.0.2.130 remote-as '65030' +set protocols bgp neighbor 2001:db8:aaaa::1 description 'Peering: IX-1 (Route Server)' +set protocols bgp neighbor 2001:db8:aaaa::1 peer-group 'IXPeeringIPv6' +set protocols bgp neighbor 2001:db8:aaaa::1 remote-as '65020' +set protocols bgp neighbor 2001:db8:aaaa::2 description 'Peering: IX-1 (Route Server)' +set protocols bgp neighbor 2001:db8:aaaa::2 peer-group 'IXPeeringIPv6' +set protocols bgp neighbor 2001:db8:aaaa::2 remote-as '65020' +set protocols bgp neighbor 2001:db8:bbbb::1 description 'Peering: IX-2 (Route Server)' +set protocols bgp neighbor 2001:db8:bbbb::1 peer-group 'IXPeeringIPv6' +set protocols bgp neighbor 2001:db8:bbbb::1 remote-as '65030' +set protocols bgp neighbor 2001:db8:bbbb::2 description 'Peering: IX-2 (Route Server)' +set protocols bgp neighbor 2001:db8:bbbb::2 peer-group 'IXPeeringIPv6' +set protocols bgp neighbor 2001:db8:bbbb::2 remote-as '65030' +set protocols bgp peer-group IXPeeringIPv4 address-family ipv4-unicast route-map export 'IX-out-v4' +set protocols bgp peer-group IXPeeringIPv4 address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp peer-group IXPeeringIPv6 address-family ipv6-unicast route-map export 'IX-out-v6' +set protocols bgp peer-group IXPeeringIPv6 address-family ipv6-unicast soft-reconfiguration inbound +set protocols bgp system-as '65000' +set protocols static route 10.0.0.0/23 blackhole distance '250' +set protocols static route 10.0.128.0/23 blackhole distance '250' +set protocols static route6 2001:db8:100::/40 blackhole distance '250' +set protocols static route6 2001:db8:200::/40 blackhole distance '250' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set service ssh +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/bgp-small-ipv4-unicast b/smoketest/config-tests/bgp-small-ipv4-unicast new file mode 100644 index 000000000..b8c0e1246 --- /dev/null +++ b/smoketest/config-tests/bgp-small-ipv4-unicast @@ -0,0 +1,32 @@ +set interfaces ethernet eth0 address '192.0.2.1/24' +set interfaces ethernet eth0 address '2001:db8::1/64' +set interfaces loopback lo +set protocols bgp address-family ipv4-unicast network 10.0.150.0/23 +set protocols bgp address-family ipv6-unicast network 2001:db8:200::/40 +set protocols bgp neighbor 192.0.2.10 address-family ipv4-unicast +set protocols bgp neighbor 192.0.2.10 remote-as '65010' +set protocols bgp neighbor 192.0.2.11 address-family ipv4-unicast +set protocols bgp neighbor 192.0.2.11 remote-as '65011' +set protocols bgp neighbor 2001:db8::10 address-family ipv4-unicast +set protocols bgp neighbor 2001:db8::10 remote-as '65010' +set protocols bgp neighbor 2001:db8::11 address-family ipv4-unicast +set protocols bgp neighbor 2001:db8::11 remote-as '65011' +set protocols bgp parameters log-neighbor-changes +set protocols bgp system-as '65001' +set service ssh disable-host-validation +set service ssh port '22' +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'notice' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/cluster-basic b/smoketest/config-tests/cluster-basic new file mode 100644 index 000000000..744c117eb --- /dev/null +++ b/smoketest/config-tests/cluster-basic @@ -0,0 +1,21 @@ +set high-availability vrrp group VyOS address 192.0.2.10/24 +set high-availability vrrp group VyOS address 192.0.2.20/24 +set high-availability vrrp group VyOS advertise-interval '1' +set high-availability vrrp group VyOS authentication password 'qwerty' +set high-availability vrrp group VyOS authentication type 'plaintext-password' +set high-availability vrrp group VyOS interface 'eth1' +set high-availability vrrp group VyOS vrid '1' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 address '192.0.2.1/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set interfaces loopback lo +set system config-management commit-revisions '100' +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Antarctica/South_Pole' diff --git a/smoketest/config-tests/container-simple b/smoketest/config-tests/container-simple index 5af365cf9..fcc665100 100644 --- a/smoketest/config-tests/container-simple +++ b/smoketest/config-tests/container-simple @@ -1,8 +1,3 @@ -set system config-management commit-revisions '50' -set system host-name 'vyos' -set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' -set system login user vyos authentication plaintext-password '' -set system console device ttyS0 speed '115200' set container name c01 allow-host-networks set container name c01 capability 'net-bind-service' set container name c01 capability 'net-raw' @@ -11,4 +6,13 @@ set container name c02 allow-host-networks set container name c02 allow-host-pid set container name c02 capability 'sys-time' set container name c02 image 'busybox:stable' -set container name c02 sysctl parameter kernel.msgmax value '8192'
\ No newline at end of file +set container name c02 sysctl parameter kernel.msgmax value '8192' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set system config-management commit-revisions '50' +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' +set system login user vyos authentication plaintext-password '' diff --git a/smoketest/config-tests/dialup-router-complex b/smoketest/config-tests/dialup-router-complex new file mode 100644 index 000000000..4416ef82e --- /dev/null +++ b/smoketest/config-tests/dialup-router-complex @@ -0,0 +1,740 @@ +set firewall global-options all-ping 'enable' +set firewall global-options broadcast-ping 'disable' +set firewall global-options ip-src-route 'disable' +set firewall global-options ipv6-receive-redirects 'disable' +set firewall global-options ipv6-src-route 'disable' +set firewall global-options log-martians 'enable' +set firewall global-options receive-redirects 'disable' +set firewall global-options send-redirects 'enable' +set firewall global-options source-validation 'disable' +set firewall global-options syn-cookies 'enable' +set firewall global-options timeout icmp '30' +set firewall global-options timeout other '600' +set firewall global-options timeout udp other '300' +set firewall global-options timeout udp stream '300' +set firewall global-options twa-hazards-protection 'disable' +set firewall group address-group AUDIO-STREAM address '172.16.35.20' +set firewall group address-group AUDIO-STREAM address '172.16.35.21' +set firewall group address-group AUDIO-STREAM address '172.16.35.22' +set firewall group address-group AUDIO-STREAM address '172.16.35.23' +set firewall group address-group DMZ-RDP-SERVER address '172.16.33.40' +set firewall group address-group DMZ-WEBSERVER address '172.16.36.10' +set firewall group address-group DMZ-WEBSERVER address '172.16.36.40' +set firewall group address-group DMZ-WEBSERVER address '172.16.36.20' +set firewall group address-group DOMAIN-CONTROLLER address '172.16.100.10' +set firewall group address-group DOMAIN-CONTROLLER address '172.16.100.20' +set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.241' +set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.242' +set firewall group address-group MEDIA-STREAMING-CLIENTS address '172.16.35.243' +set firewall group ipv6-network-group LOCAL-ADDRESSES network 'ff02::/64' +set firewall group ipv6-network-group LOCAL-ADDRESSES network 'fe80::/10' +set firewall group network-group SSH-IN-ALLOW network '192.0.2.0/24' +set firewall group network-group SSH-IN-ALLOW network '10.0.0.0/8' +set firewall group network-group SSH-IN-ALLOW network '172.16.0.0/12' +set firewall group network-group SSH-IN-ALLOW network '192.168.0.0/16' +set firewall group port-group SMART-TV-PORTS port '5005-5006' +set firewall group port-group SMART-TV-PORTS port '80' +set firewall group port-group SMART-TV-PORTS port '443' +set firewall group port-group SMART-TV-PORTS port '3722' +set firewall ipv4 name DMZ-GUEST default-action 'drop' +set firewall ipv4 name DMZ-GUEST default-log +set firewall ipv4 name DMZ-GUEST rule 1 action 'return' +set firewall ipv4 name DMZ-GUEST rule 1 state 'established' +set firewall ipv4 name DMZ-GUEST rule 1 state 'related' +set firewall ipv4 name DMZ-GUEST rule 2 action 'drop' +set firewall ipv4 name DMZ-GUEST rule 2 log +set firewall ipv4 name DMZ-GUEST rule 2 state 'invalid' +set firewall ipv4 name DMZ-LAN default-action 'drop' +set firewall ipv4 name DMZ-LAN default-log +set firewall ipv4 name DMZ-LAN rule 1 action 'return' +set firewall ipv4 name DMZ-LAN rule 1 state 'established' +set firewall ipv4 name DMZ-LAN rule 1 state 'related' +set firewall ipv4 name DMZ-LAN rule 2 action 'drop' +set firewall ipv4 name DMZ-LAN rule 2 log +set firewall ipv4 name DMZ-LAN rule 2 state 'invalid' +set firewall ipv4 name DMZ-LAN rule 100 action 'return' +set firewall ipv4 name DMZ-LAN rule 100 description 'NTP and LDAP to AD DC' +set firewall ipv4 name DMZ-LAN rule 100 destination group address-group 'DOMAIN-CONTROLLER' +set firewall ipv4 name DMZ-LAN rule 100 destination port '123,389,636' +set firewall ipv4 name DMZ-LAN rule 100 protocol 'tcp_udp' +set firewall ipv4 name DMZ-LAN rule 300 action 'return' +set firewall ipv4 name DMZ-LAN rule 300 destination group address-group 'DMZ-RDP-SERVER' +set firewall ipv4 name DMZ-LAN rule 300 destination port '3389' +set firewall ipv4 name DMZ-LAN rule 300 protocol 'tcp_udp' +set firewall ipv4 name DMZ-LAN rule 300 source address '172.16.36.20' +set firewall ipv4 name DMZ-LOCAL default-action 'drop' +set firewall ipv4 name DMZ-LOCAL default-log +set firewall ipv4 name DMZ-LOCAL rule 1 action 'return' +set firewall ipv4 name DMZ-LOCAL rule 1 state 'established' +set firewall ipv4 name DMZ-LOCAL rule 1 state 'related' +set firewall ipv4 name DMZ-LOCAL rule 2 action 'drop' +set firewall ipv4 name DMZ-LOCAL rule 2 log +set firewall ipv4 name DMZ-LOCAL rule 2 state 'invalid' +set firewall ipv4 name DMZ-LOCAL rule 50 action 'return' +set firewall ipv4 name DMZ-LOCAL rule 50 destination address '172.16.254.30' +set firewall ipv4 name DMZ-LOCAL rule 50 destination port '53' +set firewall ipv4 name DMZ-LOCAL rule 50 protocol 'tcp_udp' +set firewall ipv4 name DMZ-LOCAL rule 123 action 'return' +set firewall ipv4 name DMZ-LOCAL rule 123 destination port '123' +set firewall ipv4 name DMZ-LOCAL rule 123 protocol 'udp' +set firewall ipv4 name DMZ-LOCAL rule 800 action 'drop' +set firewall ipv4 name DMZ-LOCAL rule 800 description 'SSH anti brute force' +set firewall ipv4 name DMZ-LOCAL rule 800 destination port 'ssh' +set firewall ipv4 name DMZ-LOCAL rule 800 log +set firewall ipv4 name DMZ-LOCAL rule 800 protocol 'tcp' +set firewall ipv4 name DMZ-LOCAL rule 800 recent count '4' +set firewall ipv4 name DMZ-LOCAL rule 800 recent time 'minute' +set firewall ipv4 name DMZ-LOCAL rule 800 state 'new' +set firewall ipv4 name DMZ-WAN default-action 'return' +set firewall ipv4 name GUEST-DMZ default-action 'drop' +set firewall ipv4 name GUEST-DMZ default-log +set firewall ipv4 name GUEST-DMZ rule 1 action 'return' +set firewall ipv4 name GUEST-DMZ rule 1 state 'established' +set firewall ipv4 name GUEST-DMZ rule 1 state 'related' +set firewall ipv4 name GUEST-DMZ rule 2 action 'drop' +set firewall ipv4 name GUEST-DMZ rule 2 log +set firewall ipv4 name GUEST-DMZ rule 2 state 'invalid' +set firewall ipv4 name GUEST-DMZ rule 100 action 'return' +set firewall ipv4 name GUEST-DMZ rule 100 destination port '80,443' +set firewall ipv4 name GUEST-DMZ rule 100 protocol 'tcp' +set firewall ipv4 name GUEST-IOT default-action 'drop' +set firewall ipv4 name GUEST-IOT default-log +set firewall ipv4 name GUEST-IOT rule 1 action 'return' +set firewall ipv4 name GUEST-IOT rule 1 state 'established' +set firewall ipv4 name GUEST-IOT rule 1 state 'related' +set firewall ipv4 name GUEST-IOT rule 2 action 'drop' +set firewall ipv4 name GUEST-IOT rule 2 log +set firewall ipv4 name GUEST-IOT rule 2 state 'invalid' +set firewall ipv4 name GUEST-IOT rule 100 action 'return' +set firewall ipv4 name GUEST-IOT rule 100 description 'MEDIA-STREAMING-CLIENTS Devices to GUEST' +set firewall ipv4 name GUEST-IOT rule 100 destination group address-group 'MEDIA-STREAMING-CLIENTS' +set firewall ipv4 name GUEST-IOT rule 100 protocol 'tcp_udp' +set firewall ipv4 name GUEST-IOT rule 110 action 'return' +set firewall ipv4 name GUEST-IOT rule 110 description 'AUDIO-STREAM Devices to GUEST' +set firewall ipv4 name GUEST-IOT rule 110 destination group address-group 'AUDIO-STREAM' +set firewall ipv4 name GUEST-IOT rule 110 protocol 'tcp_udp' +set firewall ipv4 name GUEST-IOT rule 200 action 'return' +set firewall ipv4 name GUEST-IOT rule 200 description 'MCAST relay' +set firewall ipv4 name GUEST-IOT rule 200 destination address '224.0.0.251' +set firewall ipv4 name GUEST-IOT rule 200 destination port '5353' +set firewall ipv4 name GUEST-IOT rule 200 protocol 'udp' +set firewall ipv4 name GUEST-IOT rule 300 action 'return' +set firewall ipv4 name GUEST-IOT rule 300 description 'BCAST relay' +set firewall ipv4 name GUEST-IOT rule 300 destination port '1900' +set firewall ipv4 name GUEST-IOT rule 300 protocol 'udp' +set firewall ipv4 name GUEST-LAN default-action 'drop' +set firewall ipv4 name GUEST-LAN default-log +set firewall ipv4 name GUEST-LAN rule 1 action 'return' +set firewall ipv4 name GUEST-LAN rule 1 state 'established' +set firewall ipv4 name GUEST-LAN rule 1 state 'related' +set firewall ipv4 name GUEST-LAN rule 2 action 'drop' +set firewall ipv4 name GUEST-LAN rule 2 log +set firewall ipv4 name GUEST-LAN rule 2 state 'invalid' +set firewall ipv4 name GUEST-LOCAL default-action 'drop' +set firewall ipv4 name GUEST-LOCAL default-log +set firewall ipv4 name GUEST-LOCAL rule 1 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 1 state 'established' +set firewall ipv4 name GUEST-LOCAL rule 1 state 'related' +set firewall ipv4 name GUEST-LOCAL rule 2 action 'drop' +set firewall ipv4 name GUEST-LOCAL rule 2 log +set firewall ipv4 name GUEST-LOCAL rule 2 state 'invalid' +set firewall ipv4 name GUEST-LOCAL rule 10 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 10 description 'DNS' +set firewall ipv4 name GUEST-LOCAL rule 10 destination address '172.31.0.254' +set firewall ipv4 name GUEST-LOCAL rule 10 destination port '53' +set firewall ipv4 name GUEST-LOCAL rule 10 protocol 'tcp_udp' +set firewall ipv4 name GUEST-LOCAL rule 11 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 11 description 'DHCP' +set firewall ipv4 name GUEST-LOCAL rule 11 destination port '67' +set firewall ipv4 name GUEST-LOCAL rule 11 protocol 'udp' +set firewall ipv4 name GUEST-LOCAL rule 15 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 15 destination address '172.31.0.254' +set firewall ipv4 name GUEST-LOCAL rule 15 protocol 'icmp' +set firewall ipv4 name GUEST-LOCAL rule 200 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 200 description 'MCAST relay' +set firewall ipv4 name GUEST-LOCAL rule 200 destination address '224.0.0.251' +set firewall ipv4 name GUEST-LOCAL rule 200 destination port '5353' +set firewall ipv4 name GUEST-LOCAL rule 200 protocol 'udp' +set firewall ipv4 name GUEST-LOCAL rule 210 action 'return' +set firewall ipv4 name GUEST-LOCAL rule 210 description 'AUDIO-STREAM Broadcast' +set firewall ipv4 name GUEST-LOCAL rule 210 destination port '1900' +set firewall ipv4 name GUEST-LOCAL rule 210 protocol 'udp' +set firewall ipv4 name GUEST-WAN default-action 'drop' +set firewall ipv4 name GUEST-WAN default-log +set firewall ipv4 name GUEST-WAN rule 1 action 'return' +set firewall ipv4 name GUEST-WAN rule 1 state 'established' +set firewall ipv4 name GUEST-WAN rule 1 state 'related' +set firewall ipv4 name GUEST-WAN rule 2 action 'drop' +set firewall ipv4 name GUEST-WAN rule 2 log +set firewall ipv4 name GUEST-WAN rule 2 state 'invalid' +set firewall ipv4 name GUEST-WAN rule 25 action 'return' +set firewall ipv4 name GUEST-WAN rule 25 description 'SMTP' +set firewall ipv4 name GUEST-WAN rule 25 destination port '25,587' +set firewall ipv4 name GUEST-WAN rule 25 protocol 'tcp' +set firewall ipv4 name GUEST-WAN rule 53 action 'return' +set firewall ipv4 name GUEST-WAN rule 53 destination port '53' +set firewall ipv4 name GUEST-WAN rule 53 protocol 'tcp_udp' +set firewall ipv4 name GUEST-WAN rule 60 action 'return' +set firewall ipv4 name GUEST-WAN rule 60 source address '172.31.0.200' +set firewall ipv4 name GUEST-WAN rule 80 action 'return' +set firewall ipv4 name GUEST-WAN rule 80 source address '172.31.0.200' +set firewall ipv4 name GUEST-WAN rule 100 action 'return' +set firewall ipv4 name GUEST-WAN rule 100 protocol 'icmp' +set firewall ipv4 name GUEST-WAN rule 110 action 'return' +set firewall ipv4 name GUEST-WAN rule 110 description 'POP3' +set firewall ipv4 name GUEST-WAN rule 110 destination port '110,995' +set firewall ipv4 name GUEST-WAN rule 110 limit rate '10/minute' +set firewall ipv4 name GUEST-WAN rule 110 protocol 'tcp' +set firewall ipv4 name GUEST-WAN rule 123 action 'return' +set firewall ipv4 name GUEST-WAN rule 123 description 'NTP Client' +set firewall ipv4 name GUEST-WAN rule 123 destination port '123' +set firewall ipv4 name GUEST-WAN rule 123 protocol 'udp' +set firewall ipv4 name GUEST-WAN rule 143 action 'return' +set firewall ipv4 name GUEST-WAN rule 143 description 'IMAP' +set firewall ipv4 name GUEST-WAN rule 143 destination port '143,993' +set firewall ipv4 name GUEST-WAN rule 143 protocol 'tcp' +set firewall ipv4 name GUEST-WAN rule 200 action 'return' +set firewall ipv4 name GUEST-WAN rule 200 destination port '80,443' +set firewall ipv4 name GUEST-WAN rule 200 protocol 'tcp' +set firewall ipv4 name GUEST-WAN rule 500 action 'return' +set firewall ipv4 name GUEST-WAN rule 500 description 'L2TP IPSec' +set firewall ipv4 name GUEST-WAN rule 500 destination port '500,4500' +set firewall ipv4 name GUEST-WAN rule 500 protocol 'udp' +set firewall ipv4 name GUEST-WAN rule 600 action 'return' +set firewall ipv4 name GUEST-WAN rule 600 destination port '5222-5224' +set firewall ipv4 name GUEST-WAN rule 600 protocol 'tcp' +set firewall ipv4 name GUEST-WAN rule 601 action 'return' +set firewall ipv4 name GUEST-WAN rule 601 destination port '3478-3497,4500,16384-16387,16393-16402' +set firewall ipv4 name GUEST-WAN rule 601 protocol 'udp' +set firewall ipv4 name GUEST-WAN rule 1000 action 'return' +set firewall ipv4 name GUEST-WAN rule 1000 source address '172.31.0.184' +set firewall ipv4 name IOT-GUEST default-action 'drop' +set firewall ipv4 name IOT-GUEST default-log +set firewall ipv4 name IOT-GUEST rule 1 action 'return' +set firewall ipv4 name IOT-GUEST rule 1 state 'established' +set firewall ipv4 name IOT-GUEST rule 1 state 'related' +set firewall ipv4 name IOT-GUEST rule 2 action 'drop' +set firewall ipv4 name IOT-GUEST rule 2 log +set firewall ipv4 name IOT-GUEST rule 2 state 'invalid' +set firewall ipv4 name IOT-GUEST rule 100 action 'return' +set firewall ipv4 name IOT-GUEST rule 100 description 'MEDIA-STREAMING-CLIENTS Devices to IOT' +set firewall ipv4 name IOT-GUEST rule 100 protocol 'tcp_udp' +set firewall ipv4 name IOT-GUEST rule 100 source group address-group 'MEDIA-STREAMING-CLIENTS' +set firewall ipv4 name IOT-GUEST rule 110 action 'return' +set firewall ipv4 name IOT-GUEST rule 110 description 'AUDIO-STREAM Devices to IOT' +set firewall ipv4 name IOT-GUEST rule 110 protocol 'tcp_udp' +set firewall ipv4 name IOT-GUEST rule 110 source group address-group 'AUDIO-STREAM' +set firewall ipv4 name IOT-GUEST rule 200 action 'return' +set firewall ipv4 name IOT-GUEST rule 200 description 'MCAST relay' +set firewall ipv4 name IOT-GUEST rule 200 destination address '224.0.0.251' +set firewall ipv4 name IOT-GUEST rule 200 destination port '5353' +set firewall ipv4 name IOT-GUEST rule 200 protocol 'udp' +set firewall ipv4 name IOT-GUEST rule 300 action 'return' +set firewall ipv4 name IOT-GUEST rule 300 description 'BCAST relay' +set firewall ipv4 name IOT-GUEST rule 300 destination port '1900' +set firewall ipv4 name IOT-GUEST rule 300 protocol 'udp' +set firewall ipv4 name IOT-LAN default-action 'drop' +set firewall ipv4 name IOT-LAN default-log +set firewall ipv4 name IOT-LAN rule 1 action 'return' +set firewall ipv4 name IOT-LAN rule 1 state 'established' +set firewall ipv4 name IOT-LAN rule 1 state 'related' +set firewall ipv4 name IOT-LAN rule 2 action 'drop' +set firewall ipv4 name IOT-LAN rule 2 log +set firewall ipv4 name IOT-LAN rule 2 state 'invalid' +set firewall ipv4 name IOT-LAN rule 100 action 'return' +set firewall ipv4 name IOT-LAN rule 100 description 'AppleTV to LAN' +set firewall ipv4 name IOT-LAN rule 100 destination group port-group 'SMART-TV-PORTS' +set firewall ipv4 name IOT-LAN rule 100 protocol 'tcp_udp' +set firewall ipv4 name IOT-LAN rule 100 source group address-group 'MEDIA-STREAMING-CLIENTS' +set firewall ipv4 name IOT-LAN rule 110 action 'return' +set firewall ipv4 name IOT-LAN rule 110 description 'AUDIO-STREAM Devices to LAN' +set firewall ipv4 name IOT-LAN rule 110 protocol 'tcp_udp' +set firewall ipv4 name IOT-LAN rule 110 source group address-group 'AUDIO-STREAM' +set firewall ipv4 name IOT-LOCAL default-action 'drop' +set firewall ipv4 name IOT-LOCAL default-log +set firewall ipv4 name IOT-LOCAL rule 1 action 'return' +set firewall ipv4 name IOT-LOCAL rule 1 state 'established' +set firewall ipv4 name IOT-LOCAL rule 1 state 'related' +set firewall ipv4 name IOT-LOCAL rule 2 action 'drop' +set firewall ipv4 name IOT-LOCAL rule 2 log +set firewall ipv4 name IOT-LOCAL rule 2 state 'invalid' +set firewall ipv4 name IOT-LOCAL rule 10 action 'return' +set firewall ipv4 name IOT-LOCAL rule 10 description 'DNS' +set firewall ipv4 name IOT-LOCAL rule 10 destination address '172.16.254.30' +set firewall ipv4 name IOT-LOCAL rule 10 destination port '53' +set firewall ipv4 name IOT-LOCAL rule 10 protocol 'tcp_udp' +set firewall ipv4 name IOT-LOCAL rule 11 action 'return' +set firewall ipv4 name IOT-LOCAL rule 11 description 'DHCP' +set firewall ipv4 name IOT-LOCAL rule 11 destination port '67' +set firewall ipv4 name IOT-LOCAL rule 11 protocol 'udp' +set firewall ipv4 name IOT-LOCAL rule 15 action 'return' +set firewall ipv4 name IOT-LOCAL rule 15 destination address '172.16.35.254' +set firewall ipv4 name IOT-LOCAL rule 15 protocol 'icmp' +set firewall ipv4 name IOT-LOCAL rule 200 action 'return' +set firewall ipv4 name IOT-LOCAL rule 200 description 'MCAST relay' +set firewall ipv4 name IOT-LOCAL rule 200 destination address '224.0.0.251' +set firewall ipv4 name IOT-LOCAL rule 200 destination port '5353' +set firewall ipv4 name IOT-LOCAL rule 200 protocol 'udp' +set firewall ipv4 name IOT-LOCAL rule 201 action 'return' +set firewall ipv4 name IOT-LOCAL rule 201 description 'MCAST relay' +set firewall ipv4 name IOT-LOCAL rule 201 destination address '172.16.35.254' +set firewall ipv4 name IOT-LOCAL rule 201 destination port '5353' +set firewall ipv4 name IOT-LOCAL rule 201 protocol 'udp' +set firewall ipv4 name IOT-LOCAL rule 210 action 'return' +set firewall ipv4 name IOT-LOCAL rule 210 description 'AUDIO-STREAM Broadcast' +set firewall ipv4 name IOT-LOCAL rule 210 destination port '1900,1902,6969' +set firewall ipv4 name IOT-LOCAL rule 210 protocol 'udp' +set firewall ipv4 name IOT-WAN default-action 'return' +set firewall ipv4 name LAN-DMZ default-action 'drop' +set firewall ipv4 name LAN-DMZ default-log +set firewall ipv4 name LAN-DMZ rule 1 action 'return' +set firewall ipv4 name LAN-DMZ rule 1 state 'established' +set firewall ipv4 name LAN-DMZ rule 1 state 'related' +set firewall ipv4 name LAN-DMZ rule 2 action 'drop' +set firewall ipv4 name LAN-DMZ rule 2 log +set firewall ipv4 name LAN-DMZ rule 2 state 'invalid' +set firewall ipv4 name LAN-DMZ rule 22 action 'return' +set firewall ipv4 name LAN-DMZ rule 22 description 'SSH into DMZ' +set firewall ipv4 name LAN-DMZ rule 22 destination port '22' +set firewall ipv4 name LAN-DMZ rule 22 protocol 'tcp' +set firewall ipv4 name LAN-DMZ rule 100 action 'return' +set firewall ipv4 name LAN-DMZ rule 100 destination group address-group 'DMZ-WEBSERVER' +set firewall ipv4 name LAN-DMZ rule 100 destination port '22,80,443' +set firewall ipv4 name LAN-DMZ rule 100 protocol 'tcp' +set firewall ipv4 name LAN-GUEST default-action 'drop' +set firewall ipv4 name LAN-GUEST default-log +set firewall ipv4 name LAN-GUEST rule 1 action 'return' +set firewall ipv4 name LAN-GUEST rule 1 state 'established' +set firewall ipv4 name LAN-GUEST rule 1 state 'related' +set firewall ipv4 name LAN-GUEST rule 2 action 'drop' +set firewall ipv4 name LAN-GUEST rule 2 log +set firewall ipv4 name LAN-GUEST rule 2 state 'invalid' +set firewall ipv4 name LAN-IOT default-action 'return' +set firewall ipv4 name LAN-LOCAL default-action 'return' +set firewall ipv4 name LAN-WAN default-action 'return' +set firewall ipv4 name LOCAL-DMZ default-action 'drop' +set firewall ipv4 name LOCAL-DMZ default-log +set firewall ipv4 name LOCAL-DMZ rule 1 action 'return' +set firewall ipv4 name LOCAL-DMZ rule 1 state 'established' +set firewall ipv4 name LOCAL-DMZ rule 1 state 'related' +set firewall ipv4 name LOCAL-DMZ rule 2 action 'drop' +set firewall ipv4 name LOCAL-DMZ rule 2 log +set firewall ipv4 name LOCAL-DMZ rule 2 state 'invalid' +set firewall ipv4 name LOCAL-GUEST default-action 'drop' +set firewall ipv4 name LOCAL-GUEST default-log +set firewall ipv4 name LOCAL-GUEST rule 1 action 'return' +set firewall ipv4 name LOCAL-GUEST rule 1 state 'established' +set firewall ipv4 name LOCAL-GUEST rule 1 state 'related' +set firewall ipv4 name LOCAL-GUEST rule 2 action 'drop' +set firewall ipv4 name LOCAL-GUEST rule 2 log +set firewall ipv4 name LOCAL-GUEST rule 2 state 'invalid' +set firewall ipv4 name LOCAL-GUEST rule 5 action 'return' +set firewall ipv4 name LOCAL-GUEST rule 5 protocol 'icmp' +set firewall ipv4 name LOCAL-GUEST rule 200 action 'return' +set firewall ipv4 name LOCAL-GUEST rule 200 description 'MCAST relay' +set firewall ipv4 name LOCAL-GUEST rule 200 destination address '224.0.0.251' +set firewall ipv4 name LOCAL-GUEST rule 200 destination port '5353' +set firewall ipv4 name LOCAL-GUEST rule 200 protocol 'udp' +set firewall ipv4 name LOCAL-GUEST rule 300 action 'return' +set firewall ipv4 name LOCAL-GUEST rule 300 description 'BCAST relay' +set firewall ipv4 name LOCAL-GUEST rule 300 destination port '1900' +set firewall ipv4 name LOCAL-GUEST rule 300 protocol 'udp' +set firewall ipv4 name LOCAL-IOT default-action 'drop' +set firewall ipv4 name LOCAL-IOT default-log +set firewall ipv4 name LOCAL-IOT rule 1 action 'return' +set firewall ipv4 name LOCAL-IOT rule 1 state 'established' +set firewall ipv4 name LOCAL-IOT rule 1 state 'related' +set firewall ipv4 name LOCAL-IOT rule 2 action 'drop' +set firewall ipv4 name LOCAL-IOT rule 2 log +set firewall ipv4 name LOCAL-IOT rule 2 state 'invalid' +set firewall ipv4 name LOCAL-IOT rule 5 action 'return' +set firewall ipv4 name LOCAL-IOT rule 5 protocol 'icmp' +set firewall ipv4 name LOCAL-IOT rule 200 action 'return' +set firewall ipv4 name LOCAL-IOT rule 200 description 'MCAST relay' +set firewall ipv4 name LOCAL-IOT rule 200 destination address '224.0.0.251' +set firewall ipv4 name LOCAL-IOT rule 200 destination port '5353' +set firewall ipv4 name LOCAL-IOT rule 200 protocol 'udp' +set firewall ipv4 name LOCAL-IOT rule 300 action 'return' +set firewall ipv4 name LOCAL-IOT rule 300 description 'BCAST relay' +set firewall ipv4 name LOCAL-IOT rule 300 destination port '1900,6969' +set firewall ipv4 name LOCAL-IOT rule 300 protocol 'udp' +set firewall ipv4 name LOCAL-LAN default-action 'return' +set firewall ipv4 name LOCAL-WAN default-action 'drop' +set firewall ipv4 name LOCAL-WAN default-log +set firewall ipv4 name LOCAL-WAN rule 1 action 'return' +set firewall ipv4 name LOCAL-WAN rule 1 state 'established' +set firewall ipv4 name LOCAL-WAN rule 1 state 'related' +set firewall ipv4 name LOCAL-WAN rule 2 action 'drop' +set firewall ipv4 name LOCAL-WAN rule 2 log +set firewall ipv4 name LOCAL-WAN rule 2 state 'invalid' +set firewall ipv4 name LOCAL-WAN rule 10 action 'return' +set firewall ipv4 name LOCAL-WAN rule 10 protocol 'icmp' +set firewall ipv4 name LOCAL-WAN rule 50 action 'return' +set firewall ipv4 name LOCAL-WAN rule 50 description 'DNS' +set firewall ipv4 name LOCAL-WAN rule 50 destination port '53' +set firewall ipv4 name LOCAL-WAN rule 50 protocol 'tcp_udp' +set firewall ipv4 name LOCAL-WAN rule 80 action 'return' +set firewall ipv4 name LOCAL-WAN rule 80 destination port '80,443' +set firewall ipv4 name LOCAL-WAN rule 80 protocol 'tcp' +set firewall ipv4 name LOCAL-WAN rule 123 action 'return' +set firewall ipv4 name LOCAL-WAN rule 123 description 'NTP' +set firewall ipv4 name LOCAL-WAN rule 123 destination port '123' +set firewall ipv4 name LOCAL-WAN rule 123 protocol 'udp' +set firewall ipv4 name WAN-DMZ default-action 'drop' +set firewall ipv4 name WAN-DMZ default-log +set firewall ipv4 name WAN-DMZ rule 1 action 'return' +set firewall ipv4 name WAN-DMZ rule 1 state 'established' +set firewall ipv4 name WAN-DMZ rule 1 state 'related' +set firewall ipv4 name WAN-DMZ rule 2 action 'drop' +set firewall ipv4 name WAN-DMZ rule 2 log +set firewall ipv4 name WAN-DMZ rule 2 state 'invalid' +set firewall ipv4 name WAN-DMZ rule 100 action 'return' +set firewall ipv4 name WAN-DMZ rule 100 destination address '172.16.36.10' +set firewall ipv4 name WAN-DMZ rule 100 destination port '80,443' +set firewall ipv4 name WAN-DMZ rule 100 protocol 'tcp' +set firewall ipv4 name WAN-GUEST default-action 'drop' +set firewall ipv4 name WAN-GUEST default-log +set firewall ipv4 name WAN-GUEST rule 1 action 'return' +set firewall ipv4 name WAN-GUEST rule 1 state 'established' +set firewall ipv4 name WAN-GUEST rule 1 state 'related' +set firewall ipv4 name WAN-GUEST rule 2 action 'drop' +set firewall ipv4 name WAN-GUEST rule 2 log +set firewall ipv4 name WAN-GUEST rule 2 state 'invalid' +set firewall ipv4 name WAN-GUEST rule 1000 action 'return' +set firewall ipv4 name WAN-GUEST rule 1000 destination address '172.31.0.184' +set firewall ipv4 name WAN-GUEST rule 8000 action 'return' +set firewall ipv4 name WAN-GUEST rule 8000 destination address '172.31.0.200' +set firewall ipv4 name WAN-GUEST rule 8000 destination port '10000' +set firewall ipv4 name WAN-GUEST rule 8000 protocol 'udp' +set firewall ipv4 name WAN-IOT default-action 'drop' +set firewall ipv4 name WAN-IOT default-log +set firewall ipv4 name WAN-IOT rule 1 action 'return' +set firewall ipv4 name WAN-IOT rule 1 state 'established' +set firewall ipv4 name WAN-IOT rule 1 state 'related' +set firewall ipv4 name WAN-IOT rule 2 action 'drop' +set firewall ipv4 name WAN-IOT rule 2 log +set firewall ipv4 name WAN-IOT rule 2 state 'invalid' +set firewall ipv4 name WAN-LAN default-action 'drop' +set firewall ipv4 name WAN-LAN default-log +set firewall ipv4 name WAN-LAN rule 1 action 'return' +set firewall ipv4 name WAN-LAN rule 1 state 'established' +set firewall ipv4 name WAN-LAN rule 1 state 'related' +set firewall ipv4 name WAN-LAN rule 2 action 'drop' +set firewall ipv4 name WAN-LAN rule 2 log +set firewall ipv4 name WAN-LAN rule 2 state 'invalid' +set firewall ipv4 name WAN-LAN rule 1000 action 'return' +set firewall ipv4 name WAN-LAN rule 1000 destination address '172.16.33.40' +set firewall ipv4 name WAN-LAN rule 1000 destination port '3389' +set firewall ipv4 name WAN-LAN rule 1000 protocol 'tcp' +set firewall ipv4 name WAN-LAN rule 1000 source group network-group 'SSH-IN-ALLOW' +set firewall ipv4 name WAN-LOCAL default-action 'drop' +set firewall ipv4 name WAN-LOCAL default-log +set firewall ipv4 name WAN-LOCAL rule 1 action 'return' +set firewall ipv4 name WAN-LOCAL rule 1 state 'established' +set firewall ipv4 name WAN-LOCAL rule 1 state 'related' +set firewall ipv4 name WAN-LOCAL rule 2 action 'drop' +set firewall ipv4 name WAN-LOCAL rule 2 log +set firewall ipv4 name WAN-LOCAL rule 2 state 'invalid' +set firewall ipv4 name WAN-LOCAL rule 22 action 'return' +set firewall ipv4 name WAN-LOCAL rule 22 destination port '22' +set firewall ipv4 name WAN-LOCAL rule 22 protocol 'tcp' +set firewall ipv4 name WAN-LOCAL rule 22 source group network-group 'SSH-IN-ALLOW' +set firewall ipv6 name ALLOW-ALL-6 default-action 'return' +set firewall ipv6 name ALLOW-BASIC-6 default-action 'drop' +set firewall ipv6 name ALLOW-BASIC-6 default-log +set firewall ipv6 name ALLOW-BASIC-6 rule 1 action 'return' +set firewall ipv6 name ALLOW-BASIC-6 rule 1 state 'established' +set firewall ipv6 name ALLOW-BASIC-6 rule 1 state 'related' +set firewall ipv6 name ALLOW-BASIC-6 rule 2 action 'drop' +set firewall ipv6 name ALLOW-BASIC-6 rule 2 state 'invalid' +set firewall ipv6 name ALLOW-BASIC-6 rule 10 action 'return' +set firewall ipv6 name ALLOW-BASIC-6 rule 10 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-BASIC-6 rule 15 action 'return' +set firewall ipv6 name ALLOW-BASIC-6 rule 15 icmpv6 type '1' +set firewall ipv6 name ALLOW-BASIC-6 rule 15 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-BASIC-6 rule 16 action 'return' +set firewall ipv6 name ALLOW-BASIC-6 rule 16 icmpv6 code '1' +set firewall ipv6 name ALLOW-BASIC-6 rule 16 icmpv6 type '1' +set firewall ipv6 name ALLOW-BASIC-6 rule 16 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-BASIC-6 rule 17 action 'return' +set firewall ipv6 name ALLOW-BASIC-6 rule 17 icmpv6 type-name 'destination-unreachable' +set firewall ipv6 name ALLOW-BASIC-6 rule 17 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 default-action 'drop' +set firewall ipv6 name ALLOW-ESTABLISHED-6 default-log +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 state 'established' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 1 state 'related' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 2 action 'drop' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 2 state 'invalid' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 destination group network-group 'LOCAL-ADDRESSES' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 10 source address 'fe80::/10' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 icmpv6 type-name 'echo-request' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 20 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 icmpv6 type-name 'destination-unreachable' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 21 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 icmpv6 type-name 'packet-too-big' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 22 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 icmpv6 type-name 'time-exceeded' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 23 protocol 'ipv6-icmp' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 action 'return' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 icmpv6 type-name 'parameter-problem' +set firewall ipv6 name ALLOW-ESTABLISHED-6 rule 24 protocol 'ipv6-icmp' +set firewall ipv6 name WAN-LOCAL-6 default-action 'drop' +set firewall ipv6 name WAN-LOCAL-6 default-log +set firewall ipv6 name WAN-LOCAL-6 rule 1 action 'return' +set firewall ipv6 name WAN-LOCAL-6 rule 1 state 'established' +set firewall ipv6 name WAN-LOCAL-6 rule 1 state 'related' +set firewall ipv6 name WAN-LOCAL-6 rule 2 action 'drop' +set firewall ipv6 name WAN-LOCAL-6 rule 2 state 'invalid' +set firewall ipv6 name WAN-LOCAL-6 rule 10 action 'return' +set firewall ipv6 name WAN-LOCAL-6 rule 10 destination address 'ff02::/64' +set firewall ipv6 name WAN-LOCAL-6 rule 10 protocol 'ipv6-icmp' +set firewall ipv6 name WAN-LOCAL-6 rule 10 source address 'fe80::/10' +set firewall ipv6 name WAN-LOCAL-6 rule 50 action 'return' +set firewall ipv6 name WAN-LOCAL-6 rule 50 description 'DHCPv6' +set firewall ipv6 name WAN-LOCAL-6 rule 50 destination address 'fe80::/10' +set firewall ipv6 name WAN-LOCAL-6 rule 50 destination port '546' +set firewall ipv6 name WAN-LOCAL-6 rule 50 protocol 'udp' +set firewall ipv6 name WAN-LOCAL-6 rule 50 source address 'fe80::/10' +set firewall ipv6 name WAN-LOCAL-6 rule 50 source port '547' +set firewall zone DMZ default-action 'drop' +set firewall zone DMZ from GUEST firewall name 'GUEST-DMZ' +set firewall zone DMZ from LAN firewall name 'LAN-DMZ' +set firewall zone DMZ from LOCAL firewall name 'LOCAL-DMZ' +set firewall zone DMZ from WAN firewall name 'WAN-DMZ' +set firewall zone DMZ interface 'eth0.50' +set firewall zone GUEST default-action 'drop' +set firewall zone GUEST from DMZ firewall name 'DMZ-GUEST' +set firewall zone GUEST from IOT firewall name 'IOT-GUEST' +set firewall zone GUEST from LAN firewall name 'LAN-GUEST' +set firewall zone GUEST from LOCAL firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone GUEST from LOCAL firewall name 'LOCAL-GUEST' +set firewall zone GUEST from WAN firewall ipv6-name 'ALLOW-ESTABLISHED-6' +set firewall zone GUEST from WAN firewall name 'WAN-GUEST' +set firewall zone GUEST interface 'eth0.20' +set firewall zone IOT default-action 'drop' +set firewall zone IOT from GUEST firewall name 'GUEST-IOT' +set firewall zone IOT from LAN firewall name 'LAN-IOT' +set firewall zone IOT from LOCAL firewall name 'LOCAL-IOT' +set firewall zone IOT from WAN firewall name 'WAN-IOT' +set firewall zone IOT interface 'eth0.35' +set firewall zone LAN default-action 'drop' +set firewall zone LAN from DMZ firewall name 'DMZ-LAN' +set firewall zone LAN from GUEST firewall name 'GUEST-LAN' +set firewall zone LAN from IOT firewall name 'IOT-LAN' +set firewall zone LAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone LAN from LOCAL firewall name 'LOCAL-LAN' +set firewall zone LAN from WAN firewall ipv6-name 'ALLOW-ESTABLISHED-6' +set firewall zone LAN from WAN firewall name 'WAN-LAN' +set firewall zone LAN interface 'eth0.5' +set firewall zone LAN interface 'eth0.10' +set firewall zone LAN interface 'eth0.100' +set firewall zone LAN interface 'eth0.201' +set firewall zone LAN interface 'eth0.202' +set firewall zone LAN interface 'eth0.203' +set firewall zone LAN interface 'eth0.204' +set firewall zone LOCAL default-action 'drop' +set firewall zone LOCAL from DMZ firewall name 'DMZ-LOCAL' +set firewall zone LOCAL from GUEST firewall ipv6-name 'ALLOW-ESTABLISHED-6' +set firewall zone LOCAL from GUEST firewall name 'GUEST-LOCAL' +set firewall zone LOCAL from IOT firewall name 'IOT-LOCAL' +set firewall zone LOCAL from LAN firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone LOCAL from LAN firewall name 'LAN-LOCAL' +set firewall zone LOCAL from WAN firewall ipv6-name 'WAN-LOCAL-6' +set firewall zone LOCAL from WAN firewall name 'WAN-LOCAL' +set firewall zone LOCAL local-zone +set firewall zone WAN default-action 'drop' +set firewall zone WAN from DMZ firewall name 'DMZ-WAN' +set firewall zone WAN from GUEST firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone WAN from GUEST firewall name 'GUEST-WAN' +set firewall zone WAN from IOT firewall name 'IOT-WAN' +set firewall zone WAN from LAN firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone WAN from LAN firewall name 'LAN-WAN' +set firewall zone WAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6' +set firewall zone WAN from LOCAL firewall name 'LOCAL-WAN' +set firewall zone WAN interface 'pppoe0' +set interfaces dummy dum0 address '172.16.254.30/32' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 vif 5 address '172.16.37.254/24' +set interfaces ethernet eth0 vif 10 address '172.16.33.254/24' +set interfaces ethernet eth0 vif 10 ip adjust-mss '1320' +set interfaces ethernet eth0 vif 10 ipv6 adjust-mss '1300' +set interfaces ethernet eth0 vif 20 address '172.31.0.254/24' +set interfaces ethernet eth0 vif 35 address '172.16.35.254/24' +set interfaces ethernet eth0 vif 50 address '172.16.36.254/24' +set interfaces ethernet eth0 vif 100 address '172.16.100.254/24' +set interfaces ethernet eth0 vif 201 address '172.18.201.254/24' +set interfaces ethernet eth0 vif 202 address '172.18.202.254/24' +set interfaces ethernet eth0 vif 203 address '172.18.203.254/24' +set interfaces ethernet eth0 vif 204 address '172.18.204.254/24' +set interfaces ethernet eth1 vif 7 description 'FTTH-PPPoE' +set interfaces loopback lo address '172.16.254.30/32' +set interfaces pppoe pppoe0 authentication password 'vyos' +set interfaces pppoe pppoe0 authentication username 'vyos' +set interfaces pppoe pppoe0 description 'FTTH 100/50MBit' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.20 address '1' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.20 sla-id '20' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56' +set interfaces pppoe pppoe0 ip adjust-mss '1452' +set interfaces pppoe pppoe0 ipv6 address autoconf +set interfaces pppoe pppoe0 ipv6 adjust-mss '1432' +set interfaces pppoe pppoe0 mtu '1492' +set interfaces pppoe pppoe0 no-peer-dns +set interfaces pppoe pppoe0 source-interface 'eth1.7' +set nat destination rule 100 description 'HTTP(S)' +set nat destination rule 100 destination port '80,443' +set nat destination rule 100 inbound-interface name 'pppoe0' +set nat destination rule 100 log +set nat destination rule 100 protocol 'tcp' +set nat destination rule 100 translation address '172.16.36.10' +set nat destination rule 1000 destination port '3389' +set nat destination rule 1000 disable +set nat destination rule 1000 inbound-interface name 'pppoe0' +set nat destination rule 1000 protocol 'tcp' +set nat destination rule 1000 translation address '172.16.33.40' +set nat destination rule 8000 destination port '10000' +set nat destination rule 8000 inbound-interface name 'pppoe0' +set nat destination rule 8000 log +set nat destination rule 8000 protocol 'udp' +set nat destination rule 8000 translation address '172.31.0.200' +set nat source rule 100 log +set nat source rule 100 outbound-interface name 'pppoe0' +set nat source rule 100 source address '172.16.32.0/19' +set nat source rule 100 translation address 'masquerade' +set nat source rule 200 outbound-interface name 'pppoe0' +set nat source rule 200 source address '172.16.100.0/24' +set nat source rule 200 translation address 'masquerade' +set nat source rule 300 outbound-interface name 'pppoe0' +set nat source rule 300 source address '172.31.0.0/24' +set nat source rule 300 translation address 'masquerade' +set nat source rule 400 outbound-interface name 'pppoe0' +set nat source rule 400 source address '172.18.200.0/21' +set nat source rule 400 translation address 'masquerade' +set protocols static route 10.0.0.0/8 blackhole distance '254' +set protocols static route 169.254.0.0/16 blackhole distance '254' +set protocols static route 172.16.0.0/12 blackhole distance '254' +set protocols static route 192.168.0.0/16 blackhole distance '254' +set protocols static route6 2000::/3 interface pppoe0 +set qos policy shaper QoS bandwidth '50mbit' +set qos policy shaper QoS default bandwidth '100%' +set qos policy shaper QoS default burst '15k' +set qos policy shaper QoS default queue-limit '1000' +set qos policy shaper QoS default queue-type 'fq-codel' +set service dhcp-server shared-network-name BACKBONE authoritative +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1.wue3 ip-address '172.16.37.231' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1.wue3 mac '18:e8:29:6c:c3:a5' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1' +set service dhcp-server shared-network-name GUEST authoritative +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.100' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host01 ip-address '172.31.0.200' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host01 mac '00:50:00:00:00:01' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host02 ip-address '172.31.0.184' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 static-mapping host02 mac '00:50:00:00:00:02' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2' +set service dhcp-server shared-network-name IOT authoritative +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 lease '86400' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option default-router '172.16.35.254' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option name-server '172.16.254.30' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 option ntp-server '172.16.254.30' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 range 0 start '172.16.35.101' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 range 0 stop '172.16.35.149' +set service dhcp-server shared-network-name IOT subnet 172.16.35.0/24 subnet-id '3' +set service dhcp-server shared-network-name LAN authoritative +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '4' +set service dns forwarding allow-from '172.16.0.0/12' +set service dns forwarding cache-size '0' +set service dns forwarding domain 16.172.in-addr.arpa addnta +set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10 +set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20 +set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.110.30 +set service dns forwarding domain 16.172.in-addr.arpa recursion-desired +set service dns forwarding domain 18.172.in-addr.arpa addnta +set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10 +set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20 +set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.110.30 +set service dns forwarding domain 18.172.in-addr.arpa recursion-desired +set service dns forwarding domain vyos.net addnta +set service dns forwarding domain vyos.net name-server 172.16.100.10 +set service dns forwarding domain vyos.net name-server 172.16.100.20 +set service dns forwarding domain vyos.net name-server 172.16.110.30 +set service dns forwarding domain vyos.net recursion-desired +set service dns forwarding ignore-hosts-file +set service dns forwarding listen-address '172.16.254.30' +set service dns forwarding listen-address '172.31.0.254' +set service dns forwarding negative-ttl '60' +set service lldp legacy-protocols cdp +set service lldp snmp +set service mdns repeater interface 'eth0.35' +set service mdns repeater interface 'eth0.10' +set service ntp allow-client address '172.16.0.0/12' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400' +set service router-advert interface eth0.20 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface eth0.20 prefix ::/64 valid-lifetime '5400' +set service snmp community fooBar authorization 'ro' +set service snmp community fooBar network '172.16.100.0/24' +set service snmp contact 'VyOS maintainers and contributors <maintainers@vyos.io>' +set service snmp listen-address 172.16.254.30 port '161' +set service snmp location 'The Internet' +set service ssh disable-host-validation +set service ssh port '22' +set system config-management commit-revisions '200' +set system conntrack expect-table-size '2048' +set system conntrack hash-size '32768' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sqlnet +set system conntrack modules tftp +set system conntrack table-size '262144' +set system conntrack timeout +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '172.16.254.30' +set system option ctrl-alt-delete 'ignore' +set system option reboot-on-panic +set system option startup-beep +set system syslog global facility all level 'debug' +set system syslog global facility local7 level 'debug' +set system syslog host 172.16.100.1 facility all level 'warning' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/dialup-router-medium-vpn b/smoketest/config-tests/dialup-router-medium-vpn index 8c221707f..67af456f4 100644 --- a/smoketest/config-tests/dialup-router-medium-vpn +++ b/smoketest/config-tests/dialup-router-medium-vpn @@ -25,18 +25,12 @@ set high-availability vrrp sync-group failover-group member 'LAN' set interfaces ethernet eth0 duplex 'auto' set interfaces ethernet eth0 mtu '9000' set interfaces ethernet eth0 offload gro -set interfaces ethernet eth0 offload gso -set interfaces ethernet eth0 offload sg -set interfaces ethernet eth0 offload tso set interfaces ethernet eth0 speed 'auto' set interfaces ethernet eth1 address '192.168.0.250/24' set interfaces ethernet eth1 duplex 'auto' set interfaces ethernet eth1 ip source-validation 'strict' set interfaces ethernet eth1 mtu '9000' set interfaces ethernet eth1 offload gro -set interfaces ethernet eth1 offload gso -set interfaces ethernet eth1 offload sg -set interfaces ethernet eth1 offload tso set interfaces ethernet eth1 speed 'auto' set interfaces loopback lo set interfaces openvpn vtun0 encryption ncp-ciphers 'aes256' @@ -130,6 +124,7 @@ set interfaces wireguard wg0 peer red persistent-keepalive '20' set interfaces wireguard wg0 peer red preshared-key 'CumyXX7osvUT9AwnS+m2TEfCaL0Ptc2LfuZ78Sujuk8=' set interfaces wireguard wg0 peer red public-key 'ALGWvMJCKpHF2tVH3hEIHqUe9iFfAmZATUUok/WQzks=' set interfaces wireguard wg0 port '7777' +set interfaces wireguard wg0 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0=' set interfaces wireguard wg1 address '10.89.90.2/30' set interfaces wireguard wg1 ip adjust-mss '1380' set interfaces wireguard wg1 peer sam address '192.0.2.45' @@ -140,6 +135,7 @@ set interfaces wireguard wg1 peer sam port '1200' set interfaces wireguard wg1 peer sam preshared-key 'XpFtzx2Z+nR8pBv9/sSf7I94OkZkVYTz0AeU5Q/QQUE=' set interfaces wireguard wg1 peer sam public-key 'v5zfKGvH6W/lfDXJ0en96lvKo1gfFxMUWxe02+Fj5BU=' set interfaces wireguard wg1 port '7778' +set interfaces wireguard wg1 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0=' set nat destination rule 50 destination port '49371' set nat destination rule 50 inbound-interface name 'pppoe0' set nat destination rule 50 protocol 'tcp_udp' @@ -295,9 +291,18 @@ set service ssh listen-address '192.168.0.1' set service ssh listen-address '192.168.10.1' set service ssh listen-address '192.168.0.250' set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp set system console device ttyS0 speed '115200' set system host-name 'vyos' set system ip arp table-size '1024' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' set system name-server '192.168.0.1' set system name-server 'pppoe0' set system option ctrl-alt-delete 'ignore' diff --git a/smoketest/config-tests/dialup-router-wireguard-ipv6 b/smoketest/config-tests/dialup-router-wireguard-ipv6 index 814a62d55..ff4bf89c2 100644 --- a/smoketest/config-tests/dialup-router-wireguard-ipv6 +++ b/smoketest/config-tests/dialup-router-wireguard-ipv6 @@ -1,207 +1,3 @@ -set interfaces dummy dum0 address '172.16.254.30/32' -set interfaces ethernet eth0 vif 10 address '172.16.33.254/24' -set interfaces ethernet eth0 vif 10 address '172.16.40.254/24' -set interfaces ethernet eth0 vif 5 address '172.16.37.254/24' -set interfaces ethernet eth0 vif 50 address '172.16.36.254/24' -set interfaces ethernet eth0 ring-buffer rx '256' -set interfaces ethernet eth0 ring-buffer tx '256' -set interfaces ethernet eth1 offload gro -set interfaces ethernet eth1 offload gso -set interfaces ethernet eth1 offload sg -set interfaces ethernet eth1 offload tso -set interfaces ethernet eth1 vif 20 address '172.31.0.254/24' -set interfaces ethernet eth2 disable -set interfaces ethernet eth2 offload gro -set interfaces ethernet eth2 offload gso -set interfaces ethernet eth2 offload sg -set interfaces ethernet eth2 offload tso -set interfaces ethernet eth3 offload gro -set interfaces ethernet eth3 offload gso -set interfaces ethernet eth3 offload sg -set interfaces ethernet eth3 offload tso -set interfaces ethernet eth3 ring-buffer rx '256' -set interfaces ethernet eth3 ring-buffer tx '256' -set interfaces ethernet eth3 vif 7 -set interfaces loopback lo address '172.16.254.30/32' -set interfaces pppoe pppoe0 authentication password 'vyos' -set interfaces pppoe pppoe0 authentication username 'vyos' -set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1' -set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10' -set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 address '1' -set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 sla-id '20' -set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56' -set interfaces pppoe pppoe0 ip adjust-mss '1452' -set interfaces pppoe pppoe0 ipv6 address autoconf -set interfaces pppoe pppoe0 ipv6 adjust-mss '1432' -set interfaces pppoe pppoe0 no-peer-dns -set interfaces pppoe pppoe0 source-interface 'eth3.7' -set interfaces wireguard wg100 address '172.16.252.128/31' -set interfaces wireguard wg100 mtu '1500' -set interfaces wireguard wg100 peer HR6 address '100.65.151.213' -set interfaces wireguard wg100 peer HR6 allowed-ips '0.0.0.0/0' -set interfaces wireguard wg100 peer HR6 port '10100' -set interfaces wireguard wg100 port '10100' -set interfaces wireguard wg200 address '172.16.252.130/31' -set interfaces wireguard wg200 mtu '1500' -set interfaces wireguard wg200 peer WH56 address '80.151.69.205' -set interfaces wireguard wg200 peer WH56 allowed-ips '0.0.0.0/0' -set interfaces wireguard wg200 peer WH56 port '10200' -set interfaces wireguard wg200 port '10200' -set interfaces wireguard wg666 address '172.29.0.1/31' -set interfaces wireguard wg666 mtu '1500' -set interfaces wireguard wg666 peer WH34 address '100.65.55.1' -set interfaces wireguard wg666 peer WH34 allowed-ips '0.0.0.0/0' -set interfaces wireguard wg666 peer WH34 port '10666' -set interfaces wireguard wg666 port '10666' -set protocols ospf area 0 network '172.16.37.0/24' -set protocols ospf area 0 network '172.16.254.30/32' -set protocols ospf area 0 network '172.18.202.0/24' -set protocols ospf area 0 network '172.18.203.0/24' -set protocols ospf area 0 network '172.18.204.0/24' -set protocols ospf interface eth0.5 authentication md5 key-id 10 md5-key 'ospf' -set protocols ospf interface eth0.5 dead-interval '40' -set protocols ospf interface eth0.5 hello-interval '10' -set protocols ospf interface eth0.5 passive disable -set protocols ospf interface eth0.5 priority '1' -set protocols ospf interface eth0.5 retransmit-interval '5' -set protocols ospf interface eth0.5 transmit-delay '1' -set protocols ospf log-adjacency-changes detail -set protocols ospf parameters router-id '172.16.254.30' -set protocols ospf default-information originate always -set protocols ospf default-information originate metric-type '2' -set protocols ospf redistribute connected metric-type '2' -set protocols ospf redistribute connected route-map 'MAP-OSPF-CONNECTED' -set protocols static route 10.0.0.0/8 blackhole distance '254' -set protocols static route 169.254.0.0/16 blackhole distance '254' -set protocols static route 172.16.0.0/12 blackhole distance '254' -set protocols static route 172.16.32.0/21 blackhole -set protocols static route 172.18.0.0/16 blackhole -set protocols static route 172.29.0.2/31 next-hop 172.29.0.0 -set protocols static route 192.168.0.0/16 blackhole distance '254' -set protocols static route 192.168.189.0/24 next-hop 172.29.0.0 -set protocols static route6 2000::/3 interface pppoe0 -set protocols bfd peer 172.16.252.129 -set protocols bfd peer 172.16.252.131 -set protocols bfd peer 172.18.254.201 -set protocols bgp address-family ipv4-unicast network 172.16.32.0/21 -set protocols bgp address-family ipv4-unicast network 172.16.100.0/24 -set protocols bgp address-family ipv4-unicast network 172.16.252.128/31 -set protocols bgp address-family ipv4-unicast network 172.16.252.130/31 -set protocols bgp address-family ipv4-unicast network 172.16.254.30/32 -set protocols bgp address-family ipv4-unicast network 172.18.0.0/16 -set protocols bgp neighbor 172.16.252.129 peer-group 'WIREGUARD' -set protocols bgp neighbor 172.16.252.131 peer-group 'WIREGUARD' -set protocols bgp neighbor 172.18.254.201 address-family ipv4-unicast nexthop-self -set protocols bgp neighbor 172.18.254.201 bfd -set protocols bgp neighbor 172.18.254.201 remote-as '64503' -set protocols bgp neighbor 172.18.254.201 update-source 'dum0' -set protocols bgp parameters log-neighbor-changes -set protocols bgp peer-group WIREGUARD address-family ipv4-unicast soft-reconfiguration inbound -set protocols bgp peer-group WIREGUARD bfd -set protocols bgp peer-group WIREGUARD remote-as 'external' -set protocols bgp system-as '64503' -set protocols bgp timers holdtime '30' -set protocols bgp timers keepalive '10' -set service lldp legacy-protocols cdp -set service lldp legacy-protocols edp -set service lldp legacy-protocols fdp -set service lldp legacy-protocols sonmp -set service lldp snmp -set service ntp allow-client address '172.16.0.0/12' -set service ntp server time1.vyos.net -set service ntp server time2.vyos.net -set service dhcp-server shared-network-name BACKBONE authoritative -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 ip-address '172.16.37.231' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 mac '02:00:00:00:ee:18' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 ip-address '172.16.37.232' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 mac '02:00:00:00:52:84' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 ip-address '172.16.37.233' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 mac '02:00:00:00:51:c0' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 ip-address '172.16.37.234' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 mac '02:00:00:00:e6:fc' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 ip-address '172.16.37.235' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 mac '02:00:00:00:c3:50' -set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1' -set service dhcp-server shared-network-name GUEST authoritative -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.101' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199' -set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2' -set service dhcp-server shared-network-name LAN authoritative -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four ip-address '172.16.33.214' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four mac '02:00:00:00:c4:33' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one ip-address '172.16.33.221' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one mac '02:00:00:00:eb:a6' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three ip-address '172.16.33.212' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three mac '02:00:00:00:12:c7' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two ip-address '172.16.33.211' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two mac '02:00:00:00:58:90' -set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '3' -set service dns dynamic name service-vyos-pppoe0 address interface 'pppoe0' -set service dns dynamic name service-vyos-pppoe0 host-name 'r1.vyos.net' -set service dns dynamic name service-vyos-pppoe0 password 'vyos' -set service dns dynamic name service-vyos-pppoe0 protocol 'dyndns2' -set service dns dynamic name service-vyos-pppoe0 server 'dyndns.vyos.io' -set service dns dynamic name service-vyos-pppoe0 username 'vyos-vyos' -set service dns forwarding allow-from '172.16.0.0/12' -set service dns forwarding domain 16.172.in-addr.arpa addnta -set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10 -set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20 -set service dns forwarding domain 16.172.in-addr.arpa recursion-desired -set service dns forwarding domain 18.172.in-addr.arpa addnta -set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10 -set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20 -set service dns forwarding domain 18.172.in-addr.arpa recursion-desired -set service dns forwarding domain vyos.net addnta -set service dns forwarding domain vyos.net name-server 172.16.100.10 -set service dns forwarding domain vyos.net name-server 172.16.100.20 -set service dns forwarding domain vyos.net recursion-desired -set service dns forwarding ignore-hosts-file -set service dns forwarding listen-address '172.16.254.30' -set service dns forwarding listen-address '172.31.0.254' -set service dns forwarding negative-ttl '60' -set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700' -set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400' -set service router-advert interface eth1.20 prefix ::/64 preferred-lifetime '2700' -set service router-advert interface eth1.20 prefix ::/64 valid-lifetime '5400' -set service snmp community ro-community authorization 'ro' -set service snmp community ro-community network '172.16.100.0/24' -set service snmp contact 'VyOS' -set service snmp listen-address 172.16.254.30 port '161' -set service snmp location 'CLOUD' -set system conntrack expect-table-size '2048' -set system conntrack hash-size '32768' -set system conntrack table-size '262144' -set system domain-name 'vyos.net' -set system host-name 'r1' -set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' -set system login user vyos authentication plaintext-password '' -set system option ctrl-alt-delete 'ignore' -set system option performance 'latency' -set system option startup-beep -set system syslog global facility all level 'debug' -set system syslog host 172.16.100.1 facility all level 'warning' -set system console device ttyS0 speed '115200' set firewall global-options all-ping 'enable' set firewall global-options broadcast-ping 'disable' set firewall global-options ip-src-route 'disable' @@ -634,6 +430,67 @@ set firewall zone WAN from LOCAL firewall ipv6-name 'ALLOW-ALL-6' set firewall zone WAN from LOCAL firewall name 'LOCAL-WAN' set firewall zone WAN interface 'pppoe0' set firewall zone WAN interface 'wg666' +set interfaces dummy dum0 address '172.16.254.30/32' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 ring-buffer rx '256' +set interfaces ethernet eth0 ring-buffer tx '256' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 vif 5 address '172.16.37.254/24' +set interfaces ethernet eth0 vif 10 address '172.16.33.254/24' +set interfaces ethernet eth0 vif 10 address '172.16.40.254/24' +set interfaces ethernet eth0 vif 50 address '172.16.36.254/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth1 vif 20 address '172.31.0.254/24' +set interfaces ethernet eth2 disable +set interfaces ethernet eth2 duplex 'auto' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth2 speed 'auto' +set interfaces ethernet eth3 duplex 'auto' +set interfaces ethernet eth3 offload gro +set interfaces ethernet eth3 ring-buffer rx '256' +set interfaces ethernet eth3 ring-buffer tx '256' +set interfaces ethernet eth3 speed 'auto' +set interfaces ethernet eth3 vif 7 +set interfaces loopback lo address '172.16.254.30/32' +set interfaces pppoe pppoe0 authentication password 'vyos' +set interfaces pppoe pppoe0 authentication username 'vyos' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 address '1' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth0.10 sla-id '10' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 address '1' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 interface eth1.20 sla-id '20' +set interfaces pppoe pppoe0 dhcpv6-options pd 0 length '56' +set interfaces pppoe pppoe0 ip adjust-mss '1452' +set interfaces pppoe pppoe0 ipv6 address autoconf +set interfaces pppoe pppoe0 ipv6 adjust-mss '1432' +set interfaces pppoe pppoe0 no-peer-dns +set interfaces pppoe pppoe0 source-interface 'eth3.7' +set interfaces wireguard wg100 address '172.16.252.128/31' +set interfaces wireguard wg100 mtu '1500' +set interfaces wireguard wg100 peer HR6 address '100.65.151.213' +set interfaces wireguard wg100 peer HR6 allowed-ips '0.0.0.0/0' +set interfaces wireguard wg100 peer HR6 port '10100' +set interfaces wireguard wg100 peer HR6 public-key 'yLpi+UZuI019bmWH2h5fX3gStbpPPPLgEoYMyrdkOnQ=' +set interfaces wireguard wg100 port '10100' +set interfaces wireguard wg100 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0=' +set interfaces wireguard wg200 address '172.16.252.130/31' +set interfaces wireguard wg200 mtu '1500' +set interfaces wireguard wg200 peer WH56 address '80.151.69.205' +set interfaces wireguard wg200 peer WH56 allowed-ips '0.0.0.0/0' +set interfaces wireguard wg200 peer WH56 port '10200' +set interfaces wireguard wg200 peer WH56 public-key 'XQbkj6vnKKBJfJQyThXysU0iGxCvEOEb31kpaZgkrD8=' +set interfaces wireguard wg200 port '10200' +set interfaces wireguard wg200 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0=' +set interfaces wireguard wg666 address '172.29.0.1/31' +set interfaces wireguard wg666 mtu '1500' +set interfaces wireguard wg666 peer WH34 address '100.65.55.1' +set interfaces wireguard wg666 peer WH34 allowed-ips '0.0.0.0/0' +set interfaces wireguard wg666 peer WH34 port '10666' +set interfaces wireguard wg666 peer WH34 public-key 'yaTN4+xAafKM04D+Baeg5GWfbdaw35TE9HQivwRgAk0=' +set interfaces wireguard wg666 port '10666' +set interfaces wireguard wg666 private-key 'aGx+fvW916Ej7QRnBbW3QMoldhNv1u95/WHz45zDmF0=' set nat destination rule 8000 destination port '10000' set nat destination rule 8000 inbound-interface name 'pppoe0' set nat destination rule 8000 protocol 'udp' @@ -667,8 +524,174 @@ set policy route-map MAP-OSPF-CONNECTED rule 20 action 'permit' set policy route-map MAP-OSPF-CONNECTED rule 20 match interface 'eth0.10' set policy route-map MAP-OSPF-CONNECTED rule 40 action 'permit' set policy route-map MAP-OSPF-CONNECTED rule 40 match interface 'eth0.50' +set protocols bfd peer 172.16.252.129 +set protocols bfd peer 172.16.252.131 +set protocols bfd peer 172.18.254.201 +set protocols bgp address-family ipv4-unicast network 172.16.32.0/21 +set protocols bgp address-family ipv4-unicast network 172.16.100.0/24 +set protocols bgp address-family ipv4-unicast network 172.16.252.128/31 +set protocols bgp address-family ipv4-unicast network 172.16.252.130/31 +set protocols bgp address-family ipv4-unicast network 172.16.254.30/32 +set protocols bgp address-family ipv4-unicast network 172.18.0.0/16 +set protocols bgp neighbor 172.16.252.129 peer-group 'WIREGUARD' +set protocols bgp neighbor 172.16.252.131 peer-group 'WIREGUARD' +set protocols bgp neighbor 172.18.254.201 address-family ipv4-unicast nexthop-self +set protocols bgp neighbor 172.18.254.201 bfd +set protocols bgp neighbor 172.18.254.201 remote-as '64503' +set protocols bgp neighbor 172.18.254.201 update-source 'dum0' +set protocols bgp parameters log-neighbor-changes +set protocols bgp peer-group WIREGUARD address-family ipv4-unicast soft-reconfiguration inbound +set protocols bgp peer-group WIREGUARD bfd +set protocols bgp peer-group WIREGUARD remote-as 'external' +set protocols bgp system-as '64503' +set protocols bgp timers holdtime '30' +set protocols bgp timers keepalive '10' +set protocols ospf area 0 network '172.16.254.30/32' +set protocols ospf area 0 network '172.16.37.0/24' +set protocols ospf area 0 network '172.18.201.0/24' +set protocols ospf area 0 network '172.18.202.0/24' +set protocols ospf area 0 network '172.18.203.0/24' +set protocols ospf area 0 network '172.18.204.0/24' +set protocols ospf default-information originate always +set protocols ospf default-information originate metric-type '2' +set protocols ospf interface eth0.5 authentication md5 key-id 10 md5-key 'ospf' +set protocols ospf interface eth0.5 dead-interval '40' +set protocols ospf interface eth0.5 hello-interval '10' +set protocols ospf interface eth0.5 passive disable +set protocols ospf interface eth0.5 priority '1' +set protocols ospf interface eth0.5 retransmit-interval '5' +set protocols ospf interface eth0.5 transmit-delay '1' +set protocols ospf log-adjacency-changes detail +set protocols ospf parameters abr-type 'cisco' +set protocols ospf parameters router-id '172.16.254.30' +set protocols ospf passive-interface 'default' +set protocols ospf redistribute connected metric-type '2' +set protocols ospf redistribute connected route-map 'MAP-OSPF-CONNECTED' +set protocols static route 10.0.0.0/8 blackhole distance '254' +set protocols static route 169.254.0.0/16 blackhole distance '254' +set protocols static route 172.16.0.0/12 blackhole distance '254' +set protocols static route 172.16.32.0/21 blackhole +set protocols static route 172.18.0.0/16 blackhole +set protocols static route 172.29.0.2/31 next-hop 172.29.0.0 +set protocols static route 192.168.0.0/16 blackhole distance '254' +set protocols static route 192.168.189.0/24 next-hop 172.29.0.0 +set protocols static route6 2000::/3 interface pppoe0 set qos policy shaper QoS bandwidth '50mbit' set qos policy shaper QoS default bandwidth '100%' set qos policy shaper QoS default burst '15k' set qos policy shaper QoS default queue-limit '1000' set qos policy shaper QoS default queue-type 'fq-codel' +set service dhcp-server shared-network-name BACKBONE authoritative +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 lease '86400' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option default-router '172.16.37.254' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option name-server '172.16.254.30' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 option ntp-server '172.16.254.30' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 start '172.16.37.120' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 range 0 stop '172.16.37.149' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 ip-address '172.16.37.231' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP1 mac '02:00:00:00:ee:18' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 ip-address '172.16.37.232' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP2 mac '02:00:00:00:52:84' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 ip-address '172.16.37.233' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP3 mac '02:00:00:00:51:c0' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 ip-address '172.16.37.234' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP4 mac '02:00:00:00:e6:fc' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 ip-address '172.16.37.235' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 static-mapping AP5 mac '02:00:00:00:c3:50' +set service dhcp-server shared-network-name BACKBONE subnet 172.16.37.0/24 subnet-id '1' +set service dhcp-server shared-network-name GUEST authoritative +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 lease '86400' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option default-router '172.31.0.254' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 option name-server '172.31.0.254' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 start '172.31.0.101' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 range 0 stop '172.31.0.199' +set service dhcp-server shared-network-name GUEST subnet 172.31.0.0/24 subnet-id '2' +set service dhcp-server shared-network-name LAN authoritative +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 lease '86400' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option default-router '172.16.33.254' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option domain-search 'vyos.net' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option name-server '172.16.254.30' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 option ntp-server '172.16.254.30' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 start '172.16.33.100' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 range 0 stop '172.16.33.189' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four ip-address '172.16.33.214' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping four mac '02:00:00:00:c4:33' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one ip-address '172.16.33.221' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping one mac '02:00:00:00:eb:a6' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three ip-address '172.16.33.212' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping three mac '02:00:00:00:12:c7' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two ip-address '172.16.33.211' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 static-mapping two mac '02:00:00:00:58:90' +set service dhcp-server shared-network-name LAN subnet 172.16.33.0/24 subnet-id '3' +set service dns dynamic name service-vyos-pppoe0 address interface 'pppoe0' +set service dns dynamic name service-vyos-pppoe0 host-name 'r1.vyos.net' +set service dns dynamic name service-vyos-pppoe0 password 'vyos' +set service dns dynamic name service-vyos-pppoe0 protocol 'dyndns2' +set service dns dynamic name service-vyos-pppoe0 server 'dyndns.vyos.io' +set service dns dynamic name service-vyos-pppoe0 username 'vyos-vyos' +set service dns forwarding allow-from '172.16.0.0/12' +set service dns forwarding domain 16.172.in-addr.arpa addnta +set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.10 +set service dns forwarding domain 16.172.in-addr.arpa name-server 172.16.100.20 +set service dns forwarding domain 16.172.in-addr.arpa recursion-desired +set service dns forwarding domain 18.172.in-addr.arpa addnta +set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.10 +set service dns forwarding domain 18.172.in-addr.arpa name-server 172.16.100.20 +set service dns forwarding domain 18.172.in-addr.arpa recursion-desired +set service dns forwarding domain vyos.net addnta +set service dns forwarding domain vyos.net name-server 172.16.100.10 +set service dns forwarding domain vyos.net name-server 172.16.100.20 +set service dns forwarding domain vyos.net recursion-desired +set service dns forwarding ignore-hosts-file +set service dns forwarding listen-address '172.16.254.30' +set service dns forwarding listen-address '172.31.0.254' +set service dns forwarding negative-ttl '60' +set service lldp legacy-protocols cdp +set service lldp legacy-protocols edp +set service lldp legacy-protocols fdp +set service lldp legacy-protocols sonmp +set service lldp snmp +set service ntp allow-client address '172.16.0.0/12' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service router-advert interface eth0.10 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface eth0.10 prefix ::/64 valid-lifetime '5400' +set service router-advert interface eth1.20 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface eth1.20 prefix ::/64 valid-lifetime '5400' +set service snmp community ro-community authorization 'ro' +set service snmp community ro-community network '172.16.100.0/24' +set service snmp contact 'VyOS' +set service snmp listen-address 172.16.254.30 port '161' +set service snmp location 'CLOUD' +set service ssh disable-host-validation +set service ssh port '22' +set system config-management commit-revisions '200' +set system conntrack expect-table-size '2048' +set system conntrack hash-size '32768' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sqlnet +set system conntrack modules tftp +set system conntrack table-size '262144' +set system conntrack timeout +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'r1' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '172.16.254.30' +set system option ctrl-alt-delete 'ignore' +set system option performance 'latency' +set system option reboot-on-panic +set system option startup-beep +set system syslog global facility all level 'debug' +set system syslog global facility local7 level 'debug' +set system syslog host 172.16.100.1 facility all level 'warning' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/egp-igp-route-maps b/smoketest/config-tests/egp-igp-route-maps new file mode 100644 index 000000000..fc46d25ff --- /dev/null +++ b/smoketest/config-tests/egp-igp-route-maps @@ -0,0 +1,46 @@ +set interfaces ethernet eth0 address '192.0.2.1/25' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 address '192.0.2.129/25' +set interfaces ethernet eth1 address '2001:db8::1234/64' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set interfaces loopback lo +set policy route-map zebra-bgp rule 10 action 'permit' +set policy route-map zebra-isis rule 10 action 'permit' +set policy route-map zebra-ospf rule 10 action 'permit' +set policy route-map zebra-ospfv3 rule 10 action 'permit' +set policy route-map zebra-ripng rule 10 action 'permit' +set policy route-map zebra-static rule 10 action 'permit' +set protocols bgp system-as '100' +set protocols isis interface eth0 +set protocols isis net '49.0001.1921.6800.1002.00' +set protocols ospf area 0 network '192.0.2.0/25' +set protocols ospf area 0 network '192.0.2.128/25' +set protocols ospf interface eth0 passive disable +set protocols ospf interface eth1 passive disable +set protocols ospf log-adjacency-changes +set protocols ospf parameters abr-type 'cisco' +set protocols ospf parameters router-id '1.1.1.1' +set protocols ospf passive-interface 'default' +set protocols ospfv3 area 0 +set protocols ospfv3 interface eth1 area '0' +set protocols ospfv3 parameters router-id '1.1.1.1' +set protocols ripng interface eth1 +set protocols static +set system config-management commit-revisions '100' +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system ip protocol bgp route-map 'zebra-bgp' +set system ip protocol isis route-map 'zebra-isis' +set system ip protocol ospf route-map 'zebra-ospf' +set system ip protocol static route-map 'zebra-static' +set system ipv6 protocol ospfv3 route-map 'zebra-ospfv3' +set system ipv6 protocol ripng route-map 'zebra-ripng' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system logs logrotate messages max-size '1' +set system logs logrotate messages rotate '5' +set system name-server '192.168.0.1' +set system syslog global facility all level 'info' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/igmp-pim-small b/smoketest/config-tests/igmp-pim-small index 207c17d45..909c3d67b 100644 --- a/smoketest/config-tests/igmp-pim-small +++ b/smoketest/config-tests/igmp-pim-small @@ -1,5 +1,12 @@ +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' set interfaces ethernet eth1 address '100.64.0.1/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' set interfaces ethernet eth2 address '172.16.0.2/24' +set interfaces ethernet eth2 duplex 'auto' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth2 speed 'auto' set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.1' set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.2' set protocols pim interface eth1 igmp query-interval '1000' @@ -7,11 +14,24 @@ set protocols pim interface eth1 igmp query-max-response-time '30' set protocols pim interface eth1 igmp version '2' set protocols pim interface eth2 set protocols pim rp address 172.16.255.1 group '224.0.0.0/4' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' set service ntp server 0.pool.ntp.org set service ntp server 1.pool.ntp.org set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' set system domain-name 'vyos.io' set system host-name 'vyos' set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' set system login user vyos authentication plaintext-password '' -set system console device ttyS0 speed '115200' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/ipoe-server b/smoketest/config-tests/ipoe-server index fb32fdb14..f4a12f502 100644 --- a/smoketest/config-tests/ipoe-server +++ b/smoketest/config-tests/ipoe-server @@ -1,9 +1,10 @@ set interfaces ethernet eth0 address 'dhcp' set interfaces ethernet eth1 address '192.168.0.1/24' +set interfaces ethernet eth2 offload gro set interfaces loopback lo -set service ntp server time1.vyos.net -set service ntp server time2.vyos.net -set service ntp server time3.vyos.net +set nat source rule 100 outbound-interface name 'eth0' +set nat source rule 100 source address '192.168.0.0/24' +set nat source rule 100 translation address 'masquerade' set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 rate-limit download '1000' set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 rate-limit upload '500' set service ipoe-server authentication interface eth1 mac 08:00:27:2f:d8:06 vlan '100' @@ -25,11 +26,23 @@ set service ipoe-server name-server '10.10.1.1' set service ipoe-server name-server '10.10.1.2' set service ipoe-server name-server '2001:db8:aaa::' set service ipoe-server name-server '2001:db8:bbb::' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set service ssh set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' set system host-name 'vyos' set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' set system login user vyos authentication plaintext-password '' -set system console device ttyS0 speed '115200' -set nat source rule 100 outbound-interface name 'eth0' -set nat source rule 100 source address '192.168.0.0/24' -set nat source rule 100 translation address 'masquerade' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/ipv6-disable b/smoketest/config-tests/ipv6-disable new file mode 100644 index 000000000..40e34fa0c --- /dev/null +++ b/smoketest/config-tests/ipv6-disable @@ -0,0 +1,31 @@ +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 vif 201 address '172.18.201.10/24' +set interfaces ethernet eth0 vif 202 address '172.18.202.10/24' +set interfaces ethernet eth0 vif 203 address '172.18.203.10/24' +set interfaces ethernet eth0 vif 204 address '172.18.204.10/24' +set protocols static route 0.0.0.0/0 next-hop 172.18.201.254 distance '10' +set protocols static route 0.0.0.0/0 next-hop 172.18.202.254 distance '20' +set protocols static route 0.0.0.0/0 next-hop 172.18.203.254 distance '30' +set protocols static route 0.0.0.0/0 next-hop 172.18.204.254 distance '40' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 172.16.254.20 +set service ntp server 172.16.254.30 +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '172.16.254.20' +set system name-server '172.16.254.30' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/isis-small b/smoketest/config-tests/isis-small new file mode 100644 index 000000000..b322f4e29 --- /dev/null +++ b/smoketest/config-tests/isis-small @@ -0,0 +1,44 @@ +set interfaces dummy dum0 address '203.0.113.1/24' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 offload sg +set interfaces ethernet eth0 offload tso +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 address '192.0.2.1/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 offload sg +set interfaces ethernet eth1 offload tso +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth2 duplex 'auto' +set interfaces ethernet eth2 offload sg +set interfaces ethernet eth2 offload tso +set interfaces ethernet eth2 speed 'auto' +set interfaces ethernet eth3 duplex 'auto' +set interfaces ethernet eth3 offload sg +set interfaces ethernet eth3 offload tso +set interfaces ethernet eth3 speed 'auto' +set policy prefix-list EXPORT-ISIS rule 10 action 'permit' +set policy prefix-list EXPORT-ISIS rule 10 prefix '203.0.113.0/24' +set policy route-map EXPORT-ISIS rule 10 action 'permit' +set policy route-map EXPORT-ISIS rule 10 match ip address prefix-list 'EXPORT-ISIS' +set protocols isis interface eth1 bfd +set protocols isis net '49.0001.1921.6800.1002.00' +set protocols isis redistribute ipv4 connected level-2 route-map 'EXPORT-ISIS' +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.io' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/nat-basic b/smoketest/config-tests/nat-basic index 9fea08b02..471add3b3 100644 --- a/smoketest/config-tests/nat-basic +++ b/smoketest/config-tests/nat-basic @@ -1,25 +1,17 @@ -set interfaces ethernet eth0 offload rps +set interfaces bonding bond10 hash-policy 'layer3+4' +set interfaces bonding bond10 member interface 'eth2' +set interfaces bonding bond10 member interface 'eth3' +set interfaces bonding bond10 mode '802.3ad' +set interfaces bonding bond10 vif 50 address '192.168.189.1/24' set interfaces ethernet eth0 disable +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 offload rps set interfaces ethernet eth1 offload gro -set interfaces ethernet eth1 offload gso set interfaces ethernet eth1 offload rps -set interfaces ethernet eth1 offload sg -set interfaces ethernet eth1 offload tso set interfaces ethernet eth2 offload gro -set interfaces ethernet eth2 offload gso set interfaces ethernet eth2 offload rps -set interfaces ethernet eth2 offload sg -set interfaces ethernet eth2 offload tso set interfaces ethernet eth3 offload gro -set interfaces ethernet eth3 offload gso set interfaces ethernet eth3 offload rps -set interfaces ethernet eth3 offload sg -set interfaces ethernet eth3 offload tso -set interfaces bonding bond10 hash-policy 'layer3+4' -set interfaces bonding bond10 member interface 'eth2' -set interfaces bonding bond10 member interface 'eth3' -set interfaces bonding bond10 mode '802.3ad' -set interfaces bonding bond10 vif 50 address '192.168.189.1/24' set interfaces loopback lo set interfaces pppoe pppoe7 authentication password 'vyos' set interfaces pppoe pppoe7 authentication username 'vyos' @@ -31,30 +23,6 @@ set interfaces pppoe pppoe7 ipv6 adjust-mss '1432' set interfaces pppoe pppoe7 mtu '1492' set interfaces pppoe pppoe7 no-peer-dns set interfaces pppoe pppoe7 source-interface 'eth1' -set service lldp interface eth1 disable -set service ntp allow-client address '192.168.189.0/24' -set service ntp server time1.vyos.net -set service ntp server time2.vyos.net -set service ntp listen-address '192.168.189.1' -set service ssh dynamic-protection -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 lease '604800' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option default-router '192.168.189.1' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option domain-name 'vyos.net' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '1.1.1.1' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '9.9.9.9' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 start '192.168.189.20' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 stop '192.168.189.254' -set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 subnet-id '1' -set service router-advert interface bond10.50 prefix ::/64 preferred-lifetime '2700' -set service router-advert interface bond10.50 prefix ::/64 valid-lifetime '5400' -set system config-management commit-revisions '100' -set system domain-name 'vyos.net' -set system host-name 'R1' -set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' -set system login user vyos authentication plaintext-password '' -set system name-server '1.1.1.1' -set system name-server '9.9.9.9' -set system console device ttyS0 speed '115200' set nat destination rule 1000 destination port '3389' set nat destination rule 1000 inbound-interface name 'pppoe7' set nat destination rule 1000 protocol 'tcp' @@ -83,3 +51,38 @@ set nat source rule 50 translation port '10300' set nat source rule 100 outbound-interface name 'pppoe7' set nat source rule 100 source address '192.168.189.0/24' set nat source rule 100 translation address 'masquerade' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 lease '604800' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option default-router '192.168.189.1' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option domain-name 'vyos.net' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '1.1.1.1' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 option name-server '9.9.9.9' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 start '192.168.189.20' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 range 0 stop '192.168.189.254' +set service dhcp-server shared-network-name LAN subnet 192.168.189.0/24 subnet-id '1' +set service lldp interface all +set service lldp interface eth1 disable +set service ntp allow-client address '192.168.189.0/24' +set service ntp listen-address '192.168.189.1' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service router-advert interface bond10.50 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface bond10.50 prefix ::/64 valid-lifetime '5400' +set service ssh disable-host-validation +set service ssh dynamic-protection +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'R1' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '1.1.1.1' +set system name-server '9.9.9.9' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/ospf-simple b/smoketest/config-tests/ospf-simple index 13d5e7038..355709448 100644 --- a/smoketest/config-tests/ospf-simple +++ b/smoketest/config-tests/ospf-simple @@ -1,9 +1,11 @@ set interfaces ethernet eth0 vif 20 address '193.201.42.173/28' set interfaces ethernet eth0 vif 666 address '10.66.66.1/24' +set interfaces ethernet eth1 +set interfaces ethernet eth2 set interfaces loopback lo -set protocols ospf area 0 network '10.66.66.0/24' -set protocols ospf area 0 network '193.201.42.160/28' set protocols ospf area 0 area-type normal +set protocols ospf area 0 network '193.201.42.160/28' +set protocols ospf area 0 network '10.66.66.0/24' set protocols ospf interface eth0.20 cost '999' set protocols ospf interface eth0.20 dead-interval '4' set protocols ospf interface eth0.20 hello-interval '1' @@ -14,7 +16,9 @@ set protocols ospf interface eth0.666 passive set protocols ospf log-adjacency-changes detail set protocols static route 0.0.0.0/0 next-hop 193.201.42.170 distance '130' set system config-management commit-revisions '100' +set system console device ttyS0 speed '115200' set system host-name 'lab-vyos-r1' set system login user vyos authentication encrypted-password '$6$R.OnGzfXSfl6J$Iba/hl9bmjBs0VPtZ2zdW.Snh/nHuvxUwi0R6ruypgW63iKEbicJH.uUst8xZCyByURblxRtjAC1lAnYfIt.b0' set system login user vyos authentication plaintext-password '' -set system console device ttyS0 speed '115200' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/ospf-small b/smoketest/config-tests/ospf-small new file mode 100644 index 000000000..a7f8b682c --- /dev/null +++ b/smoketest/config-tests/ospf-small @@ -0,0 +1,82 @@ +set interfaces dummy dum0 address '172.18.254.200/32' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth0 vif 201 address '172.18.201.9/24' +set interfaces ethernet eth0 vif 202 address '172.18.202.9/24' +set interfaces ethernet eth0 vif 203 address '172.18.203.9/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set protocols ospf area 0 network '172.18.201.0/24' +set protocols ospf area 0 network '172.18.202.0/24' +set protocols ospf area 0 network '172.18.203.0/24' +set protocols ospf area 0 network '172.18.254.200/32' +set protocols ospf interface eth0.201 authentication md5 key-id 10 md5-key 'OSPFVyOSNET' +set protocols ospf interface eth0.201 dead-interval '40' +set protocols ospf interface eth0.201 hello-interval '10' +set protocols ospf interface eth0.201 passive disable +set protocols ospf interface eth0.201 priority '1' +set protocols ospf interface eth0.201 retransmit-interval '5' +set protocols ospf interface eth0.201 transmit-delay '1' +set protocols ospf interface eth0.202 authentication md5 key-id 10 md5-key 'OSPFVyOSNET' +set protocols ospf interface eth0.202 dead-interval '40' +set protocols ospf interface eth0.202 hello-interval '10' +set protocols ospf interface eth0.202 passive disable +set protocols ospf interface eth0.202 priority '1' +set protocols ospf interface eth0.202 retransmit-interval '5' +set protocols ospf interface eth0.202 transmit-delay '1' +set protocols ospf interface eth0.203 authentication md5 key-id 10 md5-key 'OSPFVyOSNET' +set protocols ospf interface eth0.203 dead-interval '40' +set protocols ospf interface eth0.203 hello-interval '10' +set protocols ospf interface eth0.203 passive disable +set protocols ospf interface eth0.203 priority '1' +set protocols ospf interface eth0.203 retransmit-interval '5' +set protocols ospf interface eth0.203 transmit-delay '1' +set protocols ospf log-adjacency-changes +set protocols ospf parameters abr-type 'cisco' +set protocols ospf parameters router-id '172.18.254.200' +set protocols ospf passive-interface 'default' +set protocols ospfv3 area 0.0.0.0 +set protocols ospfv3 interface eth0.201 area '0.0.0.0' +set protocols ospfv3 interface eth0.201 bfd +set protocols ospfv3 interface eth0.201 cost '40' +set protocols ospfv3 interface eth0.202 area '0.0.0.0' +set protocols ospfv3 interface eth0.202 bfd +set protocols ospfv3 interface eth0.202 cost '40' +set protocols ospfv3 interface eth0.203 area '0.0.0.0' +set protocols ospfv3 interface eth0.203 bfd +set protocols ospfv3 interface eth0.203 cost '40' +set protocols ospfv3 interface eth1 area '0.0.0.0' +set protocols ospfv3 interface eth1 bfd +set protocols ospfv3 interface eth1 cost '60' +set protocols ospfv3 interface eth1 mtu-ignore +set protocols ospfv3 interface eth1 network 'broadcast' +set protocols ospfv3 interface eth1 priority '20' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ssh disable-host-validation +set service ssh port '22' +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system name-server '172.16.254.30' +set system sysctl parameter net.ipv4.conf.eth0.tag value '1' +set system sysctl parameter net.ipv4.conf.eth1.tag value '1' +set system sysctl parameter net.ipv4.igmp_max_memberships value '5' +set system sysctl parameter net.ipv4.ipfrag_time value '4' +set system sysctl parameter net.mpls.default_ttl value '10' +set system sysctl parameter net.mpls.ip_ttl_propagate value '0' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' diff --git a/smoketest/config-tests/pppoe-server b/smoketest/config-tests/pppoe-server new file mode 100644 index 000000000..34fbea215 --- /dev/null +++ b/smoketest/config-tests/pppoe-server @@ -0,0 +1,47 @@ +set interfaces ethernet eth0 address 'dhcp' +set interfaces ethernet eth1 address '192.168.0.1/24' +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth2 speed 'auto' +set interfaces ethernet eth2 duplex 'auto' +set interfaces loopback lo +set nat source rule 100 outbound-interface name 'eth0' +set nat source rule 100 source address '192.168.0.0/24' +set nat source rule 100 translation address 'masquerade' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set service pppoe-server access-concentrator 'ACN' +set service pppoe-server authentication local-users username foo password 'bar' +set service pppoe-server authentication local-users username foo rate-limit download '20480' +set service pppoe-server authentication local-users username foo rate-limit upload '10240' +set service pppoe-server authentication mode 'local' +set service pppoe-server client-ip-pool default-range-pool range '10.0.0.0/24' +set service pppoe-server client-ip-pool default-range-pool range '10.0.1.0/24' +set service pppoe-server client-ip-pool default-range-pool range '10.0.2.0/24' +set service pppoe-server default-pool 'default-range-pool' +set service pppoe-server gateway-address '192.168.0.2' +set service pppoe-server interface eth1 +set service pppoe-server interface eth2 vlan '10' +set service pppoe-server interface eth2 vlan '20' +set service pppoe-server interface eth2 vlan '30-40' +set service pppoe-server interface eth2 vlan '50-60' +set service pppoe-server name-server '192.168.0.1' +set service pppoe-server ppp-options disable-ccp +set service ssh +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/qos-basic b/smoketest/config-tests/qos-basic new file mode 100644 index 000000000..0e198b80c --- /dev/null +++ b/smoketest/config-tests/qos-basic @@ -0,0 +1,75 @@ +set interfaces ethernet eth0 address '10.1.1.100/24' +set interfaces ethernet eth1 address '10.2.1.1/24' +set interfaces ethernet eth2 address '10.9.9.1/24' +set interfaces ethernet eth2 vif 200 +set interfaces loopback lo +set qos interface eth0 egress 'FS' +set qos interface eth1 egress 'ISPC' +set qos interface eth2 egress 'MY-HTB' +set qos interface eth2.200 egress 'foo-emulate' +set qos policy network-emulator foo-emulate bandwidth '300mbit' +set qos policy shaper FS bandwidth 'auto' +set qos policy shaper FS class 10 bandwidth '100%' +set qos policy shaper FS class 10 burst '15k' +set qos policy shaper FS class 10 match ADDRESS10 ip source address '172.17.1.2/32' +set qos policy shaper FS class 10 queue-type 'fair-queue' +set qos policy shaper FS class 20 bandwidth '100%' +set qos policy shaper FS class 20 burst '15k' +set qos policy shaper FS class 20 match ADDRESS20 ip source address '172.17.1.3/32' +set qos policy shaper FS class 20 queue-type 'fair-queue' +set qos policy shaper FS class 30 bandwidth '100%' +set qos policy shaper FS class 30 burst '15k' +set qos policy shaper FS class 30 match ADDRESS30 ip source address '172.17.1.4/32' +set qos policy shaper FS class 30 queue-type 'fair-queue' +set qos policy shaper FS default bandwidth '10%' +set qos policy shaper FS default burst '15k' +set qos policy shaper FS default ceiling '100%' +set qos policy shaper FS default priority '7' +set qos policy shaper FS default queue-type 'fair-queue' +set qos policy shaper ISPC bandwidth '600mbit' +set qos policy shaper ISPC default bandwidth '50%' +set qos policy shaper ISPC default burst '768k' +set qos policy shaper ISPC default ceiling '100%' +set qos policy shaper ISPC default queue-type 'fq-codel' +set qos policy shaper ISPC description 'Outbound Traffic Shaper - ISPC' +set qos policy shaper MY-HTB bandwidth '10mbit' +set qos policy shaper MY-HTB class 30 bandwidth '10%' +set qos policy shaper MY-HTB class 30 burst '15k' +set qos policy shaper MY-HTB class 30 ceiling '50%' +set qos policy shaper MY-HTB class 30 match ADDRESS30 ip source address '10.1.1.0/24' +set qos policy shaper MY-HTB class 30 priority '5' +set qos policy shaper MY-HTB class 30 queue-type 'fair-queue' +set qos policy shaper MY-HTB class 40 bandwidth '90%' +set qos policy shaper MY-HTB class 40 burst '15k' +set qos policy shaper MY-HTB class 40 ceiling '100%' +set qos policy shaper MY-HTB class 40 match ADDRESS40 ip source address '10.2.1.0/24' +set qos policy shaper MY-HTB class 40 priority '5' +set qos policy shaper MY-HTB class 40 queue-type 'fair-queue' +set qos policy shaper MY-HTB class 50 bandwidth '100%' +set qos policy shaper MY-HTB class 50 burst '15k' +set qos policy shaper MY-HTB class 50 match ADDRESS50 ipv6 source address '2001:db8::1/64' +set qos policy shaper MY-HTB class 50 queue-type 'fair-queue' +set qos policy shaper MY-HTB default bandwidth '10%' +set qos policy shaper MY-HTB default burst '15k' +set qos policy shaper MY-HTB default ceiling '100%' +set qos policy shaper MY-HTB default priority '7' +set qos policy shaper MY-HTB default queue-type 'fair-queue' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set system config-management commit-revisions '10' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/rip-router b/smoketest/config-tests/rip-router new file mode 100644 index 000000000..829aafbd5 --- /dev/null +++ b/smoketest/config-tests/rip-router @@ -0,0 +1,83 @@ +set interfaces dummy dum0 address '192.0.2.0/32' +set interfaces ethernet eth0 address '172.18.202.10/24' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth1 vif 20 +set interfaces ethernet eth1 vif-s 200 vif-c 2000 +set interfaces ethernet eth1 vif-s 200 vif-c 3000 +set policy access-list6 198 rule 10 action 'permit' +set policy access-list6 198 rule 10 source any +set policy access-list6 199 rule 20 action 'deny' +set policy access-list6 199 rule 20 source any +set policy prefix-list6 bar-prefix rule 200 action 'deny' +set policy prefix-list6 bar-prefix rule 200 prefix '2001:db8::/32' +set policy prefix-list6 foo-prefix rule 100 action 'permit' +set policy prefix-list6 foo-prefix rule 100 prefix '2001:db8::/32' +set policy route-map FooBar123 rule 10 action 'permit' +set protocols rip default-distance '20' +set protocols rip default-information originate +set protocols rip interface eth0 authentication md5 1 password 'VyOSsecure' +set protocols rip interface eth0 split-horizon poison-reverse +set protocols rip interface eth1.20 authentication plaintext-password 'VyOSsecure' +set protocols rip interface eth1.20 split-horizon poison-reverse +set protocols rip interface eth1.200 authentication md5 1 password 'VyOSsecure' +set protocols rip interface eth1.200 split-horizon disable +set protocols rip interface eth1.200.2000 authentication md5 1 password 'VyOSsecure' +set protocols rip interface eth1.200.3000 split-horizon disable +set protocols rip network '192.168.0.0/24' +set protocols rip redistribute connected +set protocols ripng aggregate-address '2001:db8:1000::/48' +set protocols ripng default-information originate +set protocols ripng default-metric '8' +set protocols ripng distribute-list access-list in '198' +set protocols ripng distribute-list access-list out '199' +set protocols ripng distribute-list interface eth0 access-list in '198' +set protocols ripng distribute-list interface eth0 access-list out '199' +set protocols ripng distribute-list interface eth0 prefix-list in 'foo-prefix' +set protocols ripng distribute-list interface eth0 prefix-list out 'bar-prefix' +set protocols ripng distribute-list interface eth1 access-list in '198' +set protocols ripng distribute-list interface eth1 access-list out '199' +set protocols ripng distribute-list interface eth1 prefix-list in 'foo-prefix' +set protocols ripng distribute-list interface eth1 prefix-list out 'bar-prefix' +set protocols ripng distribute-list interface eth2 access-list in '198' +set protocols ripng distribute-list interface eth2 access-list out '199' +set protocols ripng distribute-list interface eth2 prefix-list in 'foo-prefix' +set protocols ripng distribute-list interface eth2 prefix-list out 'bar-prefix' +set protocols ripng distribute-list prefix-list in 'foo-prefix' +set protocols ripng distribute-list prefix-list out 'bar-prefix' +set protocols ripng interface eth0 split-horizon poison-reverse +set protocols ripng interface eth1.20 split-horizon disable +set protocols ripng interface eth1.200 split-horizon poison-reverse +set protocols ripng interface eth1.200.3000 split-horizon poison-reverse +set protocols ripng network '2001:db8:1000::/64' +set protocols ripng network '2001:db8:1001::/64' +set protocols ripng network '2001:db8:2000::/64' +set protocols ripng network '2001:db8:2001::/64' +set protocols ripng passive-interface 'default' +set protocols ripng redistribute connected metric '8' +set protocols ripng redistribute connected route-map 'FooBar123' +set protocols ripng redistribute static metric '8' +set protocols ripng redistribute static route-map 'FooBar123' +set protocols ripng route '2001:db8:1000::/64' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set service ssh port '22' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/rpki-only b/smoketest/config-tests/rpki-only index 569463b12..dcbc7673d 100644 --- a/smoketest/config-tests/rpki-only +++ b/smoketest/config-tests/rpki-only @@ -1,5 +1,7 @@ set interfaces ethernet eth0 address '192.0.2.1/24' set interfaces ethernet eth0 address '2001:db8::1/64' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' set interfaces loopback lo set pki openssh rpki-5.6.7.8 private key 'b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAweDyflDFR4qyEwETbJkZ2ZZc+sJNiDTvYpwGsWIkju49lJSxHe1xKf8FhwfyMu40Snt1yDlRmmmz4CsbLgbuZGMPvXG11e34+C0pSVUvpF6aqRTeLl1pDRK7Rnjgm3su+I8SRLQR4qbLG6VXWOFuVpwiqbExLaU0hFYTPNP+dArNpsWEEKsohk6pTXdhg3VzWp3vCMjl2JTshDa3lD7p2xISSAReEY0fnfEAmQzH4Z6DIwwGdFuMWoQIg+oFBM9ARrO2/FIjRsz6AecR/WeU72JEw4aJic1/cAJQA6PiQBHwkuo3Wll1tbpxeRZoB2NQG22ETyJLvhfTaooNLT9HpQAAA8joU5dM6FOXTAAAAAdzc2gtcnNhAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0elAAAAAwEAAQAAAQACkDlUjzfUhtJs6uY5WNrdJB5NmHUS+HQzzxFNlhkapK6+wKqI1UNaRUtq6iF7J+gcFf7MK2nXS098BsXguWm8fQzPuemoDvHsQhiaJhyvpSqRUrvPTB/f8t/0AhQiKiJIWgfpTaIw53inAGwjujNNxNm2eafHTThhCYxOkRT7rsT6bnSio6yeqPy5QHg7IKFztp5FXDUyiOS3aX3SvzQcDUkMXALdvzX50t1XIk+X48Rgkq72dL4VpV2oMNDu3hM6FqBUplf9Mv3s51FNSma/cibCQoVufrIfoqYjkNTjIpYFUcq4zZ0/KvgXgzSsy9VN/4TtbalrOuu7X/SHJbvhAAAAgGPFsXgONYQvXxCnK1dIueozgaZg1I/n522E2ZCOXBW4dYJVyNpppwRreDzuFzTDEe061MpNHfScjVBJCCulivFYWscL6oaGsryDbFxO3QmB4I98UBqrds2yan9/JGc6EYe299yvaHy7Y64+NC0+fN8H2RAZ61T4w10JrCaJRyvzAAAAgQDvBfuV1U7o9k/fbU+U7W2UYnWblpOZAMfi1XQP6IJJeyWs90PdTdXh+l0eIQrCawIiRJytNfxMmbD4huwTf77fWiyCcPznmALQ7ex/yJ+W5Z0V4dPGF3h7o1uiS236JhQ7mfcliCkhp/1PIklBIMPcCp0zl+s9wMv2hX7w1Pah9QAAAIEAz6YgU9Xute+J+dBwoWxEQ+igR6KE55Um7O9AvSrqnCm9r7lSFsXC2ErYOxoDSJ3yIBEV0b4XAGn6tbbVIs3jS8BnLHxclAHQecOx1PGn7PKbnPW0oJRq/X9QCIEelKYvlykpayn7uZooTXqcDaPZxfPpmPdye8chVJvdygi7kPEAAAAMY3BvQExSMS53dWUzAQIDBAUGBw==' set pki openssh rpki-5.6.7.8 public key 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDB4PJ+UMVHirITARNsmRnZllz6wk2INO9inAaxYiSO7j2UlLEd7XEp/wWHB/Iy7jRKe3XIOVGaabPgKxsuBu5kYw+9cbXV7fj4LSlJVS+kXpqpFN4uXWkNErtGeOCbey74jxJEtBHipssbpVdY4W5WnCKpsTEtpTSEVhM80/50Cs2mxYQQqyiGTqlNd2GDdXNane8IyOXYlOyENreUPunbEhJIBF4RjR+d8QCZDMfhnoMjDAZ0W4xahAiD6gUEz0BGs7b8UiNGzPoB5xH9Z5TvYkTDhomJzX9wAlADo+JAEfCS6jdaWXW1unF5FmgHY1AbbYRPIku+F9Nqig0tP0el' @@ -14,6 +16,7 @@ set policy route-map ROUTES-IN rule 30 action 'deny' set policy route-map ROUTES-IN rule 30 match rpki 'invalid' set protocols bgp neighbor 192.0.2.200 address-family ipv4-unicast route-map import 'ROUTES-IN' set protocols bgp neighbor 192.0.2.200 remote-as '200' +set protocols bgp neighbor 2001:db8::200 address-family ipv4-unicast set protocols bgp neighbor 2001:db8::200 address-family ipv6-unicast route-map import 'ROUTES-IN' set protocols bgp neighbor 2001:db8::200 remote-as '200' set protocols bgp system-as '100' @@ -23,8 +26,17 @@ set protocols rpki cache 5.6.7.8 port '2222' set protocols rpki cache 5.6.7.8 preference '20' set protocols rpki cache 5.6.7.8 ssh key 'rpki-5.6.7.8' set protocols rpki cache 5.6.7.8 ssh username 'vyos' +set system config-management commit-revisions '200' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' set system host-name 'vyos' set system login user vyos authentication encrypted-password '$6$r/Yw/07NXNY$/ZB.Rjf9jxEV.BYoDyLdH.kH14rU52pOBtrX.4S34qlPt77chflCHvpTCq9a6huLzwaMR50rEICzA5GoIRZlM0' set system login user vyos authentication plaintext-password '' set system syslog global facility all level 'debug' -set system console device ttyS0 speed '115200' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/tunnel-broker b/smoketest/config-tests/tunnel-broker new file mode 100644 index 000000000..ee6301c85 --- /dev/null +++ b/smoketest/config-tests/tunnel-broker @@ -0,0 +1,75 @@ +set interfaces dummy dum0 address '192.0.2.0/32' +set interfaces dummy dum1 address '192.0.2.1/32' +set interfaces dummy dum2 address '192.0.2.2/32' +set interfaces dummy dum3 address '192.0.2.3/32' +set interfaces dummy dum4 address '192.0.2.4/32' +set interfaces ethernet eth0 address '172.18.202.10/24' +set interfaces ethernet eth0 duplex 'auto' +set interfaces ethernet eth0 speed 'auto' +set interfaces l2tpv3 l2tpeth10 destination-port '5010' +set interfaces l2tpv3 l2tpeth10 encapsulation 'ip' +set interfaces l2tpv3 l2tpeth10 peer-session-id '110' +set interfaces l2tpv3 l2tpeth10 peer-tunnel-id '10' +set interfaces l2tpv3 l2tpeth10 remote '172.18.202.110' +set interfaces l2tpv3 l2tpeth10 session-id '110' +set interfaces l2tpv3 l2tpeth10 source-address '172.18.202.10' +set interfaces l2tpv3 l2tpeth10 source-port '5010' +set interfaces l2tpv3 l2tpeth10 tunnel-id '10' +set interfaces l2tpv3 l2tpeth20 destination-port '5020' +set interfaces l2tpv3 l2tpeth20 encapsulation 'ip' +set interfaces l2tpv3 l2tpeth20 peer-session-id '120' +set interfaces l2tpv3 l2tpeth20 peer-tunnel-id '20' +set interfaces l2tpv3 l2tpeth20 remote '172.18.202.120' +set interfaces l2tpv3 l2tpeth20 session-id '120' +set interfaces l2tpv3 l2tpeth20 source-address '172.18.202.10' +set interfaces l2tpv3 l2tpeth20 source-port '5020' +set interfaces l2tpv3 l2tpeth20 tunnel-id '20' +set interfaces l2tpv3 l2tpeth30 destination-port '5030' +set interfaces l2tpv3 l2tpeth30 encapsulation 'ip' +set interfaces l2tpv3 l2tpeth30 peer-session-id '130' +set interfaces l2tpv3 l2tpeth30 peer-tunnel-id '30' +set interfaces l2tpv3 l2tpeth30 remote '172.18.202.130' +set interfaces l2tpv3 l2tpeth30 session-id '130' +set interfaces l2tpv3 l2tpeth30 source-address '172.18.202.10' +set interfaces l2tpv3 l2tpeth30 source-port '5030' +set interfaces l2tpv3 l2tpeth30 tunnel-id '30' +set interfaces tunnel tun100 address '172.16.0.1/30' +set interfaces tunnel tun100 encapsulation 'gretap' +set interfaces tunnel tun100 remote '192.0.2.100' +set interfaces tunnel tun100 source-address '192.0.2.1' +set interfaces tunnel tun200 address '172.16.0.5/30' +set interfaces tunnel tun200 encapsulation 'gre' +set interfaces tunnel tun200 remote '192.0.2.101' +set interfaces tunnel tun200 source-interface 'eth0' +set interfaces tunnel tun300 address '172.16.0.9/30' +set interfaces tunnel tun300 encapsulation 'ipip' +set interfaces tunnel tun300 remote '192.0.2.102' +set interfaces tunnel tun300 source-address '192.0.2.2' +set interfaces tunnel tun400 address '172.16.0.13/30' +set interfaces tunnel tun400 encapsulation 'gretap' +set interfaces tunnel tun400 remote '192.0.2.103' +set interfaces tunnel tun400 source-address '192.0.2.3' +set interfaces tunnel tun500 address '172.16.0.17/30' +set interfaces tunnel tun500 encapsulation 'gre' +set interfaces tunnel tun500 remote '192.0.2.104' +set interfaces tunnel tun500 source-address '192.0.2.4' +set protocols static route 0.0.0.0/0 next-hop 172.18.202.254 +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' diff --git a/smoketest/config-tests/vpn-openconnect-sstp b/smoketest/config-tests/vpn-openconnect-sstp new file mode 100644 index 000000000..28d7d5daa --- /dev/null +++ b/smoketest/config-tests/vpn-openconnect-sstp @@ -0,0 +1,35 @@ +set interfaces ethernet eth0 address '192.168.150.1/24' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server time1.vyos.net +set service ntp server time2.vyos.net +set service ntp server time3.vyos.net +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set vpn openconnect authentication local-users username test password 'test' +set vpn openconnect authentication mode local 'password' +set vpn openconnect network-settings client-ip-settings subnet '192.168.160.0/24' +set vpn openconnect ssl ca-certificate 'openconnect' +set vpn openconnect ssl certificate 'openconnect' +set vpn openconnect tls-version-min '1.0' +set vpn sstp authentication local-users username test password 'test' +set vpn sstp authentication mode 'local' +set vpn sstp authentication protocols 'mschap-v2' +set vpn sstp client-ip-pool default-range-pool range '192.168.170.0/24' +set vpn sstp default-pool 'default-range-pool' +set vpn sstp gateway-address '192.168.150.1' +set vpn sstp port '8443' +set vpn sstp ssl ca-certificate 'sstp' +set vpn sstp ssl certificate 'sstp' diff --git a/smoketest/config-tests/vrf-basic b/smoketest/config-tests/vrf-basic new file mode 100644 index 000000000..1d2874a60 --- /dev/null +++ b/smoketest/config-tests/vrf-basic @@ -0,0 +1,65 @@ +set interfaces ethernet eth0 address '192.0.2.1/24' +set interfaces ethernet eth1 duplex 'auto' +set interfaces ethernet eth1 speed 'auto' +set interfaces ethernet eth1 vrf 'green' +set interfaces ethernet eth2 vrf 'red' +set protocols static route 0.0.0.0/0 next-hop 192.0.2.254 distance '10' +set protocols static table 10 route 1.0.0.0/8 interface eth0 distance '20' +set protocols static table 10 route 2.0.0.0/8 interface eth0 distance '20' +set protocols static table 10 route 3.0.0.0/8 interface eth0 distance '20' +set protocols static table 20 route 4.0.0.0/8 interface eth0 distance '20' +set protocols static table 20 route 5.0.0.0/8 interface eth0 distance '50' +set protocols static table 20 route 6.0.0.0/8 interface eth0 distance '60' +set protocols static table 20 route 11.0.0.0/8 next-hop 1.1.1.1 interface 'eth0' +set protocols static table 20 route 12.0.0.0/8 next-hop 1.1.1.1 interface 'eth0' +set protocols static table 20 route 13.0.0.0/8 next-hop 1.1.1.1 interface 'eth0' +set protocols static table 20 route6 2001:db8:100::/40 interface eth1 distance '20' +set protocols static table 20 route6 2001:db8::/40 interface eth1 distance '10' +set protocols static table 30 route 14.0.0.0/8 next-hop 2.2.1.1 interface 'eth1' +set protocols static table 30 route 15.0.0.0/8 next-hop 2.2.1.1 interface 'eth1' +set protocols static table 30 route6 2001:db8:200::/40 interface eth1 distance '20' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' +set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 interface 'eth1' +set vrf name green protocols static route 20.0.0.0/8 next-hop 1.1.1.1 vrf 'default' +set vrf name green protocols static route 21.0.0.0/8 next-hop 2.2.1.1 interface 'eth1' +set vrf name green protocols static route 21.0.0.0/8 next-hop 2.2.1.1 vrf 'default' +set vrf name green protocols static route 100.0.0.0/8 interface eth0 distance '200' +set vrf name green protocols static route 100.0.0.0/8 interface eth0 vrf 'default' +set vrf name green protocols static route 101.0.0.0/8 interface eth0 vrf 'default' +set vrf name green protocols static route 101.0.0.0/8 interface eth1 +set vrf name green protocols static route6 2001:db8:100::/40 next-hop fe80::1 interface 'eth0' +set vrf name green protocols static route6 2001:db8:100::/40 next-hop fe80::1 vrf 'default' +set vrf name green protocols static route6 2001:db8:300::/40 interface eth1 distance '20' +set vrf name green protocols static route6 2001:db8:300::/40 interface eth1 vrf 'default' +set vrf name green table '1000' +set vrf name red protocols static route 30.0.0.0/8 next-hop 1.1.1.1 interface 'eth1' +set vrf name red protocols static route 40.0.0.0/8 next-hop 2.2.1.1 interface 'eth1' +set vrf name red protocols static route 40.0.0.0/8 next-hop 2.2.1.1 vrf 'default' +set vrf name red protocols static route 103.0.0.0/8 interface eth0 distance '201' +set vrf name red protocols static route 103.0.0.0/8 interface eth0 vrf 'default' +set vrf name red protocols static route 104.0.0.0/8 interface eth0 vrf 'default' +set vrf name red protocols static route 104.0.0.0/8 interface eth1 vrf 'default' +set vrf name red protocols static route6 2001:db8:100::/40 next-hop fe80::1 interface 'eth0' +set vrf name red protocols static route6 2001:db8:100::/40 next-hop fe80::1 vrf 'default' +set vrf name red protocols static route6 2001:db8:400::/40 interface eth1 distance '24' +set vrf name red protocols static route6 2001:db8:400::/40 interface eth1 vrf 'default' +set vrf name red table '2000' diff --git a/smoketest/config-tests/vrf-bgp-pppoe-underlay b/smoketest/config-tests/vrf-bgp-pppoe-underlay new file mode 100644 index 000000000..bd64c914a --- /dev/null +++ b/smoketest/config-tests/vrf-bgp-pppoe-underlay @@ -0,0 +1,186 @@ +set interfaces bridge br50 address '192.168.0.1/24' +set interfaces bridge br50 member interface eth0.50 +set interfaces bridge br50 member interface eth2 +set interfaces bridge br50 member interface eth3 +set interfaces dummy dum0 address '100.64.51.252/32' +set interfaces dummy dum0 address '2001:db8:200:ffff::1/128' +set interfaces dummy dum0 vrf 'vyos-test-01' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth0 offload rps +set interfaces ethernet eth0 ring-buffer rx '256' +set interfaces ethernet eth0 ring-buffer tx '256' +set interfaces ethernet eth0 vif 5 address '2001:db8:200:f0::114/64' +set interfaces ethernet eth0 vif 5 address '100.64.50.121/28' +set interfaces ethernet eth0 vif 5 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 10 address '2001:db8:200:10::ffff/64' +set interfaces ethernet eth0 vif 10 address '2001:db8:200::ffff/64' +set interfaces ethernet eth0 vif 10 address '100.64.50.62/26' +set interfaces ethernet eth0 vif 10 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 15 address '100.64.50.78/28' +set interfaces ethernet eth0 vif 15 address '2001:db8:200:15::ffff/64' +set interfaces ethernet eth0 vif 15 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 50 description 'Member of bridge br50' +set interfaces ethernet eth0 vif 110 address '100.64.51.190/27' +set interfaces ethernet eth0 vif 110 address '100.64.51.158/28' +set interfaces ethernet eth0 vif 110 address '2001:db8:200:101::ffff/64' +set interfaces ethernet eth0 vif 110 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 410 address '100.64.51.206/28' +set interfaces ethernet eth0 vif 410 address '2001:db8:200:104::ffff/64' +set interfaces ethernet eth0 vif 410 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 500 address '100.64.51.238/28' +set interfaces ethernet eth0 vif 500 address '2001:db8:200:50::ffff/64' +set interfaces ethernet eth0 vif 500 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 520 address '100.64.50.190/28' +set interfaces ethernet eth0 vif 520 address '2001:db8:200:520::ffff/64' +set interfaces ethernet eth0 vif 520 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 666 address '2001:db8:200:ff::101:1/112' +set interfaces ethernet eth0 vif 666 address '100.64.51.223/31' +set interfaces ethernet eth0 vif 666 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 800 address '2001:db8:200:ff::104:1/112' +set interfaces ethernet eth0 vif 800 address '100.64.51.212/31' +set interfaces ethernet eth0 vif 800 vrf 'vyos-test-01' +set interfaces ethernet eth0 vif 810 address '100.64.51.30/27' +set interfaces ethernet eth0 vif 810 address '2001:db8:200:102::ffff/64' +set interfaces ethernet eth0 vif 810 vrf 'vyos-test-01' +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth1 offload rps +set interfaces ethernet eth1 ring-buffer rx '256' +set interfaces ethernet eth1 ring-buffer tx '256' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth3 offload gro +set interfaces loopback lo +set interfaces pppoe pppoe7 authentication password 'vyos' +set interfaces pppoe pppoe7 authentication username 'vyos' +set interfaces pppoe pppoe7 dhcpv6-options pd 0 interface br50 address '1' +set interfaces pppoe pppoe7 dhcpv6-options pd 0 length '56' +set interfaces pppoe pppoe7 ip adjust-mss '1452' +set interfaces pppoe pppoe7 ipv6 address autoconf +set interfaces pppoe pppoe7 ipv6 adjust-mss '1432' +set interfaces pppoe pppoe7 mtu '1492' +set interfaces pppoe pppoe7 no-peer-dns +set interfaces pppoe pppoe7 source-interface 'eth1' +set interfaces virtual-ethernet veth0 address '100.64.51.220/31' +set interfaces virtual-ethernet veth0 address '2001:db8:200:ff::105:1/112' +set interfaces virtual-ethernet veth0 description 'Core: connect vyos-test-01 and default VRF' +set interfaces virtual-ethernet veth0 peer-name 'veth1' +set interfaces virtual-ethernet veth1 address '100.64.51.221/31' +set interfaces virtual-ethernet veth1 address '2001:db8:200:ff::105:2/112' +set interfaces virtual-ethernet veth1 description 'Core: connect vyos-test-01 and default VRF' +set interfaces virtual-ethernet veth1 peer-name 'veth0' +set interfaces virtual-ethernet veth1 vrf 'vyos-test-01' +set interfaces wireguard wg500 address '100.64.51.209/31' +set interfaces wireguard wg500 mtu '1500' +set interfaces wireguard wg500 peer A address '192.0.2.1' +set interfaces wireguard wg500 peer A allowed-ips '0.0.0.0/0' +set interfaces wireguard wg500 peer A port '5500' +set interfaces wireguard wg500 peer A public-key 'KGSXF4QckzGe7f7CT+r6VZ5brOD/pVYk8yvrxOQ+X0Y=' +set interfaces wireguard wg500 port '5500' +set interfaces wireguard wg500 private-key 'iLJh6Me6AdPJtNv3dgGhUbtyFxExxmNU4v0Fs6YE2Xc=' +set interfaces wireguard wg500 vrf 'vyos-test-01' +set interfaces wireguard wg501 address '2001:db8:200:ff::102:2/112' +set interfaces wireguard wg501 mtu '1500' +set interfaces wireguard wg501 peer A address '2001:db8:300::1' +set interfaces wireguard wg501 peer A allowed-ips '::/0' +set interfaces wireguard wg501 peer A port '5501' +set interfaces wireguard wg501 peer A public-key 'OF+1OJ+VfQ0Yw1mgVtQ2ion4CnAdy8Bvx7yEiO4+Pn8=' +set interfaces wireguard wg501 port '5501' +set interfaces wireguard wg501 private-key '0MP5X0PW58O4q2LDpuIXgZ0ySyAoWH8/kdpvQccCbUU=' +set interfaces wireguard wg501 vrf 'vyos-test-01' +set interfaces wireguard wg666 address '172.29.0.0/31' +set interfaces wireguard wg666 mtu '1500' +set interfaces wireguard wg666 peer B allowed-ips '0.0.0.0/0' +set interfaces wireguard wg666 peer B public-key '2HT+RfwcqJMYNYzdmtmpem8Ht0dL37o31APHVwmh024=' +set interfaces wireguard wg666 port '50666' +set interfaces wireguard wg666 private-key 'zvPnp2MLAoX7SotuHLFLDyy4sdlD7ttbD1xNEqA3mkU=' +set nat source rule 100 outbound-interface name 'pppoe7' +set nat source rule 100 source address '192.168.0.0/24' +set nat source rule 100 translation address 'masquerade' +set policy prefix-list AS100-origin-v4 rule 10 action 'permit' +set policy prefix-list AS100-origin-v4 rule 10 prefix '100.64.0.0/12' +set policy prefix-list AS100-origin-v4 rule 100 action 'permit' +set policy prefix-list AS100-origin-v4 rule 100 prefix '0.0.0.0/0' +set policy prefix-list AS200-origin-v4 rule 10 action 'permit' +set policy prefix-list AS200-origin-v4 rule 10 prefix '10.0.0.0/8' +set policy prefix-list AS200-origin-v4 rule 20 action 'permit' +set policy prefix-list AS200-origin-v4 rule 20 prefix '172.16.0.0/12' +set policy prefix-list6 AS100-origin-v6 rule 10 action 'permit' +set policy prefix-list6 AS100-origin-v6 rule 10 prefix '2001:db8:200::/40' +set policy prefix-list6 AS200-origin-v6 rule 10 action 'permit' +set policy prefix-list6 AS200-origin-v6 rule 10 prefix '2001:db8:100::/40' +set protocols static route 100.64.50.0/23 next-hop 100.64.51.221 +set protocols static route 192.0.2.255/32 interface pppoe7 +set protocols static route6 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff/128 interface pppoe7 +set qos interface pppoe7 egress 'isp-out' +set qos policy shaper isp-out bandwidth '38mbit' +set qos policy shaper isp-out default bandwidth '100%' +set qos policy shaper isp-out default burst '15k' +set qos policy shaper isp-out default queue-limit '1000' +set qos policy shaper isp-out default queue-type 'fq-codel' +set service router-advert interface br50 prefix ::/64 preferred-lifetime '2700' +set service router-advert interface br50 prefix ::/64 valid-lifetime '5400' +set service router-advert interface eth0.500 default-preference 'high' +set service router-advert interface eth0.500 name-server '2001:db8:200::1' +set service router-advert interface eth0.500 name-server '2001:db8:200::2' +set service router-advert interface eth0.500 prefix 2001:db8:200:50::/64 valid-lifetime 'infinity' +set service router-advert interface eth0.520 default-preference 'high' +set service router-advert interface eth0.520 name-server '2001:db8:200::1' +set service router-advert interface eth0.520 name-server '2001:db8:200::2' +set service router-advert interface eth0.520 prefix 2001:db8:200:520::/64 valid-lifetime 'infinity' +set service ssh disable-host-validation +set service ssh dynamic-protection allow-from '100.64.0.0/10' +set service ssh dynamic-protection allow-from '2001:db8:200::/40' +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system domain-name 'vyos.net' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system name-server '192.168.0.1' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' +set vrf bind-to-all +set vrf name vyos-test-01 protocols bgp address-family ipv4-unicast network 100.64.50.0/23 +set vrf name vyos-test-01 protocols bgp address-family ipv6-unicast network 2001:db8:200:ffff::1/128 +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.208 peer-group 'AS100v4' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast default-originate +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast maximum-prefix '10' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast prefix-list export 'AS100-origin-v4' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast prefix-list import 'AS200-origin-v4' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 address-family ipv4-unicast soft-reconfiguration inbound +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 capability dynamic +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.222 remote-as '200' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.251 peer-group 'AS100v4' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.251 shutdown +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.254 peer-group 'AS100v4' +set vrf name vyos-test-01 protocols bgp neighbor 100.64.51.254 shutdown +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast maximum-prefix '10' +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast prefix-list export 'AS100-origin-v6' +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast prefix-list import 'AS200-origin-v6' +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 address-family ipv6-unicast soft-reconfiguration inbound +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 capability dynamic +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ff::101:2 remote-as '200' +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::2 peer-group 'AS100v6' +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::2 shutdown +set vrf name vyos-test-01 protocols bgp neighbor 2001:db8:200:ffff::a peer-group 'AS100v6' +set vrf name vyos-test-01 protocols bgp peer-group AS100v4 address-family ipv4-unicast nexthop-self +set vrf name vyos-test-01 protocols bgp peer-group AS100v4 capability dynamic +set vrf name vyos-test-01 protocols bgp peer-group AS100v4 remote-as 'internal' +set vrf name vyos-test-01 protocols bgp peer-group AS100v4 update-source 'dum0' +set vrf name vyos-test-01 protocols bgp peer-group AS100v6 address-family ipv6-unicast nexthop-self +set vrf name vyos-test-01 protocols bgp peer-group AS100v6 capability dynamic +set vrf name vyos-test-01 protocols bgp peer-group AS100v6 remote-as 'internal' +set vrf name vyos-test-01 protocols bgp peer-group AS100v6 update-source 'dum0' +set vrf name vyos-test-01 protocols bgp system-as '100' +set vrf name vyos-test-01 protocols static route 100.64.50.0/23 blackhole +set vrf name vyos-test-01 protocols static route 100.64.51.32/27 next-hop 100.64.51.5 +set vrf name vyos-test-01 protocols static route 192.168.0.0/24 next-hop 100.64.51.220 +set vrf name vyos-test-01 protocols static route6 2001:db8:2fe:ffff::/64 next-hop 2001:db8:200:102::5 +set vrf name vyos-test-01 table '1000' diff --git a/smoketest/config-tests/vrf-ospf b/smoketest/config-tests/vrf-ospf new file mode 100644 index 000000000..fd14615e0 --- /dev/null +++ b/smoketest/config-tests/vrf-ospf @@ -0,0 +1,59 @@ +set interfaces ethernet eth0 address '192.0.2.1/24' +set interfaces ethernet eth0 offload gro +set interfaces ethernet eth1 offload gro +set interfaces ethernet eth1 vrf 'red' +set interfaces ethernet eth2 offload gro +set interfaces ethernet eth2 vrf 'blue' +set protocols ospf area 0 network '192.0.2.0/24' +set protocols ospf interface eth0 authentication md5 key-id 10 md5-key 'ospfkey' +set protocols ospf interface eth0 passive disable +set protocols ospf log-adjacency-changes +set protocols ospf parameters abr-type 'cisco' +set protocols ospf parameters router-id '1.2.3.4' +set protocols ospf passive-interface 'default' +set service ntp allow-client address '0.0.0.0/0' +set service ntp allow-client address '::/0' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system config-management commit-revisions '100' +set system conntrack modules ftp +set system conntrack modules h323 +set system conntrack modules nfs +set system conntrack modules pptp +set system conntrack modules sip +set system conntrack modules sqlnet +set system conntrack modules tftp +set system console device ttyS0 speed '115200' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' +set system login user vyos authentication plaintext-password '' +set system syslog global facility all level 'info' +set system syslog global facility local7 level 'debug' +set system time-zone 'Europe/Berlin' +set vrf name blue protocols ospf area 0 network '172.18.201.0/24' +set vrf name blue protocols ospf interface eth2 authentication md5 key-id 30 md5-key 'vyoskey456' +set vrf name blue protocols ospf interface eth2 dead-interval '40' +set vrf name blue protocols ospf interface eth2 hello-interval '10' +set vrf name blue protocols ospf interface eth2 passive disable +set vrf name blue protocols ospf interface eth2 priority '1' +set vrf name blue protocols ospf interface eth2 retransmit-interval '5' +set vrf name blue protocols ospf interface eth2 transmit-delay '1' +set vrf name blue protocols ospf log-adjacency-changes +set vrf name blue protocols ospf parameters abr-type 'cisco' +set vrf name blue protocols ospf parameters router-id '5.6.7.8' +set vrf name blue protocols ospf passive-interface 'default' +set vrf name blue table '2000' +set vrf name red protocols ospf area 0 network '172.18.202.0/24' +set vrf name red protocols ospf interface eth1 authentication md5 key-id 20 md5-key 'vyoskey123' +set vrf name red protocols ospf interface eth1 dead-interval '40' +set vrf name red protocols ospf interface eth1 hello-interval '10' +set vrf name red protocols ospf interface eth1 passive disable +set vrf name red protocols ospf interface eth1 priority '1' +set vrf name red protocols ospf interface eth1 retransmit-interval '5' +set vrf name red protocols ospf interface eth1 transmit-delay '1' +set vrf name red protocols ospf log-adjacency-changes +set vrf name red protocols ospf parameters abr-type 'cisco' +set vrf name red protocols ospf parameters router-id '9.10.11.12' +set vrf name red protocols ospf passive-interface 'default' +set vrf name red table '1000' diff --git a/smoketest/config-tests/wireless-basic b/smoketest/config-tests/wireless-basic index 77db29c2f..d9e6c8fac 100644 --- a/smoketest/config-tests/wireless-basic +++ b/smoketest/config-tests/wireless-basic @@ -20,6 +20,6 @@ set system console device ttyS0 speed '115200' set system domain-name 'dev.vyos.net' set system host-name 'WR1' set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0' -set system wireless country-code 'es' set system syslog global facility all level 'info' set system syslog global facility local7 level 'debug' +set system wireless country-code 'es' diff --git a/smoketest/configs/basic-api-service b/smoketest/configs/basic-api-service index f997ccd73..d5364d3e6 100644 --- a/smoketest/configs/basic-api-service +++ b/smoketest/configs/basic-api-service @@ -3,8 +3,6 @@ interfaces { address 192.0.2.1/31 address 2001:db8::1234/64 } - ethernet eth1 { - } loopback lo { } } diff --git a/smoketest/configs/bgp-dmvpn-hub b/smoketest/configs/bgp-dmvpn-hub index fc5aadd8f..fc0be5e07 100644 --- a/smoketest/configs/bgp-dmvpn-hub +++ b/smoketest/configs/bgp-dmvpn-hub @@ -1,8 +1,12 @@ interfaces { ethernet eth0 { address 100.64.10.1/31 + speed auto + duplex auto } ethernet eth1 { + speed auto + duplex auto } loopback lo { } @@ -171,4 +175,3 @@ vpn { // Warning: Do not remove the following line. // vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" // Release version: 1.3.0-epa3 - diff --git a/smoketest/configs/bgp-evpn-l3vpn-pe-router b/smoketest/configs/bgp-evpn-l3vpn-pe-router index b1ca7fae3..c676463b8 100644 --- a/smoketest/configs/bgp-evpn-l3vpn-pe-router +++ b/smoketest/configs/bgp-evpn-l3vpn-pe-router @@ -38,7 +38,7 @@ interfaces { ethernet eth0 { address 192.0.2.59/27 address 2001:db8:ffff::59/64 - description "out-of-band management" + description "Out-of-Band Managament Port" vrf mgmt } ethernet eth1 { diff --git a/smoketest/configs/bgp-rpki b/smoketest/configs/bgp-rpki index dffab4c69..5588f15c9 100644 --- a/smoketest/configs/bgp-rpki +++ b/smoketest/configs/bgp-rpki @@ -4,6 +4,7 @@ interfaces { address 2001:db8::ffff/64 } ethernet eth1 { + address 100.64.0.1/24 } loopback lo { } diff --git a/smoketest/configs/isis-small b/smoketest/configs/isis-small index 5a4201988..79a2f042f 100644 --- a/smoketest/configs/isis-small +++ b/smoketest/configs/isis-small @@ -4,19 +4,35 @@ interfaces { } ethernet eth0 { duplex auto + offload { + sg + tso + } speed auto } ethernet eth1 { address 192.0.2.1/24 duplex auto + offload { + sg + tso + } speed auto } ethernet eth2 { duplex auto + offload { + sg + tso + } speed auto } ethernet eth3 { duplex auto + offload { + sg + tso + } speed auto } } @@ -41,9 +57,9 @@ policy { } } protocols { - isis FOO { + isis { interface eth1 { - bfd + bfd } net 49.0001.1921.6800.1002.00 redistribute { @@ -61,6 +77,17 @@ system { config-management { commit-revisions 200 } + conntrack { + modules { + ftp + h323 + nfs + pptp + sip + sqlnet + tftp + } + } console { device ttyS0 { speed 115200 @@ -77,11 +104,11 @@ system { } } ntp { - server 0.pool.ntp.org { + server time1.vyos.net { } - server 1.pool.ntp.org { + server time2.vyos.net { } - server 2.pool.ntp.org { + server time3.vyos.net { } } syslog { @@ -99,5 +126,5 @@ system { // Warning: Do not remove the following line. -// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@7:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" -// Release version: 1.3.0-rc1 +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@3:conntrack-sync@2:dhcp-relay@2:dhcp-server@6:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@5:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@8:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.3.0 diff --git a/smoketest/configs/pppoe-server b/smoketest/configs/pppoe-server index ff5815e29..a01a45115 100644 --- a/smoketest/configs/pppoe-server +++ b/smoketest/configs/pppoe-server @@ -4,8 +4,12 @@ interfaces { } ethernet eth1 { address 192.168.0.1/24 + speed auto + duplex auto } ethernet eth2 { + speed auto + duplex auto } loopback lo { } diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py index 421ca7861..58aef0001 100755 --- a/smoketest/scripts/cli/test_interfaces_wireless.py +++ b/smoketest/scripts/cli/test_interfaces_wireless.py @@ -66,7 +66,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): cls._test_ipv6 = False cls._test_vlan = False - cls.cli_set(cls, wifi_cc_path + ['es']) + cls.cli_set(cls, wifi_cc_path + ['se']) def test_wireless_add_single_ip_address(self): # derived method to check if member interfaces are enslaved properly @@ -84,7 +84,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): def test_wireless_hostapd_config(self): # Only set the hostapd (access-point) options - interface = 'wlan0' + interface = 'wlan1' ssid = 'ssid' self.cli_set(self._base_path + [interface, 'ssid', ssid]) @@ -297,9 +297,96 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): for key, value in vht_opt.items(): self.assertIn(value, tmp) + def test_wireless_hostapd_he_config(self): + # Only set the hostapd (access-point) options - HE mode for 802.11ax at 6GHz + interface = 'wlan1' + ssid = 'ssid' + channel = '1' + sae_pw = 'VyOSVyOSVyOS' + country = 'de' + bss_color = '37' + channel_set_width = '134' + center_channel_freq_1 = '15' + + self.cli_set(wifi_cc_path + [country]) + self.cli_set(self._base_path + [interface, 'ssid', ssid]) + self.cli_set(self._base_path + [interface, 'type', 'access-point']) + self.cli_set(self._base_path + [interface, 'channel', channel]) + self.cli_set(self._base_path + [interface, 'mode', 'ax']) + self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa3']) + self.cli_set(self._base_path + [interface, 'security', 'wpa', 'passphrase', sae_pw]) + self.cli_set(self._base_path + [interface, 'security', 'wpa', 'cipher', 'CCMP']) + self.cli_set(self._base_path + [interface, 'security', 'wpa', 'cipher', 'GCMP']) + self.cli_set(self._base_path + [interface, 'enable-bf-protection']) + self.cli_set(self._base_path + [interface, 'mgmt-frame-protection', 'required']) + self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'bss-color', bss_color]) + self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'channel-set-width', channel_set_width]) + self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'center-channel-freq', 'freq-1', center_channel_freq_1]) + self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'beamform', 'multi-user-beamformer']) + self.cli_set(self._base_path + [interface, 'capabilities', 'he', 'beamform', 'single-user-beamformer']) + + self.cli_commit() + + # + # Validate Config + # + tmp = get_config_value(interface, 'interface') + self.assertEqual(interface, tmp) + + # ssid + tmp = get_config_value(interface, 'ssid') + self.assertEqual(ssid, tmp) + + # mode of operation resulting from [interface, 'mode', 'ax'] + tmp = get_config_value(interface, 'hw_mode') + self.assertEqual('a', tmp) + tmp = get_config_value(interface, 'ieee80211h') + self.assertEqual('1', tmp) + tmp = get_config_value(interface, 'ieee80211ax') + self.assertEqual('1', tmp) + + # channel and channel width + tmp = get_config_value(interface, 'channel') + self.assertEqual(channel, tmp) + tmp = get_config_value(interface, 'op_class') + self.assertEqual(channel_set_width, tmp) + tmp = get_config_value(interface, 'he_oper_centr_freq_seg0_idx') + self.assertEqual(center_channel_freq_1, tmp) + + # Country code + tmp = get_config_value(interface, 'country_code') + self.assertEqual(country.upper(), tmp) + + # BSS coloring + tmp = get_config_value(interface, 'he_bss_color') + self.assertEqual(bss_color, tmp) + + # sae_password + tmp = get_config_value(interface, 'sae_password') + self.assertEqual(sae_pw, tmp) + + # WPA3 and dependencies + tmp = get_config_value(interface, 'wpa') + self.assertEqual('2', tmp) + tmp = get_config_value(interface, 'rsn_pairwise') + self.assertEqual('CCMP GCMP', tmp) + tmp = get_config_value(interface, 'wpa_key_mgmt') + self.assertEqual('SAE', tmp) + + # beamforming + tmp = get_config_value(interface, 'he_mu_beamformer') + self.assertEqual('1', tmp) + tmp = get_config_value(interface, 'he_su_beamformee') + self.assertEqual('0', tmp) + tmp = get_config_value(interface, 'he_mu_beamformer') + self.assertEqual('1', tmp) + + # Check for running process + self.assertTrue(process_named_running('hostapd')) + def test_wireless_hostapd_wpa_config(self): # Only set the hostapd (access-point) options - interface = 'wlan0' + interface = 'wlan1' phy = 'phy0' ssid = 'VyOS-SMOKETEST' channel = '1' @@ -311,8 +398,12 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): self.cli_set(self._base_path + [interface, 'type', 'access-point']) self.cli_set(self._base_path + [interface, 'mode', mode]) - # Country-Code must be set + # SSID and country-code are already configured in self.setUpClass() + # Therefore, we must delete those here to check if commit will fail without it. self.cli_delete(wifi_cc_path) + self.cli_delete(self._base_path + [interface, 'ssid']) + + # Country-Code must be set with self.assertRaises(ConfigSessionError): self.cli_commit() self.cli_set(wifi_cc_path + [country]) @@ -322,7 +413,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): self.cli_commit() self.cli_set(self._base_path + [interface, 'ssid', ssid]) - # Channel must be set + # Channel must be set (defaults to channel 0) self.cli_set(self._base_path + [interface, 'channel', channel]) self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2']) @@ -363,7 +454,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): self.assertTrue(process_named_running('hostapd')) def test_wireless_access_point_bridge(self): - interface = 'wlan0' + interface = 'wlan1' ssid = 'VyOS-Test' bridge = 'br42477' @@ -373,6 +464,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): self.cli_set(self._base_path + [interface, 'ssid', ssid]) self.cli_set(self._base_path + [interface, 'type', 'access-point']) + self.cli_set(self._base_path + [interface, 'channel', '1']) self.cli_commit() @@ -399,7 +491,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.TestCase): self.cli_delete(bridge_path) def test_wireless_security_station_address(self): - interface = 'wlan0' + interface = 'wlan1' ssid = 'VyOS-ACL' hostapd_accept_station_conf = f'/run/hostapd/{interface}_station_accept.conf' diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py index 97c63d4cb..34e45a81a 100755 --- a/smoketest/scripts/cli/test_service_pppoe-server.py +++ b/smoketest/scripts/cli/test_service_pppoe-server.py @@ -177,6 +177,17 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase): conf.read(self._config_file) self.assertEqual(conf['pppoe']['pado-delay'], '10,20:200,30:300,-1:400') + def test_pppoe_server_any_login(self): + # Test configuration of local authentication for PPPoE server + self.basic_config() + + self.set(['authentication', 'any-login']) + self.cli_commit() + + # Validate configuration values + config = read_file(self._config_file) + self.assertIn('any-login=1', config) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py index a2e426dc7..dcce229e2 100755 --- a/smoketest/scripts/cli/test_vpn_openconnect.py +++ b/smoketest/scripts/cli/test_vpn_openconnect.py @@ -106,32 +106,32 @@ n+vZdJAWTq76zAPT3n9FClo= """ ca_key_data = """ - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCg7Mjl6+rs8Bd - kjqgl2QDuHfrH2mTDCeB7WuNTnIz0BPDtlmwIdqhU7LdCB/zUSABAa6LBe/Z/bK - WCRKyq8fU2/4uWECe975IMXOfFdYT6KA78DROvOi32JZmln0LAXV+538eb+g19x - NtoBhPO8igiNevfkV+nJehRK/41ATj+assTOv87vaSX7WqyaP/ZqkIdQD9Kc3cq - B4JsYjkWcniHL9yk4oY3cjKK8PJ1pi4FqgFHt2hA+Ic+NvbAhc47K9otP8FM4jk - Sii3MZfHA6Czb43BtbR+YEiWPzBhzE2bCuIgeRUumMF1Z+CAT6U7Cpx3XPh+Ac2 - RnDa8wKeQ1eqE1AgMBAAECggEAEDDaoqVqmMWsONoQiWRMr2h1RZvPxP7OpuKVW - iF3XgrMOb9HZc+Ybpj1dC+NDMekvNaHhMuF2Lqz6UgjDjzzVMH/x4yfDwFWUqeb - SxbglvGmVk4zg48JNkmArLT6GJQccD1XXjZZmqSOhagM4KalCpIdxfvgoZbTCa2 - xMSCLHS+1HCDcmpCoeXM6ZBPTn0NbjRDAqIzCwcq2veG7RSz040obk8h7nrdv7j - hxRGmtPmPFzKgGLNn6GnL7AwYVMiidjj/ntvM4B1OMs9MwUYbtpg98TWcWyu+ZR - akUrnVf9z2aIHCKyuJvke/PNqMgw+L8KV4/478XxWhXfl7K1F3nMQKBgQDRBUDY - NFH0wC4MMWsA+RGwyz7RlzACChDJCMtA/agbW06gUoE9UYf8KtLQQQYljlLJHxH - GD72QnuM+sowGGXnbD4BabA9TQiQUG5c6boznTy1uU1gt8T0Zl0mmC7vIMoMBVd - 5bb0qrZvuR123kDGYn6crug9uvMIYSSlhGmBGTJQKBgQDFGC3vfkCyXzLoYy+RI - s/rXgyBF1PUYQtyDgL0N811L0H7a8JhFnt4FvodUbxv2ob+1kIc9e3yXT6FsGyO - 7IDOnqgeQKy74bYqVPZZuf1FOFb9fuxf00pn1FmhAF4OuSWkhVhrKkyrZwdD8Ar - jLK253J94dogjdKAYfN1csaOA0QKBgD0zUZI8d4a3QoRVb+RACTr/t6v8nZTrR5 - DlX0XvP2qLKJFutuKyXaOrEkDh2R/j9T9oNncMos+WhikUdEVQ7koC1u0i2LXjF - tdAYN4+Akmz+DRmeNoy2VYF4w2YP+pVR+B7OPkCtBVNuPkx3743Fy42mTGPMCKy - jX8Lf59j5Tl1AoGBAI3sk2dZqozHMIlWovIH92CtIKP0gFD2cJ94p3fklvZDSWg - aeKYg4lffc8uZB/AjlAH9ly3ziZx0uIjcOc/RTg96/+SI/dls9xgUhjCmVVJ692 - ki9GMsau/JYaEl+pTvjcOiocDJfNwQHJM3Tx+3FII59DtyXyXo3T/E6kHNSMeBA - oGAR9M48DTspv9OH1S7X6yR6MtMY5ltsBmB3gPhQFxiDKBvARkIkAPqObQ9TG/V - uOz2Purq0Oz7SHsY2jiFDd2KEGo6JfG61NDdIhiQC99ztSgt7NtvSCnX22SfVDW - oFxSK+tek7tvDVXAXCNy4ZESMEUGJ6NDHImb80aF+xZ3wYKw= +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCg7Mjl6+rs8Bdk +jqgl2QDuHfrH2mTDCeB7WuNTnIz0BPDtlmwIdqhU7LdCB/zUSABAa6LBe/Z/bKWC +RKyq8fU2/4uWECe975IMXOfFdYT6KA78DROvOi32JZmln0LAXV+538eb+g19xNto +BhPO8igiNevfkV+nJehRK/41ATj+assTOv87vaSX7WqyaP/ZqkIdQD9Kc3cqB4Js +YjkWcniHL9yk4oY3cjKK8PJ1pi4FqgFHt2hA+Ic+NvbAhc47K9otP8FM4jkSii3M +ZfHA6Czb43BtbR+YEiWPzBhzE2bCuIgeRUumMF1Z+CAT6U7Cpx3XPh+Ac2RnDa8w +KeQ1eqE1AgMBAAECggEAEDDaoqVqmMWsONoQiWRMr2h1RZvPxP7OpuKVWiF3XgrM +Ob9HZc+Ybpj1dC+NDMekvNaHhMuF2Lqz6UgjDjzzVMH/x4yfDwFWUqebSxbglvGm +Vk4zg48JNkmArLT6GJQccD1XXjZZmqSOhagM4KalCpIdxfvgoZbTCa2xMSCLHS+1 +HCDcmpCoeXM6ZBPTn0NbjRDAqIzCwcq2veG7RSz040obk8h7nrdv7jhxRGmtPmPF +zKgGLNn6GnL7AwYVMiidjj/ntvM4B1OMs9MwUYbtpg98TWcWyu+ZRakUrnVf9z2a +IHCKyuJvke/PNqMgw+L8KV4/478XxWhXfl7K1F3nMQKBgQDRBUDYNFH0wC4MMWsA ++RGwyz7RlzACChDJCMtA/agbW06gUoE9UYf8KtLQQQYljlLJHxHGD72QnuM+sowG +GXnbD4BabA9TQiQUG5c6boznTy1uU1gt8T0Zl0mmC7vIMoMBVd5bb0qrZvuR123k +DGYn6crug9uvMIYSSlhGmBGTJQKBgQDFGC3vfkCyXzLoYy+RIs/rXgyBF1PUYQty +DgL0N811L0H7a8JhFnt4FvodUbxv2ob+1kIc9e3yXT6FsGyO7IDOnqgeQKy74bYq +VPZZuf1FOFb9fuxf00pn1FmhAF4OuSWkhVhrKkyrZwdD8ArjLK253J94dogjdKAY +fN1csaOA0QKBgD0zUZI8d4a3QoRVb+RACTr/t6v8nZTrR5DlX0XvP2qLKJFutuKy +XaOrEkDh2R/j9T9oNncMos+WhikUdEVQ7koC1u0i2LXjFtdAYN4+Akmz+DRmeNoy +2VYF4w2YP+pVR+B7OPkCtBVNuPkx3743Fy42mTGPMCKyjX8Lf59j5Tl1AoGBAI3s +k2dZqozHMIlWovIH92CtIKP0gFD2cJ94p3fklvZDSWgaeKYg4lffc8uZB/AjlAH9 +ly3ziZx0uIjcOc/RTg96/+SI/dls9xgUhjCmVVJ692ki9GMsau/JYaEl+pTvjcOi +ocDJfNwQHJM3Tx+3FII59DtyXyXo3T/E6kHNSMeBAoGAR9M48DTspv9OH1S7X6yR +6MtMY5ltsBmB3gPhQFxiDKBvARkIkAPqObQ9TG/VuOz2Purq0Oz7SHsY2jiFDd2K +EGo6JfG61NDdIhiQC99ztSgt7NtvSCnX22SfVDWoFxSK+tek7tvDVXAXCNy4ZESM +EUGJ6NDHImb80aF+xZ3wYKw= """ PROCESS_NAME = 'ocserv-main' diff --git a/src/conf_mode/interfaces_wireless.py b/src/conf_mode/interfaces_wireless.py index 998ff9dba..73944dc8b 100755 --- a/src/conf_mode/interfaces_wireless.py +++ b/src/conf_mode/interfaces_wireless.py @@ -104,6 +104,15 @@ def get_config(config=None): tmp = {'security': {'wpa': {'cipher' : ['CCMP']}}} elif wpa_mode == 'both': tmp = {'security': {'wpa': {'cipher' : ['CCMP', 'TKIP']}}} + elif wpa_mode == 'wpa3': + # According to WiFi specs (https://www.wi-fi.org/file/wpa3-specification) + # section 3.5: WPA3-Enterprise 192-bit mode + # WiFi NICs which would be able to connect to WPA3-Enterprise managed + # networks MUST support GCMP-256. + # Reasoning: Provided that chipsets would most likely _not_ be + # "private user only", they all would come with built-in support + # for GCMP-256. + tmp = {'security': {'wpa': {'cipher' : ['CCMP', 'CCMP-256', 'GCMP', 'GCMP-256']}}} if tmp: wifi = dict_merge(tmp, wifi) @@ -143,6 +152,23 @@ def verify(wifi): if 'channel' not in wifi: raise ConfigError('Wireless channel must be configured!') + if 'capabilities' in wifi and 'he' in wifi['capabilities']: + if 'channel_set_width' not in wifi['capabilities']['he']: + raise ConfigError('Channel width must be configured!') + + # op_modes drawn from: + # https://w1.fi/cgit/hostap/tree/src/common/ieee802_11_common.c?id=195cc3d919503fb0d699d9a56a58a72602b25f51#n1525 + # 802.11ax (WiFi-6e - HE) can use up to 160MHz bandwidth channels + six_ghz_op_modes_he = ['131', '132', '133', '134', '135'] + # 802.11be (WiFi-7 - EHT) can use up to 320MHz bandwidth channels + six_ghz_op_modes_eht = six_ghz_op_modes_he.append('137') + if 'security' in wifi and 'wpa' in wifi['security'] and 'mode' in wifi['security']['wpa']: + if wifi['security']['wpa']['mode'] == 'wpa3': + if 'he' in wifi['capabilities']: + if wifi['capabilities']['he']['channel_set_width'] in six_ghz_op_modes_he: + if 'mgmt_frame_protection' not in wifi or wifi['mgmt_frame_protection'] != 'required': + raise ConfigError('Management Frame Protection (MFP) is required with WPA3 at 6GHz! Consider also enabling Beacon Frame Protection (BFP) if your device supports it.') + if 'security' in wifi: if {'wep', 'wpa'} <= set(wifi.get('security', {})): raise ConfigError('Must either use WEP or WPA security!') @@ -176,7 +202,8 @@ def verify(wifi): if capabilities['vht']['beamform'] == 'single-user-beamformer': if int(capabilities['vht']['antenna_count']) < 3: - # Nasty Gotcha: see https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf lines 692-705 + # Nasty Gotcha: see lines 708-721 in: + # https://w1.fi/cgit/hostap/tree/hostapd/hostapd.conf?h=hostap_2_10&id=cff80b4f7d3c0a47c052e8187d671710f48939e4#n708 raise ConfigError('Single-user beam former requires at least 3 antennas!') if 'station_interfaces' in wifi and wifi['type'] == 'station': diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py index 34ec64fce..3484e5873 100755 --- a/src/conf_mode/nat_cgnat.py +++ b/src/conf_mode/nat_cgnat.py @@ -119,37 +119,34 @@ class IPOperations: + [self.ip_network.broadcast_address] ] - def get_prefix_by_ip_range(self): + def get_prefix_by_ip_range(self) -> list[ipaddress.IPv4Network]: """Return the common prefix for the address range Example: % ip = IPOperations('100.64.0.1-100.64.0.5') % ip.get_prefix_by_ip_range() - 100.64.0.0/29 + [IPv4Network('100.64.0.1/32'), IPv4Network('100.64.0.2/31'), IPv4Network('100.64.0.4/31')] """ - if '-' in self.ip_prefix: - ip_start, ip_end = self.ip_prefix.split('-') - start_ip = ipaddress.IPv4Address(ip_start.strip()) - end_ip = ipaddress.IPv4Address(ip_end.strip()) - - start_int = int(start_ip) - end_int = int(end_ip) - - # XOR to find differing bits - xor = start_int ^ end_int - - # Count the number of leading zeros in the XOR result to find the prefix length - prefix_length = 32 - xor.bit_length() - - # Calculate the network address - network_int = start_int & (0xFFFFFFFF << (32 - prefix_length)) - network_address = ipaddress.IPv4Address(network_int) + # We do not need to convert the IP range to network + # if it is already in network format + if self.ip_network: + return [self.ip_network] + + # Raise an error if the IP range is not in the correct format + if '-' not in self.ip_prefix: + raise ValueError( + 'Invalid IP range format. Please provide the IP range in CIDR format or with "-" separator.' + ) + # Split the IP range and convert it to IP address objects + range_start, range_end = self.ip_prefix.split('-') + range_start = ipaddress.IPv4Address(range_start) + range_end = ipaddress.IPv4Address(range_end) - return f"{network_address}/{prefix_length}" - return self.ip_prefix + # Return the summarized IP networks list + return list(ipaddress.summarize_address_range(range_start, range_end)) -def _delete_conntrack_entries(source_prefixes: list) -> None: +def _delete_conntrack_entries(source_prefixes: list[ipaddress.IPv4Network]) -> None: """Delete all conntrack entries for the list of prefixes""" for source_prefix in source_prefixes: run(f'conntrack -D -s {source_prefix}') @@ -224,15 +221,31 @@ def get_config(config=None): with_recursive_defaults=True, ) - if conf.exists(base) and is_node_changed(conf, base + ['pool']): - config.update({'delete_conntrack_entries': {}}) + effective_config = conf.get_config_dict( + base, + get_first_key=True, + key_mangling=('-', '_'), + no_tag_node_value_mangle=True, + effective=True, + ) + + # Check if the pool configuration has changed + if not conf.exists(base) or is_node_changed(conf, base + ['pool']): + config['delete_conntrack_entries'] = {} + + # add running config + if effective_config: + config['effective'] = effective_config + + if not conf.exists(base): + config['deleted'] = {} return config def verify(config): # bail out early - looks like removal from running config - if not config: + if 'deleted' in config: return None if 'pool' not in config: @@ -336,7 +349,7 @@ def verify(config): def generate(config): - if not config: + if 'deleted' in config: return None proto_maps = [] @@ -401,13 +414,38 @@ def generate(config): def apply(config): - if not config: + if 'deleted' in config: # Cleanup cgnat cmd('nft delete table ip cgnat') if os.path.isfile(nftables_cgnat_config): os.unlink(nftables_cgnat_config) - return None - cmd(f'nft --file {nftables_cgnat_config}') + else: + cmd(f'nft --file {nftables_cgnat_config}') + + # Delete conntrack entries + # if the pool configuration has changed + if 'delete_conntrack_entries' in config and 'effective' in config: + # Prepare the list of internal pool prefixes + internal_pool_prefix_list: list[ipaddress.IPv4Network] = [] + + # Get effective rules configurations + for rule_config in config['effective'].get('rule', {}).values(): + # Get effective internal pool configuration + internal_pool = rule_config['source']['pool'] + # Find the internal IP ranges for the internal pool + internal_ip_ranges: list[str] = config['effective']['pool']['internal'][ + internal_pool + ]['range'] + # Get the IP prefixes for the internal IP range + for internal_range in internal_ip_ranges: + ip_prefix: list[ipaddress.IPv4Network] = IPOperations( + internal_range + ).get_prefix_by_ip_range() + # Add the IP prefixes to the list of all internal pool prefixes + internal_pool_prefix_list += ip_prefix + + # Delete required sources for conntrack + _delete_conntrack_entries(internal_pool_prefix_list) # Logging allocations if 'log_allocation' in config: @@ -420,23 +458,11 @@ def apply(config): external_host, port_range = rest.split(' . ') # Log the parsed data logger.info( - f"Internal host: {internal_host.lstrip()}, external host: {external_host}, Port range: {port_range}") + f'Internal host: {internal_host.lstrip()}, external host: {external_host}, Port range: {port_range}') except ValueError as e: # Log error message logger.error(f"Error processing line '{allocation}': {e}") - # Delete conntrack entries - if 'delete_conntrack_entries' in config: - internal_pool_prefix_list = [] - for rule, rule_config in config['rule'].items(): - internal_pool = rule_config['source']['pool'] - internal_ip_ranges: list = config['pool']['internal'][internal_pool]['range'] - for internal_range in internal_ip_ranges: - ip_prefix = IPOperations(internal_range).get_prefix_by_ip_range() - internal_pool_prefix_list.append(ip_prefix) - # Deleta required sources for conntrack - _delete_conntrack_entries(internal_pool_prefix_list) - if __name__ == '__main__': try: diff --git a/src/helpers/system-versions-foot.py b/src/helpers/add-system-version.py index 9614f0d28..5270ee7d3 100755 --- a/src/helpers/system-versions-foot.py +++ b/src/helpers/add-system-version.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -# Copyright 2019, 2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2024 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 @@ -15,14 +15,6 @@ # 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/>. -import sys -import vyos.defaults -from vyos.component_version import write_system_footer +from vyos.component_version import add_system_version -sys.stdout.write("\n\n") -if vyos.defaults.cfg_vintage == 'vyos': - write_system_footer(None, vintage='vyos') -elif vyos.defaults.cfg_vintage == 'vyatta': - write_system_footer(None, vintage='vyatta') -else: - write_system_footer(None, vintage='vyos') +add_system_version() diff --git a/src/helpers/run-config-migration.py b/src/helpers/run-config-migration.py index ce647ad0a..e6ce97363 100755 --- a/src/helpers/run-config-migration.py +++ b/src/helpers/run-config-migration.py @@ -1,86 +1,78 @@ -#!/usr/bin/python3 - -# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io> +#!/usr/bin/env python3 +# +# Copyright (C) 2019-2024 VyOS maintainers and contributors # -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. +# This 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 library is distributed in the hope that it will be useful, +# 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 -# Lesser General Public License for more details. +# 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 Lesser General Public License -# along with this library. If not, see <http://www.gnu.org/licenses/>. +# 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 argparse -import datetime - -from vyos.utils.process import cmd -from vyos.migrator import Migrator, VirtualMigrator - -def main(): - argparser = argparse.ArgumentParser( - formatter_class=argparse.RawTextHelpFormatter) - argparser.add_argument('config_file', type=str, - help="configuration file to migrate") - argparser.add_argument('--force', action='store_true', - help="Force calling of all migration scripts.") - argparser.add_argument('--set-vintage', type=str, - choices=['vyatta', 'vyos'], - help="Set the format for the config version footer in config" - " file:\n" - "set to 'vyatta':\n" - "(for '/* === vyatta-config-version ... */' format)\n" - "or 'vyos':\n" - "(for '// vyos-config-version ...' format).") - argparser.add_argument('--virtual', action='store_true', - help="Update the format of the trailing comments in" - " config file,\nfrom 'vyatta' to 'vyos'; no migration" - " scripts are run.") - args = argparser.parse_args() +import time +from argparse import ArgumentParser +from shutil import copyfile - config_file_name = args.config_file - force_on = args.force - vintage = args.set_vintage - virtual = args.virtual +from vyos.migrate import ConfigMigrate +from vyos.migrate import ConfigMigrateError - if not os.access(config_file_name, os.R_OK): - print("Read error: {}.".format(config_file_name)) - sys.exit(1) +parser = ArgumentParser() +parser.add_argument('config_file', type=str, + help="configuration file to migrate") +parser.add_argument('--test-script', type=str, + help="test named script") +parser.add_argument('--output-file', type=str, + help="write to named output file instead of config file") +parser.add_argument('--force', action='store_true', + help="force run of all migration scripts") - if not os.access(config_file_name, os.W_OK): - print("Write error: {}.".format(config_file_name)) - sys.exit(1) +args = parser.parse_args() - separator = "." - backup_file_name = separator.join([config_file_name, - '{0:%Y-%m-%d-%H%M%S}'.format(datetime.datetime.now()), - 'pre-migration']) +config_file = args.config_file +out_file = args.output_file +test_script = args.test_script +force = args.force - cmd(f'cp -p {config_file_name} {backup_file_name}') +if not os.access(config_file, os.R_OK): + print(f"Config file '{config_file}' not readable") + sys.exit(1) - if not virtual: - virtual_migration = VirtualMigrator(config_file_name) - virtual_migration.run() +if out_file is None: + if not os.access(config_file, os.W_OK): + print(f"Config file '{config_file}' not writeable") + sys.exit(1) +else: + try: + open(out_file, 'w').close() + except OSError: + print(f"Output file '{out_file}' not writeable") + sys.exit(1) - migration = Migrator(config_file_name, force=force_on) - migration.run() +config_migrate = ConfigMigrate(config_file, force=force, output_file=out_file) - if not migration.config_changed(): - os.remove(backup_file_name) - else: - virtual_migration = VirtualMigrator(config_file_name, - set_vintage=vintage) +if test_script: + # run_script and exit + config_migrate.run_script(test_script) + sys.exit(0) - virtual_migration.run() +backup = None +if out_file is None: + timestr = time.strftime("%Y%m%d-%H%M%S") + backup = f'{config_file}.{timestr}.pre-migration' + copyfile(config_file, backup) - if not virtual_migration.config_changed(): - os.remove(backup_file_name) +try: + config_migrate.run() +except ConfigMigrateError as e: + print(f'Error: {e}') + sys.exit(1) -if __name__ == '__main__': - main() +if backup is not None and not config_migrate.config_modified: + os.unlink(backup) diff --git a/src/helpers/vyos-load-config.py b/src/helpers/vyos-load-config.py index 4ec865454..16083fd41 100755 --- a/src/helpers/vyos-load-config.py +++ b/src/helpers/vyos-load-config.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019 VyOS maintainers and contributors +# Copyright (C) 2019-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -30,7 +30,8 @@ import tempfile import vyos.defaults import vyos.remote from vyos.configsource import ConfigSourceSession, VyOSError -from vyos.migrator import Migrator, VirtualMigrator, MigratorError +from vyos.migrate import ConfigMigrate +from vyos.migrate import ConfigMigrateError class LoadConfig(ConfigSourceSession): """A subclass for calling 'loadFile'. @@ -81,22 +82,16 @@ with tempfile.NamedTemporaryFile() as fp: with open(fp.name, 'w') as fd: fd.write(config_string) - virtual_migration = VirtualMigrator(fp.name) + config_migrate = ConfigMigrate(fp.name) try: - virtual_migration.run() - except MigratorError as err: - sys.exit('{}'.format(err)) - - migration = Migrator(fp.name) - try: - migration.run() - except MigratorError as err: - sys.exit('{}'.format(err)) + config_migrate.run() + except ConfigMigrateError as err: + sys.exit(err) try: config.load_config(fp.name) except VyOSError as err: - sys.exit('{}'.format(err)) + sys.exit(err) if config.session_changed(): print("Load complete. Use 'commit' to make changes effective.") diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py index 35424626e..5ef845ac2 100755 --- a/src/helpers/vyos-merge-config.py +++ b/src/helpers/vyos-merge-config.py @@ -22,7 +22,8 @@ import vyos.remote from vyos.config import Config from vyos.configtree import ConfigTree -from vyos.migrator import Migrator, VirtualMigrator +from vyos.migrate import ConfigMigrate +from vyos.migrate import ConfigMigrateError from vyos.utils.process import cmd from vyos.utils.process import DEVNULL @@ -61,15 +62,11 @@ with tempfile.NamedTemporaryFile() as file_to_migrate: with open(file_to_migrate.name, 'w') as fd: fd.write(config_file) - virtual_migration = VirtualMigrator(file_to_migrate.name) - virtual_migration.run() - - migration = Migrator(file_to_migrate.name) - migration.run() - - if virtual_migration.config_changed() or migration.config_changed(): - with open(file_to_migrate.name, 'r') as fd: - config_file = fd.read() + config_migrate = ConfigMigrate(file_to_migrate.name) + try: + config_migrate.run() + except ConfigMigrateError as e: + sys.exit(e) merge_config_tree = ConfigTree(config_file) diff --git a/src/helpers/vyos-save-config.py b/src/helpers/vyos-save-config.py index 518bd9864..fa2ea0ce4 100755 --- a/src/helpers/vyos-save-config.py +++ b/src/helpers/vyos-save-config.py @@ -23,7 +23,7 @@ from argparse import ArgumentParser from vyos.config import Config from vyos.remote import urlc -from vyos.component_version import system_footer +from vyos.component_version import add_system_version from vyos.defaults import directories DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot') @@ -50,14 +50,13 @@ if re.match(r'\w+:/', save_file): config = Config() ct = config.get_config_tree(effective=True) +# pylint: disable=consider-using-with write_file = save_file if remote_save is None else NamedTemporaryFile(delete=False).name -with open(write_file, 'w') as f: - # config_tree is None before boot configuration is complete; - # automated saves should check boot_configuration_complete - if ct is not None: - f.write(ct.to_string()) - f.write("\n") - f.write(system_footer()) + +# config_tree is None before boot configuration is complete; +# automated saves should check boot_configuration_complete +config_str = None if ct is None else ct.to_string() +add_system_version(config_str, write_file) if json_file is not None and ct is not None: try: diff --git a/src/helpers/vyos_net_name b/src/helpers/vyos_net_name index 8c0992414..518e204f9 100755 --- a/src/helpers/vyos_net_name +++ b/src/helpers/vyos_net_name @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# Copyright (C) 2021-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -26,7 +26,7 @@ from vyos.configtree import ConfigTree from vyos.defaults import directories from vyos.utils.process import cmd from vyos.utils.boot import boot_configuration_complete -from vyos.migrator import VirtualMigrator +from vyos.migrate import ConfigMigrate vyos_udev_dir = directories['vyos_udev_dir'] vyos_log_dir = '/run/udev/log' @@ -147,8 +147,10 @@ def get_configfile_interfaces() -> dict: with tempfile.NamedTemporaryFile() as fp: with open(fp.name, 'w') as fd: fd.write(config_file) - virtual_migration = VirtualMigrator(fp.name) - virtual_migration.run() + config_migrate = ConfigMigrate(fp.name) + if config_migrate.syntax_update_needed(): + config_migrate.update_syntax() + config_migrate.write_config() with open(fp.name) as fd: config_file = fd.read() diff --git a/src/init/vyos-router b/src/init/vyos-router index 59004fdc1..8825cc16a 100755 --- a/src/init/vyos-router +++ b/src/init/vyos-router @@ -134,14 +134,14 @@ init_bootfile () { if [ ! -r $DEFAULT_BOOTFILE ]; then if [ -f $vyos_data_dir/config.boot.default ]; then cp $vyos_data_dir/config.boot.default $DEFAULT_BOOTFILE - $vyos_libexec_dir/system-versions-foot.py >> $DEFAULT_BOOTFILE + $vyos_libexec_dir/add-system-version.py >> $DEFAULT_BOOTFILE fi fi if [ ! -r $BOOTFILE ] ; then if [ -f $DEFAULT_BOOTFILE ]; then cp $DEFAULT_BOOTFILE $BOOTFILE else - $vyos_libexec_dir/system-versions-foot.py > $BOOTFILE + $vyos_libexec_dir/add-system-version.py > $BOOTFILE fi chgrp ${GROUP} $BOOTFILE chmod 660 $BOOTFILE diff --git a/src/migration-scripts/bgp/0-to-1 b/src/migration-scripts/bgp/0-to-1 index 5b8e8a163..a2f3343d8 100755..100644 --- a/src/migration-scripts/bgp/0-to-1 +++ b/src/migration-scripts/bgp/0-to-1 @@ -1,60 +1,40 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3417: migrate BGP tagNode to node as we can only have one BGP process -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 = ['protocols', 'bgp'] -config = ConfigTree(config_file) - -if not config.exists(base) or not config.is_tag(base): - # Nothing to do - exit(0) +def migrate(config: ConfigTree) -> None: + base = ['protocols', 'bgp'] -# Only one BGP process is supported, thus this operation is savea -asn = config.list_nodes(base) -bgp_base = base + asn + if not config.exists(base) or not config.is_tag(base): + # Nothing to do + return -# We need a temporary copy of the config -tmp_base = ['protocols', 'bgp2'] -config.copy(bgp_base, tmp_base) + # Only one BGP process is supported, thus this operation is savea + asn = config.list_nodes(base) + bgp_base = base + asn -# Now it's save to delete the old configuration -config.delete(base) + # We need a temporary copy of the config + tmp_base = ['protocols', 'bgp2'] + config.copy(bgp_base, tmp_base) -# Rename temporary copy to new final config and set new "local-as" option -config.rename(tmp_base, 'bgp') -config.set(base + ['local-as'], value=asn[0]) + # Now it's save to delete the old configuration + config.delete(base) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # Rename temporary copy to new final config and set new "local-as" option + config.rename(tmp_base, 'bgp') + config.set(base + ['local-as'], value=asn[0]) diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2 index a40d86e67..c0fc3b05a 100755..100644 --- a/src/migration-scripts/bgp/1-to-2 +++ b/src/migration-scripts/bgp/1-to-2 @@ -1,84 +1,64 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3741: no-ipv4-unicast is now enabled by default # T5937: Migrate IPv6 BGP Neighbor Peer Groups -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] +base = ['protocols', 'bgp'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -base = ['protocols', 'bgp'] -config = ConfigTree(config_file) + # This is now a default option - simply delete it. + # As it was configured explicitly - we can also bail out early as we need to + # do nothing! + if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']): + config.delete(base + ['parameters', 'default', 'no-ipv4-unicast']) -if not config.exists(base): - # Nothing to do - exit(0) + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters', 'default'])) == 0: + config.delete(base + ['parameters', 'default']) -# This is now a default option - simply delete it. -# As it was configured explicitly - we can also bail out early as we need to -# do nothing! -if config.exists(base + ['parameters', 'default', 'no-ipv4-unicast']): - config.delete(base + ['parameters', 'default', 'no-ipv4-unicast']) + # Check if the "default" node is now empty, if so - remove it + if len(config.list_nodes(base + ['parameters'])) == 0: + config.delete(base + ['parameters']) + else: + # As we now install a new default option into BGP we need to migrate all + # existing BGP neighbors and restore the old behavior + if config.exists(base + ['neighbor']): + for neighbor in config.list_nodes(base + ['neighbor']): + peer_group = base + ['neighbor', neighbor, 'peer-group'] + if config.exists(peer_group): + peer_group_name = config.return_value(peer_group) + # peer group enables old behavior for neighbor - bail out + if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']): + continue - # Check if the "default" node is now empty, if so - remove it - if len(config.list_nodes(base + ['parameters', 'default'])) == 0: - config.delete(base + ['parameters', 'default']) + afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast'] + if not config.exists(afi_ipv4): + config.set(afi_ipv4) - # Check if the "default" node is now empty, if so - remove it - if len(config.list_nodes(base + ['parameters'])) == 0: - config.delete(base + ['parameters']) -else: - # As we now install a new default option into BGP we need to migrate all - # existing BGP neighbors and restore the old behavior + # Migrate IPv6 AFI peer-group if config.exists(base + ['neighbor']): for neighbor in config.list_nodes(base + ['neighbor']): - peer_group = base + ['neighbor', neighbor, 'peer-group'] - if config.exists(peer_group): - peer_group_name = config.return_value(peer_group) - # peer group enables old behavior for neighbor - bail out - if config.exists(base + ['peer-group', peer_group_name, 'address-family', 'ipv4-unicast']): - continue - - afi_ipv4 = base + ['neighbor', neighbor, 'address-family', 'ipv4-unicast'] - if not config.exists(afi_ipv4): - config.set(afi_ipv4) - -# Migrate IPv6 AFI peer-group -if config.exists(base + ['neighbor']): - for neighbor in config.list_nodes(base + ['neighbor']): - tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group'] - if config.exists(tmp_path): - peer_group = config.return_value(tmp_path) - config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group) - config.delete(tmp_path) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + tmp_path = base + ['neighbor', neighbor, 'address-family', 'ipv6-unicast', 'peer-group'] + if config.exists(tmp_path): + peer_group = config.return_value(tmp_path) + config.set(base + ['neighbor', neighbor, 'peer-group'], value=peer_group) + config.delete(tmp_path) diff --git a/src/migration-scripts/bgp/2-to-3 b/src/migration-scripts/bgp/2-to-3 index 34d321a96..d8bc34db6 100755..100644 --- a/src/migration-scripts/bgp/2-to-3 +++ b/src/migration-scripts/bgp/2-to-3 @@ -1,51 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4257: Discussion on changing BGP autonomous system number syntax -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -# Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration. -if config.exists(['protocols', 'bgp']): - if config.exists(['protocols', 'bgp', 'local-as']): - config.rename(['protocols', 'bgp', 'local-as'], 'system-as') - -# Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration. -if config.exists(['vrf', 'name']): - for vrf in config.list_nodes(['vrf', 'name']): - if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']): - config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as') - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + # Check if BGP is even configured. Then check if local-as exists, then add the system-as, then remove the local-as. This is for global configuration. + if config.exists(['protocols', 'bgp']): + if config.exists(['protocols', 'bgp', 'local-as']): + config.rename(['protocols', 'bgp', 'local-as'], 'system-as') + + # Check if vrf names are configured. Then check if local-as exists inside of a name, then add the system-as, then remove the local-as. This is for vrf configuration. + if config.exists(['vrf', 'name']): + for vrf in config.list_nodes(['vrf', 'name']): + if config.exists(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as']): + config.rename(['vrf', f'name {vrf}', 'protocols', 'bgp', 'local-as'], 'system-as') diff --git a/src/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4 index 894cdda2b..842aef0ce 100755..100644 --- a/src/migration-scripts/bgp/3-to-4 +++ b/src/migration-scripts/bgp/3-to-4 @@ -1,64 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5150: Rework CLI definitions to apply route-maps between routing daemons # and zebra/kernel -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -bgp_base = ['protocols', 'bgp'] -# Check if BGP is configured - if so, migrate the CLI node -if config.exists(bgp_base): - if config.exists(bgp_base + ['route-map']): - tmp = config.return_value(bgp_base + ['route-map']) - - config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp) - config.set_tag(['system', 'ip', 'protocol']) - config.delete(bgp_base + ['route-map']) - - -# Check if vrf names are configured. Check if BGP is configured - if so, migrate -# the CLI node(s) -if config.exists(['vrf', 'name']): - for vrf in config.list_nodes(['vrf', 'name']): - vrf_base = ['vrf', 'name', vrf] - if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']): - tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map']) - - config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp) - config.set_tag(vrf_base + ['ip', 'protocol', 'bgp']) - config.delete(vrf_base + ['protocols', 'bgp', 'route-map']) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + bgp_base = ['protocols', 'bgp'] + # Check if BGP is configured - if so, migrate the CLI node + if config.exists(bgp_base): + if config.exists(bgp_base + ['route-map']): + tmp = config.return_value(bgp_base + ['route-map']) + + config.set(['system', 'ip', 'protocol', 'bgp', 'route-map'], value=tmp) + config.set_tag(['system', 'ip', 'protocol']) + config.delete(bgp_base + ['route-map']) + + + # Check if vrf names are configured. Check if BGP is configured - if so, migrate + # the CLI node(s) + if config.exists(['vrf', 'name']): + for vrf in config.list_nodes(['vrf', 'name']): + vrf_base = ['vrf', 'name', vrf] + if config.exists(vrf_base + ['protocols', 'bgp', 'route-map']): + tmp = config.return_value(vrf_base + ['protocols', 'bgp', 'route-map']) + + config.set(vrf_base + ['ip', 'protocol', 'bgp', 'route-map'], value=tmp) + config.set_tag(vrf_base + ['ip', 'protocol', 'bgp']) + config.delete(vrf_base + ['protocols', 'bgp', 'route-map']) diff --git a/src/migration-scripts/bgp/4-to-5 b/src/migration-scripts/bgp/4-to-5 index c4eb9ec72..d779eb11e 100755..100644 --- a/src/migration-scripts/bgp/4-to-5 +++ b/src/migration-scripts/bgp/4-to-5 @@ -1,67 +1,46 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Delete 'protocols bgp address-family ipv6-unicast route-target vpn # import/export', if 'protocols bgp address-family ipv6-unicast # route-target vpn both' exists -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -bgp_base = ['protocols', 'bgp'] -# Delete 'import/export' in default vrf if 'both' exists -if config.exists(bgp_base): - for address_family in ['ipv4-unicast', 'ipv6-unicast']: - rt_path = bgp_base + ['address-family', address_family, 'route-target', - 'vpn'] - if config.exists(rt_path + ['both']): - if config.exists(rt_path + ['import']): - config.delete(rt_path + ['import']) - if config.exists(rt_path + ['export']): - config.delete(rt_path + ['export']) - -# Delete import/export in vrfs if both exists -if config.exists(['vrf', 'name']): - for vrf in config.list_nodes(['vrf', 'name']): - vrf_base = ['vrf', 'name', vrf] +def migrate(config: ConfigTree) -> None: + bgp_base = ['protocols', 'bgp'] + # Delete 'import/export' in default vrf if 'both' exists + if config.exists(bgp_base): for address_family in ['ipv4-unicast', 'ipv6-unicast']: - rt_path = vrf_base + bgp_base + ['address-family', address_family, - 'route-target', 'vpn'] + rt_path = bgp_base + ['address-family', address_family, 'route-target', + 'vpn'] if config.exists(rt_path + ['both']): if config.exists(rt_path + ['import']): config.delete(rt_path + ['import']) if config.exists(rt_path + ['export']): config.delete(rt_path + ['export']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # Delete import/export in vrfs if both exists + if config.exists(['vrf', 'name']): + for vrf in config.list_nodes(['vrf', 'name']): + vrf_base = ['vrf', 'name', vrf] + for address_family in ['ipv4-unicast', 'ipv6-unicast']: + rt_path = vrf_base + bgp_base + ['address-family', address_family, + 'route-target', 'vpn'] + if config.exists(rt_path + ['both']): + if config.exists(rt_path + ['import']): + config.delete(rt_path + ['import']) + if config.exists(rt_path + ['export']): + config.delete(rt_path + ['export']) diff --git a/src/migration-scripts/cluster/1-to-2 b/src/migration-scripts/cluster/1-to-2 index a2e589155..5ca4531ea 100755..100644 --- a/src/migration-scripts/cluster/1-to-2 +++ b/src/migration-scripts/cluster/1-to-2 @@ -1,40 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. import re import sys from vyos.configtree import ConfigTree +from vyos.base import MigrationError -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: if not config.exists(['cluster']): # Cluster is not set -- nothing to do at all - sys.exit(0) + return # If at least one cluster group is defined, we have real work to do. # If there are no groups, we remove the top-level cluster node at the end of this script anyway. @@ -102,8 +90,9 @@ if __name__ == '__main__': services["other"].append(s) if services["other"]: - print("Cluster config includes non-IP address services and cannot be migrated", file=sys.stderr) - sys.exit(1) + err_str = "Cluster config includes non-IP address services and cannot be migrated" + print(err_str, file=sys.stderr) + raise MigrationError(err_str) # Cluster allowed virtual IPs for different interfaces within a single group. # VRRP groups are by definition bound to interfaces, so we cannot migrate such configurations. @@ -123,14 +112,16 @@ if __name__ == '__main__': if global_interface is not None: ips.append({"ip": ip, "interface": global_interface}) else: - print("Error: cluster has groups with IPs without interfaces and 'cluster interface' is not specified.", file=sys.stderr) - sys.exit(1) + err_str = "Cluster group has addresses without interfaces and 'cluster interface' is not specified." + print(f'Error: {err_str}', file=sys.stderr) + raise MigrationError(err_str) # Then we check if all addresses are for the same interface. intfs_set = set(map(lambda i: i["interface"], ips)) if len(intfs_set) > 1: - print("Error: cluster group has addresses for different interfaces", file=sys.stderr) - sys.exit(1) + err_str = "Cluster group has addresses for different interfaces" + print(f'Error: {err_str}', file=sys.stderr) + raise MigrationError(err_str) # If we got this far, the group is migratable. @@ -143,8 +134,9 @@ if __name__ == '__main__': # If there's already a VRRP group with exactly the same name, # we probably shouldn't try to make up a unique name, just leave migration to the user... if config.exists(vrrp_path): - print("Error: VRRP group with the same name as a cluster group already exists", file=sys.stderr) - sys.exit(1) + err_str = "VRRP group with the same name already exists" + print(f'Error: {err_str}', file=sys.stderr) + raise MigrationError(err_str) config.set(vrrp_path + ['interface'], value=interface) for a in addresses: @@ -184,10 +176,3 @@ if __name__ == '__main__': # Finally, clean up the old cluster node config.delete(['cluster']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/config-management/0-to-1 b/src/migration-scripts/config-management/0-to-1 index 6528fd136..44c685630 100755..100644 --- a/src/migration-scripts/config-management/0-to-1 +++ b/src/migration-scripts/config-management/0-to-1 @@ -1,31 +1,24 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # Add commit-revisions option if it doesn't exist -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if config.exists(['system', 'config-management', 'commit-revisions']): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if config.exists(['system', 'config-management', 'commit-revisions']): + # Nothing to do + return config.set(['system', 'config-management', 'commit-revisions'], value='200') - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/conntrack-sync/1-to-2 b/src/migration-scripts/conntrack-sync/1-to-2 index a8e1007f3..3e10e98c3 100755..100644 --- a/src/migration-scripts/conntrack-sync/1-to-2 +++ b/src/migration-scripts/conntrack-sync/1-to-2 @@ -1,44 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This # is no longer supported as the input data is validated and will lead to # an error. If user specifies an upper case logleve, make it lowercase -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 = ['service', 'conntrack-sync'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + base_accept_proto = base + ['accept-protocol'] if config.exists(base_accept_proto): tmp = config.return_value(base_accept_proto) @@ -57,10 +44,3 @@ else: base_cluster = base + ['failover-mechanism', 'cluster'] if config.exists(base_cluster): config.delete(base_cluster) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2 index c4fe667fc..0a4fb3de9 100755..100644 --- a/src/migration-scripts/conntrack/1-to-2 +++ b/src/migration-scripts/conntrack/1-to-2 @@ -1,32 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 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/>. # Delete "set system conntrack modules gre" option -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['system', 'conntrack', 'modules', 'gre']): + return -config = ConfigTree(config_file) - -if not config.exists(['system', 'conntrack', 'modules', 'gre']): - # Nothing to do - sys.exit(0) -else: # Delete abandoned node config.delete(['system', 'conntrack', 'modules', 'gre']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3 index 6bb42be1e..5ad4e6350 100755..100644 --- a/src/migration-scripts/conntrack/2-to-3 +++ b/src/migration-scripts/conntrack/2-to-3 @@ -1,36 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 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/>. # Conntrack syntax version 3 # Enables all conntrack modules (previous default behaviour) and omits manually disabled modules. -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print('Must specify file name!') - sys.exit(1) - -filename = sys.argv[1] - -with open(filename, 'r') as f: - config = ConfigTree(f.read()) - module_path = ['system', 'conntrack', 'modules'] -# Go over all conntrack modules available as of v1.3.0. -for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']: - # 'disable' is being phased out. - if config.exists(module_path + [module, 'disable']): - config.delete(module_path + [module]) - # If it wasn't manually 'disable'd, it was enabled by default. - else: - config.set(module_path + [module]) - -try: - if config.exists(module_path): - with open(filename, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - sys.exit(1) +def migrate(config: ConfigTree) -> None: + # Go over all conntrack modules available as of v1.3.0. + for module in ['ftp', 'h323', 'nfs', 'pptp', 'sip', 'sqlnet', 'tftp']: + # 'disable' is being phased out. + if config.exists(module_path + [module, 'disable']): + config.delete(module_path + [module]) + # If it wasn't manually 'disable'd, it was enabled by default. + else: + config.set(module_path + [module]) diff --git a/src/migration-scripts/conntrack/3-to-4 b/src/migration-scripts/conntrack/3-to-4 index e90c383af..679a260d5 100755..100644 --- a/src/migration-scripts/conntrack/3-to-4 +++ b/src/migration-scripts/conntrack/3-to-4 @@ -1,50 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Add support for IPv6 conntrack ignore, move existing nodes to `system conntrack ignore ipv4` -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 = ['system', 'conntrack'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -if config.exists(base + ['ignore', 'rule']): - config.set(base + ['ignore', 'ipv4']) - config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule']) - config.delete(base + ['ignore', 'rule']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -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) + if config.exists(base + ['ignore', 'rule']): + config.set(base + ['ignore', 'ipv4']) + config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule']) + config.delete(base + ['ignore', 'rule']) diff --git a/src/migration-scripts/conntrack/4-to-5 b/src/migration-scripts/conntrack/4-to-5 index d2e5fc5fa..775fe7480 100755..100644 --- a/src/migration-scripts/conntrack/4-to-5 +++ b/src/migration-scripts/conntrack/4-to-5 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5779: system conntrack timeout custom # Before: @@ -23,37 +22,18 @@ # Extend functionality to ipv6 and move ipv4 custom rules to new node: # set system conntrack timeout custom [ipv4 | ipv6] rule <rule> ... -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 = ['system', 'conntrack'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['timeout', 'custom', 'rule']): - for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']): - if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']): - config.set(base + ['timeout', 'custom', 'ipv4', 'rule']) - config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule]) - config.delete(base + ['timeout', 'custom', 'rule']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['timeout', 'custom', 'rule']): + for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']): + if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']): + config.set(base + ['timeout', 'custom', 'ipv4', 'rule']) + config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule]) + config.delete(base + ['timeout', 'custom', 'rule']) diff --git a/src/migration-scripts/container/0-to-1 b/src/migration-scripts/container/0-to-1 index 6b282e082..99102a5e6 100755..100644 --- a/src/migration-scripts/container/0-to-1 +++ b/src/migration-scripts/container/0-to-1 @@ -1,77 +1,65 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4870: change underlaying container filesystem from vfs to overlay import os import shutil -import sys from vyos.configtree import ConfigTree from vyos.utils.process import call -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['container', 'name'] -config = ConfigTree(config_file) - -# Check if containers exist and we need to perform image manipulation -if config.exists(base): - for container in config.list_nodes(base): - # Stop any given container first - call(f'sudo systemctl stop vyos-container-{container}.service') - # Export container image for later re-import to new filesystem. We store - # the backup on a real disk as a tmpfs (like /tmp) could probably lack - # memory if a host has too many containers stored. - image_name = config.return_value(base + [container, 'image']) - call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}') -# No need to adjust the strage driver online (this is only used for testing and -# debugging on a live system) - it is already overlay2 when the migration script -# is run during system update. But the specified driver in the image is actually -# overwritten by the still present VFS filesystem on disk. Thus podman still -# thinks it uses VFS until we delete the libpod directory under: -# /usr/lib/live/mount/persistence/container/storage -#call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2') +def migrate(config: ConfigTree) -> None: + # Check if containers exist and we need to perform image manipulation + if config.exists(base): + for container in config.list_nodes(base): + # Stop any given container first + call(f'sudo systemctl stop vyos-container-{container}.service') + # Export container image for later re-import to new filesystem. We store + # the backup on a real disk as a tmpfs (like /tmp) could probably lack + # memory if a host has too many containers stored. + image_name = config.return_value(base + [container, 'image']) + call(f'sudo podman image save --quiet --output /root/{container}.tar --format oci-archive {image_name}') -base_path = '/usr/lib/live/mount/persistence/container/storage' -for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']: - if os.path.exists(f'{base_path}/{dir}'): - shutil.rmtree(f'{base_path}/{dir}') + # No need to adjust the strage driver online (this is only used for testing and + # debugging on a live system) - it is already overlay2 when the migration script + # is run during system update. But the specified driver in the image is actually + # overwritten by the still present VFS filesystem on disk. Thus podman still + # thinks it uses VFS until we delete the libpod directory under: + # /usr/lib/live/mount/persistence/container/storage + #call('sed -i "s/vfs/overlay2/g" /etc/containers/storage.conf /usr/share/vyos/templates/container/storage.conf.j2') -# Now all remaining information about VFS is gone and we operate in overlayfs2 -# filesystem mode. Time to re-import the images. -if config.exists(base): - for container in config.list_nodes(base): - # Export container image for later re-import to new filesystem - image_name = config.return_value(base + [container, 'image']) - image_path = f'/root/{container}.tar' - call(f'sudo podman image load --quiet --input {image_path}') + base_path = '/usr/lib/live/mount/persistence/container/storage' + for dir in ['libpod', 'vfs', 'vfs-containers', 'vfs-images', 'vfs-layers']: + if os.path.exists(f'{base_path}/{dir}'): + shutil.rmtree(f'{base_path}/{dir}') - # Start any given container first - call(f'sudo systemctl start vyos-container-{container}.service') + # Now all remaining information about VFS is gone and we operate in overlayfs2 + # filesystem mode. Time to re-import the images. + if config.exists(base): + for container in config.list_nodes(base): + # Export container image for later re-import to new filesystem + image_name = config.return_value(base + [container, 'image']) + image_path = f'/root/{container}.tar' + call(f'sudo podman image load --quiet --input {image_path}') - # Delete temporary container image - if os.path.exists(image_path): - os.unlink(image_path) + # Start any given container first + call(f'sudo systemctl start vyos-container-{container}.service') + # Delete temporary container image + if os.path.exists(image_path): + os.unlink(image_path) diff --git a/src/migration-scripts/container/1-to-2 b/src/migration-scripts/container/1-to-2 index 408faf978..c12dd8ebb 100755..100644 --- a/src/migration-scripts/container/1-to-2 +++ b/src/migration-scripts/container/1-to-2 @@ -1,50 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6208: container: rename "cap-add" CLI node to "capability" -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 = ['container', 'name'] -config = ConfigTree(config_file) -# Check if containers exist and we need to perform image manipulation -if not config.exists(base): - # Nothing to do - exit(0) +def migrate(config: ConfigTree) -> None: -for container in config.list_nodes(base): - cap_path = base + [container, 'cap-add'] - if config.exists(cap_path): - config.rename(cap_path, 'capability') + # Check if containers exist and we need to perform image manipulation + if not config.exists(base): + # Nothing to do + return -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + for container in config.list_nodes(base): + cap_path = base + [container, 'cap-add'] + if config.exists(cap_path): + config.rename(cap_path, 'capability') diff --git a/src/migration-scripts/dhcp-relay/1-to-2 b/src/migration-scripts/dhcp-relay/1-to-2 index 508bac6be..54cd8d6c0 100755..100644 --- a/src/migration-scripts/dhcp-relay/1-to-2 +++ b/src/migration-scripts/dhcp-relay/1-to-2 @@ -1,35 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # Delete "set service dhcp-relay relay-options port" option # Delete "set service dhcpv6-relay listen-port" option -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])): + # Nothing to do + return -config = ConfigTree(config_file) - -if not (config.exists(['service', 'dhcp-relay', 'relay-options', 'port']) or config.exists(['service', 'dhcpv6-relay', 'listen-port'])): - # Nothing to do - sys.exit(0) -else: # Delete abandoned node config.delete(['service', 'dhcp-relay', 'relay-options', 'port']) # Delete abandoned node config.delete(['service', 'dhcpv6-relay', 'listen-port']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/dhcp-server/10-to-11 b/src/migration-scripts/dhcp-server/10-to-11 index a0dc96ad0..f54a4c7b7 100755..100644 --- a/src/migration-scripts/dhcp-server/10-to-11 +++ b/src/migration-scripts/dhcp-server/10-to-11 @@ -1,48 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6171: rename "service dhcp-server failover" to "service dhcp-server high-availability" -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 = ['service', 'dhcp-server'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -if config.exists(base + ['failover']): - config.rename(base + ['failover'],'high-availability') +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1)
\ No newline at end of file + if config.exists(base + ['failover']): + config.rename(base + ['failover'],'high-availability') diff --git a/src/migration-scripts/dhcp-server/4-to-5 b/src/migration-scripts/dhcp-server/4-to-5 index d15e0baf5..a655515dc 100755..100644 --- a/src/migration-scripts/dhcp-server/4-to-5 +++ b/src/migration-scripts/dhcp-server/4-to-5 @@ -1,122 +1,118 @@ #!/usr/bin/env python3 +# Copyright 2018-2024 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/>. + # Removes boolean operator from: # - "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable (true|false)" # - "set service dhcp-server shared-network-name <xyz> authoritative (true|false)" # - "set service dhcp-server disabled (true|false)" -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['service', 'dhcp-server']): - # Nothing to do - sys.exit(0) -else: - base = ['service', 'dhcp-server'] - # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless - if config.exists(base + ['dynamic-dns-update']): - bool_val = config.return_value(base + ['dynamic-dns-update', 'enable']) - - # Delete the node with the old syntax - config.delete(base + ['dynamic-dns-update']) - if str(bool_val) == 'true': - # Enable dynamic-dns-update with new syntax - config.set(base + ['dynamic-dns-update'], value=None) - - # Make node "set service dhcp-server disabled (true|false)" valueless - if config.exists(base + ['disabled']): - bool_val = config.return_value(base + ['disabled']) - - # Delete the node with the old syntax - config.delete(base + ['disabled']) - if str(bool_val) == 'true': - # Now disable DHCP server with the new syntax - config.set(base + ['disable'], value=None) - - # Make node "set service dhcp-server hostfile-update (enable|disable) valueless - if config.exists(base + ['hostfile-update']): - bool_val = config.return_value(base + ['hostfile-update']) - - # Delete the node with the old syntax incl. all subnodes - config.delete(base + ['hostfile-update']) - if str(bool_val) == 'enable': - # Enable hostfile update with new syntax - config.set(base + ['hostfile-update'], value=None) - - # Run this for every instance if 'shared-network-name' - for network in config.list_nodes(base + ['shared-network-name']): - base_network = base + ['shared-network-name', network] - # format as tag node to avoid loading problems - config.set_tag(base + ['shared-network-name']) - - # Run this for every specified 'subnet' - for subnet in config.list_nodes(base_network + ['subnet']): - base_subnet = base_network + ['subnet', subnet] +def migrate(config: ConfigTree) -> None: + if not config.exists(['service', 'dhcp-server']): + # Nothing to do + return + else: + base = ['service', 'dhcp-server'] + # Make node "set service dhcp-server dynamic-dns-update enable (true|false)" valueless + if config.exists(base + ['dynamic-dns-update']): + bool_val = config.return_value(base + ['dynamic-dns-update', 'enable']) + + # Delete the node with the old syntax + config.delete(base + ['dynamic-dns-update']) + if str(bool_val) == 'true': + # Enable dynamic-dns-update with new syntax + config.set(base + ['dynamic-dns-update'], value=None) + + # Make node "set service dhcp-server disabled (true|false)" valueless + if config.exists(base + ['disabled']): + bool_val = config.return_value(base + ['disabled']) + + # Delete the node with the old syntax + config.delete(base + ['disabled']) + if str(bool_val) == 'true': + # Now disable DHCP server with the new syntax + config.set(base + ['disable'], value=None) + + # Make node "set service dhcp-server hostfile-update (enable|disable) valueless + if config.exists(base + ['hostfile-update']): + bool_val = config.return_value(base + ['hostfile-update']) + + # Delete the node with the old syntax incl. all subnodes + config.delete(base + ['hostfile-update']) + if str(bool_val) == 'enable': + # Enable hostfile update with new syntax + config.set(base + ['hostfile-update'], value=None) + + # Run this for every instance if 'shared-network-name' + for network in config.list_nodes(base + ['shared-network-name']): + base_network = base + ['shared-network-name', network] # format as tag node to avoid loading problems - config.set_tag(base_network + ['subnet']) + config.set_tag(base + ['shared-network-name']) - # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless - if config.exists(base_subnet + ['ip-forwarding', 'enable']): - bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable']) - # Delete the node with the old syntax - config.delete(base_subnet + ['ip-forwarding']) - if str(bool_val) == 'true': - # Recreate node with new syntax - config.set(base_subnet + ['ip-forwarding'], value=None) - - # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9> - if config.exists(base_subnet + ['start']): - # This is the new "range" id for DHCP lease ranges - r_id = 0 - for range in config.list_nodes(base_subnet + ['start']): - range_start = range - range_stop = config.return_value(base_subnet + ['start', range_start, 'stop']) + # Run this for every specified 'subnet' + for subnet in config.list_nodes(base_network + ['subnet']): + base_subnet = base_network + ['subnet', subnet] + # format as tag node to avoid loading problems + config.set_tag(base_network + ['subnet']) + # Make node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 ip-forwarding enable" valueless + if config.exists(base_subnet + ['ip-forwarding', 'enable']): + bool_val = config.return_value(base_subnet + ['ip-forwarding', 'enable']) # Delete the node with the old syntax - config.delete(base_subnet + ['start', range_start]) + config.delete(base_subnet + ['ip-forwarding']) + if str(bool_val) == 'true': + # Recreate node with new syntax + config.set(base_subnet + ['ip-forwarding'], value=None) + + # Rename node "set service dhcp-server shared-network-name <xyz> subnet 172.31.0.0/24 start <172.16.0.4> stop <172.16.0.9> + if config.exists(base_subnet + ['start']): + # This is the new "range" id for DHCP lease ranges + r_id = 0 + for range in config.list_nodes(base_subnet + ['start']): + range_start = range + range_stop = config.return_value(base_subnet + ['start', range_start, 'stop']) + + # Delete the node with the old syntax + config.delete(base_subnet + ['start', range_start]) + + # Create the node for the new syntax + # Note: range is a tag node, counter is its child, not a value + config.set(base_subnet + ['range', r_id]) + config.set(base_subnet + ['range', r_id, 'start'], value=range_start) + config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop) + + # format as tag node to avoid loading problems + config.set_tag(base_subnet + ['range']) + + # increment range id for possible next range definition + r_id += 1 - # Create the node for the new syntax - # Note: range is a tag node, counter is its child, not a value - config.set(base_subnet + ['range', r_id]) - config.set(base_subnet + ['range', r_id, 'start'], value=range_start) - config.set(base_subnet + ['range', r_id, 'stop'], value=range_stop) + # Delete the node with the old syntax + config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start']) - # format as tag node to avoid loading problems - config.set_tag(base_subnet + ['range']) - # increment range id for possible next range definition - r_id += 1 + # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless + if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']): + authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) # Delete the node with the old syntax - config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'subnet', subnet, 'start']) + config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) - - # Make node "set service dhcp-server shared-network-name <xyz> authoritative" valueless - if config.exists(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']): - authoritative = config.return_value(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) - - # Delete the node with the old syntax - config.delete(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) - - # Recreate node with new syntax - if required - if authoritative == "enable": - config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) - - 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)) - sys.exit(1) + # Recreate node with new syntax - if required + if authoritative == "enable": + config.set(['service', 'dhcp-server', 'shared-network-name', network, 'authoritative']) diff --git a/src/migration-scripts/dhcp-server/5-to-6 b/src/migration-scripts/dhcp-server/5-to-6 index f5c766a09..9404cd038 100755..100644 --- a/src/migration-scripts/dhcp-server/5-to-6 +++ b/src/migration-scripts/dhcp-server/5-to-6 @@ -1,87 +1,69 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T1968: allow multiple static-routes to be configured # T3838: rename dns-server -> name-server -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcp-server'] -config = ConfigTree(config_file) - -if not config.exists(base + ['shared-network-name']): - # Nothing to do - exit(0) - -# Run this for every instance if 'shared-network-name' -for network in config.list_nodes(base + ['shared-network-name']): - base_network = base + ['shared-network-name', network] - - if not config.exists(base_network + ['subnet']): - continue - - # Run this for every specified 'subnet' - for subnet in config.list_nodes(base_network + ['subnet']): - base_subnet = base_network + ['subnet', subnet] - - # T1968: allow multiple static-routes to be configured - if config.exists(base_subnet + ['static-route']): - prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet']) - router = config.return_value(base_subnet + ['static-route', 'router']) - config.delete(base_subnet + ['static-route']) - - config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router) - config.set_tag(base_subnet + ['static-route']) - - # T3838: rename dns-server -> name-server - if config.exists(base_subnet + ['dns-server']): - config.rename(base_subnet + ['dns-server'], 'name-server') - - - # T3672: ISC DHCP server only supports one failover peer - if config.exists(base_subnet + ['failover']): - # There can only be one failover configuration, if none is present - # we add the first one - if not config.exists(base + ['failover']): - local = config.return_value(base_subnet + ['failover', 'local-address']) - remote = config.return_value(base_subnet + ['failover', 'peer-address']) - status = config.return_value(base_subnet + ['failover', 'status']) - name = config.return_value(base_subnet + ['failover', 'name']) - - config.set(base + ['failover', 'remote'], value=remote) - config.set(base + ['failover', 'source-address'], value=local) - config.set(base + ['failover', 'status'], value=status) - config.set(base + ['failover', 'name'], value=name) - - config.delete(base_subnet + ['failover']) - config.set(base_subnet + ['enable-failover']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base + ['shared-network-name']): + # Nothing to do + return + + # Run this for every instance if 'shared-network-name' + for network in config.list_nodes(base + ['shared-network-name']): + base_network = base + ['shared-network-name', network] + + if not config.exists(base_network + ['subnet']): + continue + + # Run this for every specified 'subnet' + for subnet in config.list_nodes(base_network + ['subnet']): + base_subnet = base_network + ['subnet', subnet] + + # T1968: allow multiple static-routes to be configured + if config.exists(base_subnet + ['static-route']): + prefix = config.return_value(base_subnet + ['static-route', 'destination-subnet']) + router = config.return_value(base_subnet + ['static-route', 'router']) + config.delete(base_subnet + ['static-route']) + + config.set(base_subnet + ['static-route', prefix, 'next-hop'], value=router) + config.set_tag(base_subnet + ['static-route']) + + # T3838: rename dns-server -> name-server + if config.exists(base_subnet + ['dns-server']): + config.rename(base_subnet + ['dns-server'], 'name-server') + + + # T3672: ISC DHCP server only supports one failover peer + if config.exists(base_subnet + ['failover']): + # There can only be one failover configuration, if none is present + # we add the first one + if not config.exists(base + ['failover']): + local = config.return_value(base_subnet + ['failover', 'local-address']) + remote = config.return_value(base_subnet + ['failover', 'peer-address']) + status = config.return_value(base_subnet + ['failover', 'status']) + name = config.return_value(base_subnet + ['failover', 'name']) + + config.set(base + ['failover', 'remote'], value=remote) + config.set(base + ['failover', 'source-address'], value=local) + config.set(base + ['failover', 'status'], value=status) + config.set(base + ['failover', 'name'], value=name) + + config.delete(base_subnet + ['failover']) + config.set(base_subnet + ['enable-failover']) diff --git a/src/migration-scripts/dhcp-server/6-to-7 b/src/migration-scripts/dhcp-server/6-to-7 index e6c298a60..4e6583a31 100755..100644 --- a/src/migration-scripts/dhcp-server/6-to-7 +++ b/src/migration-scripts/dhcp-server/6-to-7 @@ -1,76 +1,58 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6079: Disable duplicate static mappings -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcp-server'] -config = ConfigTree(config_file) - -if not config.exists(base + ['shared-network-name']): - # Nothing to do - exit(0) -# Run this for every instance if 'shared-network-name' -for network in config.list_nodes(base + ['shared-network-name']): - base_network = base + ['shared-network-name', network] +def migrate(config: ConfigTree) -> None: + if not config.exists(base + ['shared-network-name']): + # Nothing to do + return - if not config.exists(base_network + ['subnet']): - continue + # Run this for every instance if 'shared-network-name' + for network in config.list_nodes(base + ['shared-network-name']): + base_network = base + ['shared-network-name', network] - for subnet in config.list_nodes(base_network + ['subnet']): - base_subnet = base_network + ['subnet', subnet] + if not config.exists(base_network + ['subnet']): + continue - if config.exists(base_subnet + ['static-mapping']): - used_mac = [] - used_ip = [] + for subnet in config.list_nodes(base_network + ['subnet']): + base_subnet = base_network + ['subnet', subnet] - for mapping in config.list_nodes(base_subnet + ['static-mapping']): - base_mapping = base_subnet + ['static-mapping', mapping] + if config.exists(base_subnet + ['static-mapping']): + used_mac = [] + used_ip = [] - if config.exists(base_mapping + ['mac-address']): - mac = config.return_value(base_mapping + ['mac-address']) + for mapping in config.list_nodes(base_subnet + ['static-mapping']): + base_mapping = base_subnet + ['static-mapping', mapping] - if mac in used_mac: - config.set(base_mapping + ['disable']) - else: - used_mac.append(mac) + if config.exists(base_mapping + ['mac-address']): + mac = config.return_value(base_mapping + ['mac-address']) - if config.exists(base_mapping + ['ip-address']): - ip = config.return_value(base_mapping + ['ip-address']) + if mac in used_mac: + config.set(base_mapping + ['disable']) + else: + used_mac.append(mac) - if ip in used_ip: - config.set(base_subnet + ['static-mapping', mapping, 'disable']) - else: - used_ip.append(ip) + if config.exists(base_mapping + ['ip-address']): + ip = config.return_value(base_mapping + ['ip-address']) -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) + if ip in used_ip: + config.set(base_subnet + ['static-mapping', mapping, 'disable']) + else: + used_ip.append(ip) diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8 index ccf385a30..7fcb62e86 100755..100644 --- a/src/migration-scripts/dhcp-server/7-to-8 +++ b/src/migration-scripts/dhcp-server/7-to-8 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: Migrate to Kea # - global-parameters will not function @@ -23,65 +22,48 @@ # - ping-check no longer supported # - failover is default enabled on all subnets that exist on failover servers -import sys from vyos.configtree import ConfigTree -if (len(sys.argv) < 2): - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcp-server'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - sys.exit(0) -if config.exists(base + ['host-decl-name']): - config.delete(base + ['host-decl-name']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -if config.exists(base + ['global-parameters']): - config.delete(base + ['global-parameters']) + if config.exists(base + ['host-decl-name']): + config.delete(base + ['host-decl-name']) -if config.exists(base + ['shared-network-name']): - for network in config.list_nodes(base + ['shared-network-name']): - base_network = base + ['shared-network-name', network] + if config.exists(base + ['global-parameters']): + config.delete(base + ['global-parameters']) - if config.exists(base_network + ['ping-check']): - config.delete(base_network + ['ping-check']) + if config.exists(base + ['shared-network-name']): + for network in config.list_nodes(base + ['shared-network-name']): + base_network = base + ['shared-network-name', network] - if config.exists(base_network + ['shared-network-parameters']): - config.delete(base_network +['shared-network-parameters']) + if config.exists(base_network + ['ping-check']): + config.delete(base_network + ['ping-check']) - if not config.exists(base_network + ['subnet']): - continue + if config.exists(base_network + ['shared-network-parameters']): + config.delete(base_network +['shared-network-parameters']) - # Run this for every specified 'subnet' - for subnet in config.list_nodes(base_network + ['subnet']): - base_subnet = base_network + ['subnet', subnet] + if not config.exists(base_network + ['subnet']): + continue - if config.exists(base_subnet + ['enable-failover']): - config.delete(base_subnet + ['enable-failover']) + # Run this for every specified 'subnet' + for subnet in config.list_nodes(base_network + ['subnet']): + base_subnet = base_network + ['subnet', subnet] - if config.exists(base_subnet + ['ping-check']): - config.delete(base_subnet + ['ping-check']) + if config.exists(base_subnet + ['enable-failover']): + config.delete(base_subnet + ['enable-failover']) - if config.exists(base_subnet + ['subnet-parameters']): - config.delete(base_subnet + ['subnet-parameters']) + if config.exists(base_subnet + ['ping-check']): + config.delete(base_subnet + ['ping-check']) - if config.exists(base_subnet + ['static-mapping']): - for mapping in config.list_nodes(base_subnet + ['static-mapping']): - if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']): - config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']) + if config.exists(base_subnet + ['subnet-parameters']): + config.delete(base_subnet + ['subnet-parameters']) -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) + if config.exists(base_subnet + ['static-mapping']): + for mapping in config.list_nodes(base_subnet + ['static-mapping']): + if config.exists(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']): + config.delete(base_subnet + ['static-mapping', mapping, 'static-mapping-parameters']) diff --git a/src/migration-scripts/dhcp-server/8-to-9 b/src/migration-scripts/dhcp-server/8-to-9 index 151aa6d7b..5843e9fda 100755..100644 --- a/src/migration-scripts/dhcp-server/8-to-9 +++ b/src/migration-scripts/dhcp-server/8-to-9 @@ -1,65 +1,47 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: # - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore) # - Rename "service dhcp-server shared-network-name ... static-mapping <hostname> mac-address ..." # to "service dhcp-server shared-network-name ... static-mapping <hostname> mac ..." -import sys import re from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcp-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - sys.exit(0) - -for network in config.list_nodes(base): - # Run this for every specified 'subnet' - if config.exists(base + [network, 'subnet']): - for subnet in config.list_nodes(base + [network, 'subnet']): - base_subnet = base + [network, 'subnet', subnet] - if config.exists(base_subnet + ['static-mapping']): - for hostname in config.list_nodes(base_subnet + ['static-mapping']): - base_mapping = base_subnet + ['static-mapping', hostname] - - # Rename the 'mac-address' node to 'mac' - if config.exists(base_mapping + ['mac-address']): - config.rename(base_mapping + ['mac-address'], 'mac') - - # Adjust hostname to have valid FQDN characters only - new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname) - if new_hostname != hostname: - config.rename(base_mapping, new_hostname) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for network in config.list_nodes(base): + # Run this for every specified 'subnet' + if config.exists(base + [network, 'subnet']): + for subnet in config.list_nodes(base + [network, 'subnet']): + base_subnet = base + [network, 'subnet', subnet] + if config.exists(base_subnet + ['static-mapping']): + for hostname in config.list_nodes(base_subnet + ['static-mapping']): + base_mapping = base_subnet + ['static-mapping', hostname] + + # Rename the 'mac-address' node to 'mac' + if config.exists(base_mapping + ['mac-address']): + config.rename(base_mapping + ['mac-address'], 'mac') + + # Adjust hostname to have valid FQDN characters only + new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname) + if new_hostname != hostname: + config.rename(base_mapping, new_hostname) diff --git a/src/migration-scripts/dhcp-server/9-to-10 b/src/migration-scripts/dhcp-server/9-to-10 index a459b65b5..eda97550d 100755..100644 --- a/src/migration-scripts/dhcp-server/9-to-10 +++ b/src/migration-scripts/dhcp-server/9-to-10 @@ -1,41 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: # - Migrate dhcp options under new option node # - Add subnet IDs to existing subnets -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcp-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - sys.exit(0) option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-portal', 'client-prefix-length', 'default-router', 'domain-name', 'domain-search', @@ -44,31 +28,30 @@ option_nodes = ['bootfile-name', 'bootfile-server', 'bootfile-size', 'captive-po 'tftp-server-name', 'time-offset', 'time-server', 'time-zone', 'vendor-option', 'wins-server', 'wpad-url'] -subnet_id = 1 -for network in config.list_nodes(base): - for option in option_nodes: - if config.exists(base + [network, option]): - config.set(base + [network, 'option']) - config.copy(base + [network, option], base + [network, 'option', option]) - config.delete(base + [network, option]) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + subnet_id = 1 - if config.exists(base + [network, 'subnet']): - for subnet in config.list_nodes(base + [network, 'subnet']): - base_subnet = base + [network, 'subnet', subnet] + for network in config.list_nodes(base): + for option in option_nodes: + if config.exists(base + [network, option]): + config.set(base + [network, 'option']) + config.copy(base + [network, option], base + [network, 'option', option]) + config.delete(base + [network, option]) - for option in option_nodes: - if config.exists(base_subnet + [option]): - config.set(base_subnet + ['option']) - config.copy(base_subnet + [option], base_subnet + ['option', option]) - config.delete(base_subnet + [option]) + if config.exists(base + [network, 'subnet']): + for subnet in config.list_nodes(base + [network, 'subnet']): + base_subnet = base + [network, 'subnet', subnet] - config.set(base_subnet + ['subnet-id'], value=subnet_id) - subnet_id += 1 + for option in option_nodes: + if config.exists(base_subnet + [option]): + config.set(base_subnet + ['option']) + config.copy(base_subnet + [option], base_subnet + ['option', option]) + config.delete(base_subnet + [option]) -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) + config.set(base_subnet + ['subnet-id'], value=subnet_id) + subnet_id += 1 diff --git a/src/migration-scripts/dhcpv6-server/0-to-1 b/src/migration-scripts/dhcpv6-server/0-to-1 index deae1ca29..fd9b2d739 100755..100644 --- a/src/migration-scripts/dhcpv6-server/0-to-1 +++ b/src/migration-scripts/dhcpv6-server/0-to-1 @@ -1,39 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # combine both sip-server-address and sip-server-name nodes to common sip-server -from sys import argv, exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] +base = ['service', 'dhcpv6-server', 'shared-network-name'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['service', 'dhcpv6-server', 'shared-network-name'] -if not config.exists(base): - # Nothing to do - exit(0) -else: # we need to run this for every configured network for network in config.list_nodes(base): for subnet in config.list_nodes(base + [network, 'subnet']): @@ -52,10 +42,3 @@ else: # Write new CLI value for sip-server for server in sip_server: config.set(base + [network, 'subnet', subnet, 'sip-server'], value=server, replace=False) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/dhcpv6-server/1-to-2 b/src/migration-scripts/dhcpv6-server/1-to-2 index cc5a8900a..ad307495c 100755..100644 --- a/src/migration-scripts/dhcpv6-server/1-to-2 +++ b/src/migration-scripts/dhcpv6-server/1-to-2 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: Migrate to Kea # - Kea was meant to have support for key "prefix-highest" under PD which would allow an address range @@ -20,67 +19,50 @@ # Ref: https://lists.isc.org/pipermail/kea-users/2022-November/003686.html # - Remove prefix temporary value, convert to multi leafNode (https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp6-srv.html#dhcpv6-server-limitations) -import sys from vyos.configtree import ConfigTree from vyos.utils.network import ipv6_prefix_length -if (len(sys.argv) < 1): - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcpv6-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -for network in config.list_nodes(base): - if not config.exists(base + [network, 'subnet']): - continue +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - for subnet in config.list_nodes(base + [network, 'subnet']): - # Delete temporary value under address-range prefix, convert tagNode to leafNode multi - if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']): - prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix'] - prefixes = config.list_nodes(prefix_base) - - config.delete(prefix_base) + for network in config.list_nodes(base): + if not config.exists(base + [network, 'subnet']): + continue - for prefix in prefixes: - config.set(prefix_base, value=prefix, replace=False) + for subnet in config.list_nodes(base + [network, 'subnet']): + # Delete temporary value under address-range prefix, convert tagNode to leafNode multi + if config.exists(base + [network, 'subnet', subnet, 'address-range', 'prefix']): + prefix_base = base + [network, 'subnet', subnet, 'address-range', 'prefix'] + prefixes = config.list_nodes(prefix_base) + + config.delete(prefix_base) - if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']): - prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix'] + for prefix in prefixes: + config.set(prefix_base, value=prefix, replace=False) - config.set(prefix_base) - config.set_tag(prefix_base) + if config.exists(base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix']): + prefix_base = base + [network, 'subnet', subnet, 'prefix-delegation', 'prefix'] - for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']): - path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start] + config.set(prefix_base) + config.set_tag(prefix_base) - delegated_length = config.return_value(path + ['prefix-length']) - stop = config.return_value(path + ['stop']) + for start in config.list_nodes(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']): + path = base + [network, 'subnet', subnet, 'prefix-delegation', 'start', start] - prefix_length = ipv6_prefix_length(start, stop) + delegated_length = config.return_value(path + ['prefix-length']) + stop = config.return_value(path + ['stop']) - # This range could not be converted into a simple prefix length and must be skipped - if not prefix_length: - continue + prefix_length = ipv6_prefix_length(start, stop) - config.set(prefix_base + [start, 'delegated-length'], value=delegated_length) - config.set(prefix_base + [start, 'prefix-length'], value=prefix_length) + # This range could not be converted into a simple prefix length and must be skipped + if not prefix_length: + continue - config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']) + config.set(prefix_base + [start, 'delegated-length'], value=delegated_length) + config.set(prefix_base + [start, 'prefix-length'], value=prefix_length) -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) + config.delete(base + [network, 'subnet', subnet, 'prefix-delegation', 'start']) diff --git a/src/migration-scripts/dhcpv6-server/2-to-3 b/src/migration-scripts/dhcpv6-server/2-to-3 index f4bdc1d1e..b44798d18 100755..100644 --- a/src/migration-scripts/dhcpv6-server/2-to-3 +++ b/src/migration-scripts/dhcpv6-server/2-to-3 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: # - Adjust hostname to have valid FQDN characters only (underscores aren't allowed anymore) @@ -22,57 +21,40 @@ # - Rename "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac-address ..." # to "service dhcpv6-server shared-network-name ... static-mapping <hostname> mac ..." -import sys import re from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcpv6-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - sys.exit(0) - -for network in config.list_nodes(base): - # Run this for every specified 'subnet' - if config.exists(base + [network, 'subnet']): - for subnet in config.list_nodes(base + [network, 'subnet']): - base_subnet = base + [network, 'subnet', subnet] - if config.exists(base_subnet + ['static-mapping']): - for hostname in config.list_nodes(base_subnet + ['static-mapping']): - base_mapping = base_subnet + ['static-mapping', hostname] - if config.exists(base_mapping + ['identifier']): - - # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...) - duid = config.return_value(base_mapping + ['identifier']) - new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':')) - if new_duid != duid: - config.set(base_mapping + ['identifier'], new_duid) - - # Rename the 'identifier' node to 'duid' - config.rename(base_mapping + ['identifier'], 'duid') - - # Rename the 'mac-address' node to 'mac' - if config.exists(base_mapping + ['mac-address']): - config.rename(base_mapping + ['mac-address'], 'mac') - - # Adjust hostname to have valid FQDN characters only - new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname) - if new_hostname != hostname: - config.rename(base_mapping, new_hostname) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for network in config.list_nodes(base): + # Run this for every specified 'subnet' + if config.exists(base + [network, 'subnet']): + for subnet in config.list_nodes(base + [network, 'subnet']): + base_subnet = base + [network, 'subnet', subnet] + if config.exists(base_subnet + ['static-mapping']): + for hostname in config.list_nodes(base_subnet + ['static-mapping']): + base_mapping = base_subnet + ['static-mapping', hostname] + if config.exists(base_mapping + ['identifier']): + + # Adjust duid to comply with duid format (a:3:b:04:... => 0a:03:0b:04:...) + duid = config.return_value(base_mapping + ['identifier']) + new_duid = ':'.join(x.rjust(2,'0') for x in duid.split(':')) + if new_duid != duid: + config.set(base_mapping + ['identifier'], new_duid) + + # Rename the 'identifier' node to 'duid' + config.rename(base_mapping + ['identifier'], 'duid') + + # Rename the 'mac-address' node to 'mac' + if config.exists(base_mapping + ['mac-address']): + config.rename(base_mapping + ['mac-address'], 'mac') + + # Adjust hostname to have valid FQDN characters only + new_hostname = re.sub(r'[^a-zA-Z0-9-.]', '-', hostname) + if new_hostname != hostname: + config.rename(base_mapping, new_hostname) diff --git a/src/migration-scripts/dhcpv6-server/3-to-4 b/src/migration-scripts/dhcpv6-server/3-to-4 index 7efc492a5..e38e36505 100755..100644 --- a/src/migration-scripts/dhcpv6-server/3-to-4 +++ b/src/migration-scripts/dhcpv6-server/3-to-4 @@ -1,89 +1,72 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3316: # - Add subnet IDs to existing subnets # - Move options to option node # - Migrate address-range to range tagNode -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcpv6-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - sys.exit(0) option_nodes = ['captive-portal', 'domain-search', 'name-server', 'nis-domain', 'nis-server', 'nisplus-domain', 'nisplus-server', 'sip-server', 'sntp-server', 'vendor-option'] -subnet_id = 1 -for network in config.list_nodes(base): - if config.exists(base + [network, 'subnet']): - for subnet in config.list_nodes(base + [network, 'subnet']): - base_subnet = base + [network, 'subnet', subnet] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + subnet_id = 1 - if config.exists(base_subnet + ['address-range']): - config.set(base_subnet + ['range']) - config.set_tag(base_subnet + ['range']) + for network in config.list_nodes(base): + if config.exists(base + [network, 'subnet']): + for subnet in config.list_nodes(base + [network, 'subnet']): + base_subnet = base + [network, 'subnet', subnet] - range_id = 1 + if config.exists(base_subnet + ['address-range']): + config.set(base_subnet + ['range']) + config.set_tag(base_subnet + ['range']) - if config.exists(base_subnet + ['address-range', 'prefix']): - for prefix in config.return_values(base_subnet + ['address-range', 'prefix']): - config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix) + range_id = 1 - range_id += 1 + if config.exists(base_subnet + ['address-range', 'prefix']): + for prefix in config.return_values(base_subnet + ['address-range', 'prefix']): + config.set(base_subnet + ['range', range_id, 'prefix'], value=prefix) - if config.exists(base_subnet + ['address-range', 'start']): - for start in config.list_nodes(base_subnet + ['address-range', 'start']): - stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop']) + range_id += 1 - config.set(base_subnet + ['range', range_id, 'start'], value=start) - config.set(base_subnet + ['range', range_id, 'stop'], value=stop) + if config.exists(base_subnet + ['address-range', 'start']): + for start in config.list_nodes(base_subnet + ['address-range', 'start']): + stop = config.return_value(base_subnet + ['address-range', 'start', start, 'stop']) - range_id += 1 + config.set(base_subnet + ['range', range_id, 'start'], value=start) + config.set(base_subnet + ['range', range_id, 'stop'], value=stop) - config.delete(base_subnet + ['address-range']) + range_id += 1 - for option in option_nodes: - if config.exists(base_subnet + [option]): - config.set(base_subnet + ['option']) - config.copy(base_subnet + [option], base_subnet + ['option', option]) - config.delete(base_subnet + [option]) + config.delete(base_subnet + ['address-range']) - config.set(base_subnet + ['subnet-id'], value=subnet_id) - subnet_id += 1 + for option in option_nodes: + if config.exists(base_subnet + [option]): + config.set(base_subnet + ['option']) + config.copy(base_subnet + [option], base_subnet + ['option', option]) + config.delete(base_subnet + [option]) -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) + config.set(base_subnet + ['subnet-id'], value=subnet_id) + subnet_id += 1 diff --git a/src/migration-scripts/dhcpv6-server/4-to-5 b/src/migration-scripts/dhcpv6-server/4-to-5 index 55fda91b3..ad18e1a84 100755..100644 --- a/src/migration-scripts/dhcpv6-server/4-to-5 +++ b/src/migration-scripts/dhcpv6-server/4-to-5 @@ -1,91 +1,73 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5993: Check if subnet is locally accessible and assign interface to subnet -import sys from ipaddress import ip_network from vyos.configtree import ConfigTree -if (len(sys.argv) < 1): - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['service', 'dhcpv6-server', 'shared-network-name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -def find_subnet_interface(subnet): - subnet_net = ip_network(subnet) - - def check_addr(if_path): - if config.exists(if_path + ['address']): - for addr in config.return_values(if_path + ['address']): - try: - if ip_network(addr, strict=False) == subnet_net: - return True - except: - pass # interface address was probably "dhcp" or other magic string - return None - - for iftype in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', iftype]): - if_base = ['interfaces', iftype, ifname] - - if check_addr(if_base): - return ifname - - if config.exists(if_base + ['vif']): - for vif in config.list_nodes(if_base + ['vif']): - if check_addr(if_base + ['vif', vif]): - return f'{ifname}.{vif}' - - if config.exists(if_base + ['vif-s']): - for vifs in config.list_nodes(if_base + ['vif-s']): - if check_addr(if_base + ['vif-s', vifs]): - return f'{ifname}.{vifs}' - - if config.exists(if_base + ['vif-s', vifs, 'vif-c']): - for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']): - if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]): - return f'{ifname}.{vifs}.{vifc}' - - return False - -for network in config.list_nodes(base): - if not config.exists(base + [network, 'subnet']): - continue - - for subnet in config.list_nodes(base + [network, 'subnet']): - subnet_interface = find_subnet_interface(subnet) - - if subnet_interface: - config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + def find_subnet_interface(subnet): + subnet_net = ip_network(subnet) + + def check_addr(if_path): + if config.exists(if_path + ['address']): + for addr in config.return_values(if_path + ['address']): + try: + if ip_network(addr, strict=False) == subnet_net: + return True + except: + pass # interface address was probably "dhcp" or other magic string + return None + + for iftype in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', iftype]): + if_base = ['interfaces', iftype, ifname] + + if check_addr(if_base): + return ifname + + if config.exists(if_base + ['vif']): + for vif in config.list_nodes(if_base + ['vif']): + if check_addr(if_base + ['vif', vif]): + return f'{ifname}.{vif}' + + if config.exists(if_base + ['vif-s']): + for vifs in config.list_nodes(if_base + ['vif-s']): + if check_addr(if_base + ['vif-s', vifs]): + return f'{ifname}.{vifs}' + + if config.exists(if_base + ['vif-s', vifs, 'vif-c']): + for vifc in config.list_nodes(if_base + ['vif-s', vifs, 'vif-c']): + if check_addr(if_base + ['vif-s', vifs, 'vif-c', vifc]): + return f'{ifname}.{vifs}.{vifc}' + + return False + + for network in config.list_nodes(base): + if not config.exists(base + [network, 'subnet']): + continue + + for subnet in config.list_nodes(base + [network, 'subnet']): + subnet_interface = find_subnet_interface(subnet) + + if subnet_interface: + config.set(base + [network, 'subnet', subnet, 'interface'], value=subnet_interface) diff --git a/src/migration-scripts/dns-dynamic/0-to-1 b/src/migration-scripts/dns-dynamic/0-to-1 index b7674a9c8..6a91b36af 100755..100644 --- a/src/migration-scripts/dns-dynamic/0-to-1 +++ b/src/migration-scripts/dns-dynamic/0-to-1 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5144: # - migrate "service dns dynamic interface ..." @@ -27,7 +26,6 @@ # - apply service protocol mapping upfront, they are not 'auto-detected' anymore # - migrate web-options url to stricter format -import sys import re from vyos.configtree import ConfigTree @@ -45,84 +43,67 @@ service_protocol_mapping = { 'zoneedit': 'zoneedit1' } -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - old_base_path = ['service', 'dns', 'dynamic', 'interface'] new_base_path = ['service', 'dns', 'dynamic', 'address'] -if not config.exists(old_base_path): - # Nothing to do - sys.exit(0) - -# Migrate "service dns dynamic interface" -# to "service dns dynamic address" -config.rename(old_base_path, new_base_path[-1]) - -for address in config.list_nodes(new_base_path): - # Migrate "service dns dynamic interface <interface> rfc2136 <config> record" - # to "service dns dynamic address <address> rfc2136 <config> host-name" - if config.exists(new_base_path + [address, 'rfc2136']): - for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']): - if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']): - config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name') - - # Migrate "service dns dynamic interface <interface> service <config> login" - # to "service dns dynamic address <address> service <config> username" - if config.exists(new_base_path + [address, 'service']): - for svc_cfg in config.list_nodes(new_base_path + [address, 'service']): - if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']): - config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username') - # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6' - if config.exists(new_base_path + [address, 'ipv6-enable']): - config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6') - config.delete(new_base_path + [address, 'ipv6-enable']) - # Apply service protocol mapping upfront, they are not 'auto-detected' anymore - if svc_cfg in service_protocol_mapping: - config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'], - service_protocol_mapping.get(svc_cfg)) - - # If use-web is set, then: - # Move "service dns dynamic address <address> <service|rfc2136> <service> ..." - # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..." - # Move "service dns dynamic address web use-web ..." - # to "service dns dynamic address web web-options ..." - # Note: The config is named <service>-<address> to avoid name conflict with old entries - if config.exists(new_base_path + [address, 'use-web']): - for svc_type in ['rfc2136', 'service']: - if config.exists(new_base_path + [address, svc_type]): - config.set(new_base_path + ['web', svc_type]) - config.set_tag(new_base_path + ['web', svc_type]) - for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]): - config.copy(new_base_path + [address, svc_type, svc_cfg], - new_base_path + ['web', svc_type, f'{svc_cfg}-{address}']) - - # Multiple web-options were not supported, so copy only the first one - # Also, migrate web-options url to stricter format and transition - # checkip.dyndns.org to https://domains.google.com/checkip for better - # TLS support (see: https://github.com/ddclient/ddclient/issues/597) - if not config.exists(new_base_path + ['web', 'web-options']): - config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options']) - if config.exists(new_base_path + ['web', 'web-options', 'url']): - url = config.return_value(new_base_path + ['web', 'web-options', 'url']) - if re.search("^(https?://)?checkip\.dyndns\.org", url): - config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip') - if not url.startswith(('http://', 'https://')): - config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}') - - config.delete(new_base_path + [address]) - -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)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(old_base_path): + # Nothing to do + return + + # Migrate "service dns dynamic interface" + # to "service dns dynamic address" + config.rename(old_base_path, new_base_path[-1]) + + for address in config.list_nodes(new_base_path): + # Migrate "service dns dynamic interface <interface> rfc2136 <config> record" + # to "service dns dynamic address <address> rfc2136 <config> host-name" + if config.exists(new_base_path + [address, 'rfc2136']): + for rfc_cfg in config.list_nodes(new_base_path + [address, 'rfc2136']): + if config.exists(new_base_path + [address, 'rfc2136', rfc_cfg, 'record']): + config.rename(new_base_path + [address, 'rfc2136', rfc_cfg, 'record'], 'host-name') + + # Migrate "service dns dynamic interface <interface> service <config> login" + # to "service dns dynamic address <address> service <config> username" + if config.exists(new_base_path + [address, 'service']): + for svc_cfg in config.list_nodes(new_base_path + [address, 'service']): + if config.exists(new_base_path + [address, 'service', svc_cfg, 'login']): + config.rename(new_base_path + [address, 'service', svc_cfg, 'login'], 'username') + # Apply global 'ipv6-enable' to per <config> 'ip-version: ipv6' + if config.exists(new_base_path + [address, 'ipv6-enable']): + config.set(new_base_path + [address, 'service', svc_cfg, 'ip-version'], 'ipv6') + config.delete(new_base_path + [address, 'ipv6-enable']) + # Apply service protocol mapping upfront, they are not 'auto-detected' anymore + if svc_cfg in service_protocol_mapping: + config.set(new_base_path + [address, 'service', svc_cfg, 'protocol'], + service_protocol_mapping.get(svc_cfg)) + + # If use-web is set, then: + # Move "service dns dynamic address <address> <service|rfc2136> <service> ..." + # to "service dns dynamic address web <service|rfc2136> <service>-<address> ..." + # Move "service dns dynamic address web use-web ..." + # to "service dns dynamic address web web-options ..." + # Note: The config is named <service>-<address> to avoid name conflict with old entries + if config.exists(new_base_path + [address, 'use-web']): + for svc_type in ['rfc2136', 'service']: + if config.exists(new_base_path + [address, svc_type]): + config.set(new_base_path + ['web', svc_type]) + config.set_tag(new_base_path + ['web', svc_type]) + for svc_cfg in config.list_nodes(new_base_path + [address, svc_type]): + config.copy(new_base_path + [address, svc_type, svc_cfg], + new_base_path + ['web', svc_type, f'{svc_cfg}-{address}']) + + # Multiple web-options were not supported, so copy only the first one + # Also, migrate web-options url to stricter format and transition + # checkip.dyndns.org to https://domains.google.com/checkip for better + # TLS support (see: https://github.com/ddclient/ddclient/issues/597) + if not config.exists(new_base_path + ['web', 'web-options']): + config.copy(new_base_path + [address, 'use-web'], new_base_path + ['web', 'web-options']) + if config.exists(new_base_path + ['web', 'web-options', 'url']): + url = config.return_value(new_base_path + ['web', 'web-options', 'url']) + if re.search("^(https?://)?checkip\.dyndns\.org", url): + config.set(new_base_path + ['web', 'web-options', 'url'], 'https://domains.google.com/checkip') + if not url.startswith(('http://', 'https://')): + config.set(new_base_path + ['web', 'web-options', 'url'], f'https://{url}') + + config.delete(new_base_path + [address]) diff --git a/src/migration-scripts/dns-dynamic/1-to-2 b/src/migration-scripts/dns-dynamic/1-to-2 index 8b599b57a..5dca9e32f 100755..100644 --- a/src/migration-scripts/dns-dynamic/1-to-2 +++ b/src/migration-scripts/dns-dynamic/1-to-2 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5708: # - migrate "service dns dynamic timeout ..." @@ -21,50 +20,32 @@ # - migrate "service dns dynamic address <interface> service <service> protocol dnsexit" # to "service dns dynamic address <interface> service <service> protocol dnsexit2" -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base_path = ['service', 'dns', 'dynamic'] timeout_path = base_path + ['timeout'] address_path = base_path + ['address'] -if not config.exists(base_path): - # Nothing to do - sys.exit(0) - -# Migrate "service dns dynamic timeout ..." -# to "service dns dynamic interval ..." -if config.exists(timeout_path): - config.rename(timeout_path, 'interval') - -# Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web" -for address in config.list_nodes(address_path): - if config.exists(address_path + [address, 'web-options']) and address != 'web': - config.delete(address_path + [address, 'web-options']) - -# Migrate "service dns dynamic address <interface> service <service> protocol dnsexit" -# to "service dns dynamic address <interface> service <service> protocol dnsexit2" -for address in config.list_nodes(address_path): - for svc_cfg in config.list_nodes(address_path + [address, 'service']): - if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']): - protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol']) - if protocol == 'dnsexit': - config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2') - -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)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return + + # Migrate "service dns dynamic timeout ..." + # to "service dns dynamic interval ..." + if config.exists(timeout_path): + config.rename(timeout_path, 'interval') + + # Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web" + for address in config.list_nodes(address_path): + if config.exists(address_path + [address, 'web-options']) and address != 'web': + config.delete(address_path + [address, 'web-options']) + + # Migrate "service dns dynamic address <interface> service <service> protocol dnsexit" + # to "service dns dynamic address <interface> service <service> protocol dnsexit2" + for address in config.list_nodes(address_path): + for svc_cfg in config.list_nodes(address_path + [address, 'service']): + if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']): + protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol']) + if protocol == 'dnsexit': + config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2') diff --git a/src/migration-scripts/dns-dynamic/2-to-3 b/src/migration-scripts/dns-dynamic/2-to-3 index 4e0aa37d5..9aafc41a4 100755..100644 --- a/src/migration-scripts/dns-dynamic/2-to-3 +++ b/src/migration-scripts/dns-dynamic/2-to-3 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5791: # - migrate "service dns dynamic address web web-options ..." @@ -23,7 +22,6 @@ # to "service dns dynamic name <service> address <interface> ..." # - normalize the all service names to conform with name constraints -import sys import re from unicodedata import normalize from vyos.configtree import ConfigTree @@ -41,79 +39,61 @@ def normalize_name(name): return name - -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base_path = ['service', 'dns', 'dynamic'] address_path = base_path + ['address'] name_path = base_path + ['name'] -if not config.exists(address_path): - # Nothing to do - sys.exit(0) +def migrate(config: ConfigTree) -> None: + if not config.exists(address_path): + # Nothing to do + return -# config.copy does not recursively create a path, so initialize the name path as tagged node -if not config.exists(name_path): - config.set(name_path) - config.set_tag(name_path) + # config.copy does not recursively create a path, so initialize the name path as tagged node + if not config.exists(name_path): + config.set(name_path) + config.set_tag(name_path) -for address in config.list_nodes(address_path): + for address in config.list_nodes(address_path): - address_path_tag = address_path + [address] + address_path_tag = address_path + [address] + + # Move web-option as a configuration in each service instead of top level web-option + if config.exists(address_path_tag + ['web-options']) and address == 'web': + for svc_type in ['service', 'rfc2136']: + if config.exists(address_path_tag + [svc_type]): + for svc_cfg in config.list_nodes(address_path_tag + [svc_type]): + config.copy(address_path_tag + ['web-options'], + address_path_tag + [svc_type, svc_cfg, 'web-options']) + config.delete(address_path_tag + ['web-options']) - # Move web-option as a configuration in each service instead of top level web-option - if config.exists(address_path_tag + ['web-options']) and address == 'web': for svc_type in ['service', 'rfc2136']: if config.exists(address_path_tag + [svc_type]): + # Set protocol to 'nsupdate' for RFC2136 configuration + if svc_type == 'rfc2136': + for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']): + config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate') + + # Add address as config value in each service before moving the service path + # And then copy the services from 'address <interface> service <service>' + # to 'name (service|rfc2136)-<service>-<address>' + # Note: The new service is named (service|rfc2136)-<service>-<address> + # to avoid name conflict with old entries for svc_cfg in config.list_nodes(address_path_tag + [svc_type]): - config.copy(address_path_tag + ['web-options'], - address_path_tag + [svc_type, svc_cfg, 'web-options']) - config.delete(address_path_tag + ['web-options']) - - for svc_type in ['service', 'rfc2136']: - if config.exists(address_path_tag + [svc_type]): - # Set protocol to 'nsupdate' for RFC2136 configuration - if svc_type == 'rfc2136': - for rfc_cfg in config.list_nodes(address_path_tag + ['rfc2136']): - config.set(address_path_tag + ['rfc2136', rfc_cfg, 'protocol'], 'nsupdate') - - # Add address as config value in each service before moving the service path - # And then copy the services from 'address <interface> service <service>' - # to 'name (service|rfc2136)-<service>-<address>' - # Note: The new service is named (service|rfc2136)-<service>-<address> - # to avoid name conflict with old entries - for svc_cfg in config.list_nodes(address_path_tag + [svc_type]): - config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address) - config.copy(address_path_tag + [svc_type, svc_cfg], - name_path + ['-'.join([svc_type, svc_cfg, address])]) - -# Finally cleanup the old address path -config.delete(address_path) - -# Normalize the all service names to conform with name constraints -index = 1 -for name in config.list_nodes(name_path): - new_name = normalize_name(name) - if new_name != name: - # Append index if there is still a name conflicts after normalization - # For example, "foo-?(" and "foo-!)" both normalize to "foo-" - if config.exists(name_path + [new_name]): - new_name = f'{new_name}-{index}' - index += 1 - config.rename(name_path + [name], new_name) - -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)) - sys.exit(1) + config.set(address_path_tag + [svc_type, svc_cfg, 'address'], address) + config.copy(address_path_tag + [svc_type, svc_cfg], + name_path + ['-'.join([svc_type, svc_cfg, address])]) + + # Finally cleanup the old address path + config.delete(address_path) + + # Normalize the all service names to conform with name constraints + index = 1 + for name in config.list_nodes(name_path): + new_name = normalize_name(name) + if new_name != name: + # Append index if there is still a name conflicts after normalization + # For example, "foo-?(" and "foo-!)" both normalize to "foo-" + if config.exists(name_path + [new_name]): + new_name = f'{new_name}-{index}' + index += 1 + config.rename(name_path + [name], new_name) diff --git a/src/migration-scripts/dns-dynamic/3-to-4 b/src/migration-scripts/dns-dynamic/3-to-4 index b888a3b6b..c8e1ffeee 100755..100644 --- a/src/migration-scripts/dns-dynamic/3-to-4 +++ b/src/migration-scripts/dns-dynamic/3-to-4 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2024 VyOS maintainers and contributors +# Copyright 2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5966: # - migrate "service dns dynamic name <service> address <interface>" @@ -22,55 +21,37 @@ # to "service dns dynamic name <service> address web ..." # when <interface> == 'web' -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base_path = ['service', 'dns', 'dynamic', 'name'] -if not config.exists(base_path): - # Nothing to do - sys.exit(0) - -for service in config.list_nodes(base_path): +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return - service_path = base_path + [service] + for service in config.list_nodes(base_path): - if config.exists(service_path + ['address']): - address = config.return_value(service_path + ['address']) - # 'address' is not a leaf node anymore, delete it first - config.delete(service_path + ['address']) + service_path = base_path + [service] - # When address is an interface (not 'web'), move it to 'address interface' - if address != 'web': - config.set(service_path + ['address', 'interface'], address) + if config.exists(service_path + ['address']): + address = config.return_value(service_path + ['address']) + # 'address' is not a leaf node anymore, delete it first + config.delete(service_path + ['address']) - else: # address == 'web' - # Relocate optional 'web-options' directly under 'address web' - if config.exists(service_path + ['web-options']): - # config.copy does not recursively create a path, so initialize it - config.set(service_path + ['address']) - config.copy(service_path + ['web-options'], - service_path + ['address', 'web']) - config.delete(service_path + ['web-options']) + # When address is an interface (not 'web'), move it to 'address interface' + if address != 'web': + config.set(service_path + ['address', 'interface'], address) - # ensure that valueless 'address web' still exists even if there are no 'web-options' - if not config.exists(service_path + ['address', 'web']): - config.set(service_path + ['address', 'web']) + else: # address == 'web' + # Relocate optional 'web-options' directly under 'address web' + if config.exists(service_path + ['web-options']): + # config.copy does not recursively create a path, so initialize it + config.set(service_path + ['address']) + config.copy(service_path + ['web-options'], + service_path + ['address', 'web']) + config.delete(service_path + ['web-options']) -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)) - sys.exit(1) + # ensure that valueless 'address web' still exists even if there are no 'web-options' + if not config.exists(service_path + ['address', 'web']): + config.set(service_path + ['address', 'web']) diff --git a/src/migration-scripts/dns-forwarding/0-to-1 b/src/migration-scripts/dns-forwarding/0-to-1 index 7f4343652..264ffb40d 100755..100644 --- a/src/migration-scripts/dns-forwarding/0-to-1 +++ b/src/migration-scripts/dns-forwarding/0-to-1 @@ -1,50 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2019 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. # This migration script will check if there is a allow-from directive configured # for the dns forwarding service - if not, the node will be created with the old # default values of 0.0.0.0/0 and ::/0 -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +base = ['service', 'dns', 'forwarding'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree)-> None: + if not config.exists(base): + # Nothing to do + return -base = ['service', 'dns', 'forwarding'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: if not config.exists(base + ['allow-from']): config.set(base + ['allow-from'], value='0.0.0.0/0', replace=False) config.set(base + ['allow-from'], value='::/0', replace=False) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/dns-forwarding/1-to-2 b/src/migration-scripts/dns-forwarding/1-to-2 index 7df2d47e2..15ed1e136 100755..100644 --- a/src/migration-scripts/dns-forwarding/1-to-2 +++ b/src/migration-scripts/dns-forwarding/1-to-2 @@ -1,19 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2019 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. # This migration script will remove the deprecated 'listen-on' statement # from the dns forwarding service and will add the corresponding @@ -21,66 +19,49 @@ # on interface addresses and not on interface names. from ipaddress import ip_interface -from sys import argv, exit from vyos.ifconfig import Interface from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'dns', 'forwarding'] -if not config.exists(base + ['listen-on']): - # Nothing to do - exit(0) -listen_intf = config.return_values(base + ['listen-on']) -# Delete node with abandoned command -config.delete(base + ['listen-on']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base + ['listen-on']): + # Nothing to do + return -# retrieve interface addresses for every configured listen-on interface -listen_addr = [] -for intf in listen_intf: - # we need to evaluate the interface section before manipulating the 'intf' variable - section = Interface.section(intf) - if not section: - raise ValueError(f'Invalid interface name {intf}') + listen_intf = config.return_values(base + ['listen-on']) + # Delete node with abandoned command + config.delete(base + ['listen-on']) - # we need to treat vif and vif-s interfaces differently, - # both "real interfaces" use dots for vlan identifiers - those - # need to be exchanged with vif and vif-s identifiers - if intf.count('.') == 1: - # this is a regular VLAN interface - intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1] - elif intf.count('.') == 2: - # this is a QinQ VLAN interface - intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2] + # retrieve interface addresses for every configured listen-on interface + listen_addr = [] + for intf in listen_intf: + # we need to evaluate the interface section before manipulating the 'intf' variable + section = Interface.section(intf) + if not section: + raise ValueError(f'Invalid interface name {intf}') - # retrieve corresponding interface addresses in CIDR format - # those need to be converted in pure IP addresses without network information - path = ['interfaces', section, intf, 'address'] - try: - for addr in config.return_values(path): - listen_addr.append( ip_interface(addr).ip ) - except: - # Some interface types do not use "address" option (e.g. OpenVPN) - # and may not even have a fixed address - print("Could not retrieve the address of the interface {} from the config".format(intf)) - print("You will need to update your DNS forwarding configuration manually") + # we need to treat vif and vif-s interfaces differently, + # both "real interfaces" use dots for vlan identifiers - those + # need to be exchanged with vif and vif-s identifiers + if intf.count('.') == 1: + # this is a regular VLAN interface + intf = intf.split('.')[0] + ' vif ' + intf.split('.')[1] + elif intf.count('.') == 2: + # this is a QinQ VLAN interface + intf = intf.split('.')[0] + ' vif-s ' + intf.split('.')[1] + ' vif-c ' + intf.split('.')[2] -for addr in listen_addr: - config.set(base + ['listen-address'], value=addr, replace=False) + # retrieve corresponding interface addresses in CIDR format + # those need to be converted in pure IP addresses without network information + path = ['interfaces', section, intf, 'address'] + try: + for addr in config.return_values(path): + listen_addr.append( ip_interface(addr).ip ) + except: + # Some interface types do not use "address" option (e.g. OpenVPN) + # and may not even have a fixed address + print("Could not retrieve the address of the interface {} from the config".format(intf)) + print("You will need to update your DNS forwarding configuration manually") -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + for addr in listen_addr: + config.set(base + ['listen-address'], value=addr, replace=False) diff --git a/src/migration-scripts/dns-forwarding/2-to-3 b/src/migration-scripts/dns-forwarding/2-to-3 index d7ff9e260..729c1f00a 100755..100644 --- a/src/migration-scripts/dns-forwarding/2-to-3 +++ b/src/migration-scripts/dns-forwarding/2-to-3 @@ -1,51 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. # Sets the new options "addnta" and "recursion-desired" for all # 'dns forwarding domain' as this is usually desired -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'dns', 'forwarding'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -if config.exists(base + ['domain']): - for domain in config.list_nodes(base + ['domain']): - domain_base = base + ['domain', domain] - config.set(domain_base + ['addnta']) - config.set(domain_base + ['recursion-desired']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - 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)) - sys.exit(1) + if config.exists(base + ['domain']): + for domain in config.list_nodes(base + ['domain']): + domain_base = base + ['domain', domain] + config.set(domain_base + ['addnta']) + config.set(domain_base + ['recursion-desired']) diff --git a/src/migration-scripts/dns-forwarding/3-to-4 b/src/migration-scripts/dns-forwarding/3-to-4 index 3d5316ed4..b02c0b7ca 100755..100644 --- a/src/migration-scripts/dns-forwarding/3-to-4 +++ b/src/migration-scripts/dns-forwarding/3-to-4 @@ -1,49 +1,31 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5115: migrate "service dns forwarding domain example.com server" to # "service dns forwarding domain example.com name-server" -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'dns', 'forwarding', 'domain'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -for domain in config.list_nodes(base): - if config.exists(base + [domain, 'server']): - config.copy(base + [domain, 'server'], base + [domain, 'name-server']) - config.delete(base + [domain, 'server']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -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)) - sys.exit(1) + for domain in config.list_nodes(base): + if config.exists(base + [domain, 'server']): + config.copy(base + [domain, 'server'], base + [domain, 'name-server']) + config.delete(base + [domain, 'server']) diff --git a/src/migration-scripts/firewall/10-to-11 b/src/migration-scripts/firewall/10-to-11 index 854d5a558..70a170940 100755..100644 --- a/src/migration-scripts/firewall/10-to-11 +++ b/src/migration-scripts/firewall/10-to-11 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5160: Firewall re-writing @@ -37,171 +36,152 @@ # set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> action jump # set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> jump-target <name> -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -### Migration of state policies -if config.exists(base + ['state-policy']): - for state in config.list_nodes(base + ['state-policy']): - action = config.return_value(base + ['state-policy', state, 'action']) - config.set(base + ['global-options', 'state-policy', state, 'action'], value=action) - if config.exists(base + ['state-policy', state, 'log']): - config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable') - config.delete(base + ['state-policy']) - -## migration of global options: -for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians', - 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']: - if config.exists(base + [option]): - if option != 'config-trap': - val = config.return_value(base + [option]) - config.set(base + ['global-options', option], value=val) - config.delete(base + [option]) - -### Migration of firewall name and ipv6-name -### Also migrate legacy 'accept' behaviour -if config.exists(base + ['name']): - config.set(['firewall', 'ipv4', 'name']) - config.set_tag(['firewall', 'ipv4', 'name']) - - for ipv4name in config.list_nodes(base + ['name']): - config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name]) - - if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']): - action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action']) - - if action == 'accept': - config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return') - - if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']): - for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']): - action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action']) + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + ### Migration of state policies + if config.exists(base + ['state-policy']): + for state in config.list_nodes(base + ['state-policy']): + action = config.return_value(base + ['state-policy', state, 'action']) + config.set(base + ['global-options', 'state-policy', state, 'action'], value=action) + if config.exists(base + ['state-policy', state, 'log']): + config.set(base + ['global-options', 'state-policy', state, 'log'], value='enable') + config.delete(base + ['state-policy']) + + ## migration of global options: + for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians', + 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']: + if config.exists(base + [option]): + if option != 'config-trap': + val = config.return_value(base + [option]) + config.set(base + ['global-options', option], value=val) + config.delete(base + [option]) + + ### Migration of firewall name and ipv6-name + ### Also migrate legacy 'accept' behaviour + if config.exists(base + ['name']): + config.set(['firewall', 'ipv4', 'name']) + config.set_tag(['firewall', 'ipv4', 'name']) + + for ipv4name in config.list_nodes(base + ['name']): + config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name]) + + if config.exists(base + ['ipv4', 'name', ipv4name, 'default-action']): + action = config.return_value(base + ['ipv4', 'name', ipv4name, 'default-action']) if action == 'accept': - config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return') + config.set(base + ['ipv4', 'name', ipv4name, 'default-action'], value='return') - config.delete(base + ['name']) + if config.exists(base + ['ipv4', 'name', ipv4name, 'rule']): + for rule_id in config.list_nodes(base + ['ipv4', 'name', ipv4name, 'rule']): + action = config.return_value(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action']) -if config.exists(base + ['ipv6-name']): - config.set(['firewall', 'ipv6', 'name']) - config.set_tag(['firewall', 'ipv6', 'name']) + if action == 'accept': + config.set(base + ['ipv4', 'name', ipv4name, 'rule', rule_id, 'action'], value='return') - for ipv6name in config.list_nodes(base + ['ipv6-name']): - config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name]) + config.delete(base + ['name']) - if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']): - action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action']) + if config.exists(base + ['ipv6-name']): + config.set(['firewall', 'ipv6', 'name']) + config.set_tag(['firewall', 'ipv6', 'name']) - if action == 'accept': - config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return') + for ipv6name in config.list_nodes(base + ['ipv6-name']): + config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name]) - if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']): - for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']): - action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action']) + if config.exists(base + ['ipv6', 'name', ipv6name, 'default-action']): + action = config.return_value(base + ['ipv6', 'name', ipv6name, 'default-action']) if action == 'accept': - config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return') - - config.delete(base + ['ipv6-name']) - -### Migration of firewall interface -if config.exists(base + ['interface']): - fwd_ipv4_rule = 5 - inp_ipv4_rule = 5 - fwd_ipv6_rule = 5 - inp_ipv6_rule = 5 - for direction in ['in', 'out', 'local']: - for iface in config.list_nodes(base + ['interface']): - if config.exists(base + ['interface', iface, direction]): - if config.exists(base + ['interface', iface, direction, 'name']): - target = config.return_value(base + ['interface', iface, direction, 'name']) - if direction == 'in': - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept') - new_base = base + ['ipv4', 'forward', 'filter', 'rule'] - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface) - config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump') - config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target) - fwd_ipv4_rule = fwd_ipv4_rule + 5 - elif direction == 'out': - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept') - new_base = base + ['ipv4', 'forward', 'filter', 'rule'] - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface) - config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump') - config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target) - fwd_ipv4_rule = fwd_ipv4_rule + 5 - else: - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept') - new_base = base + ['ipv4', 'input', 'filter', 'rule'] - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface) - config.set(new_base + [inp_ipv4_rule, 'action'], value='jump') - config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target) - inp_ipv4_rule = inp_ipv4_rule + 5 - - if config.exists(base + ['interface', iface, direction, 'ipv6-name']): - target = config.return_value(base + ['interface', iface, direction, 'ipv6-name']) - if direction == 'in': - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept') - new_base = base + ['ipv6', 'forward', 'filter', 'rule'] - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface) - config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump') - config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target) - fwd_ipv6_rule = fwd_ipv6_rule + 5 - elif direction == 'out': - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept') - new_base = base + ['ipv6', 'forward', 'filter', 'rule'] - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface) - config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump') - config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target) - fwd_ipv6_rule = fwd_ipv6_rule + 5 - else: - new_base = base + ['ipv6', 'input', 'filter', 'rule'] - # Add default-action== accept for compatibility reasons: - config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept') - config.set(new_base) - config.set_tag(new_base) - config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface) - config.set(new_base + [inp_ipv6_rule, 'action'], value='jump') - config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target) - inp_ipv6_rule = inp_ipv6_rule + 5 - - config.delete(base + ['interface']) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) + config.set(base + ['ipv6', 'name', ipv6name, 'default-action'], value='return') + + if config.exists(base + ['ipv6', 'name', ipv6name, 'rule']): + for rule_id in config.list_nodes(base + ['ipv6', 'name', ipv6name, 'rule']): + action = config.return_value(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action']) + + if action == 'accept': + config.set(base + ['ipv6', 'name', ipv6name, 'rule', rule_id, 'action'], value='return') + + config.delete(base + ['ipv6-name']) + + ### Migration of firewall interface + if config.exists(base + ['interface']): + fwd_ipv4_rule = 5 + inp_ipv4_rule = 5 + fwd_ipv6_rule = 5 + inp_ipv6_rule = 5 + for direction in ['in', 'out', 'local']: + for iface in config.list_nodes(base + ['interface']): + if config.exists(base + ['interface', iface, direction]): + if config.exists(base + ['interface', iface, direction, 'name']): + target = config.return_value(base + ['interface', iface, direction, 'name']) + if direction == 'in': + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept') + new_base = base + ['ipv4', 'forward', 'filter', 'rule'] + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface) + config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump') + config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target) + fwd_ipv4_rule = fwd_ipv4_rule + 5 + elif direction == 'out': + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept') + new_base = base + ['ipv4', 'forward', 'filter', 'rule'] + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface) + config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump') + config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target) + fwd_ipv4_rule = fwd_ipv4_rule + 5 + else: + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept') + new_base = base + ['ipv4', 'input', 'filter', 'rule'] + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface) + config.set(new_base + [inp_ipv4_rule, 'action'], value='jump') + config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target) + inp_ipv4_rule = inp_ipv4_rule + 5 + + if config.exists(base + ['interface', iface, direction, 'ipv6-name']): + target = config.return_value(base + ['interface', iface, direction, 'ipv6-name']) + if direction == 'in': + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept') + new_base = base + ['ipv6', 'forward', 'filter', 'rule'] + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface) + config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump') + config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target) + fwd_ipv6_rule = fwd_ipv6_rule + 5 + elif direction == 'out': + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept') + new_base = base + ['ipv6', 'forward', 'filter', 'rule'] + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface) + config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump') + config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target) + fwd_ipv6_rule = fwd_ipv6_rule + 5 + else: + new_base = base + ['ipv6', 'input', 'filter', 'rule'] + # Add default-action== accept for compatibility reasons: + config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept') + config.set(new_base) + config.set_tag(new_base) + config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface) + config.set(new_base + [inp_ipv6_rule, 'action'], value='jump') + config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target) + inp_ipv6_rule = inp_ipv6_rule + 5 + + config.delete(base + ['interface']) diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12 index f9122e74c..80a74cca9 100755..100644 --- a/src/migration-scripts/firewall/11-to-12 +++ b/src/migration-scripts/firewall/11-to-12 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5681: Firewall re-writing. Simplify cli when mathcing interface # From @@ -22,50 +21,31 @@ # set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface> # set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group> -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -## Migration from base chains -#if config.exists(base + ['interface', iface, direction]): -for family in ['ipv4', 'ipv6']: - if config.exists(base + [family]): - for hook in ['forward', 'input', 'output', 'name']: - if config.exists(base + [family, hook]): - for priority in config.list_nodes(base + [family, hook]): - if config.exists(base + [family, hook, priority, 'rule']): - for rule in config.list_nodes(base + [family, hook, priority, 'rule']): - for direction in ['inbound-interface', 'outbound-interface']: - if config.exists(base + [family, hook, priority, 'rule', rule, direction]): - if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']): - iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) - config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface) - config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) - elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']): - group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) - config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group) - config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + ## Migration from base chains + #if config.exists(base + ['interface', iface, direction]): + for family in ['ipv4', 'ipv6']: + if config.exists(base + [family]): + for hook in ['forward', 'input', 'output', 'name']: + if config.exists(base + [family, hook]): + for priority in config.list_nodes(base + [family, hook]): + if config.exists(base + [family, hook, priority, 'rule']): + for rule in config.list_nodes(base + [family, hook, priority, 'rule']): + for direction in ['inbound-interface', 'outbound-interface']: + if config.exists(base + [family, hook, priority, 'rule', rule, direction]): + if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']): + iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) + config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface) + config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) + elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']): + group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) + config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group) + config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) diff --git a/src/migration-scripts/firewall/12-to-13 b/src/migration-scripts/firewall/12-to-13 index d72ba834d..d7b801cd3 100755..100644 --- a/src/migration-scripts/firewall/12-to-13 +++ b/src/migration-scripts/firewall/12-to-13 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5729: Switch to valueless whenever is possible. # From @@ -25,65 +24,46 @@ # set firewall ... rule <rule> state <state> # Remove command if log=disable or <state>=disable -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -# State Policy logs: -if config.exists(base + ['global-options', 'state-policy']): - for state in config.list_nodes(base + ['global-options', 'state-policy']): - if config.exists(base + ['global-options', 'state-policy', state, 'log']): - log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log']) - config.delete(base + ['global-options', 'state-policy', state, 'log']) - if log_value == 'enable': - config.set(base + ['global-options', 'state-policy', state, 'log']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -for family in ['ipv4', 'ipv6', 'bridge']: - if config.exists(base + [family]): - for hook in ['forward', 'input', 'output', 'name']: - if config.exists(base + [family, hook]): - for priority in config.list_nodes(base + [family, hook]): - if config.exists(base + [family, hook, priority, 'rule']): - for rule in config.list_nodes(base + [family, hook, priority, 'rule']): - # Log - if config.exists(base + [family, hook, priority, 'rule', rule, 'log']): - log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log']) - config.delete(base + [family, hook, priority, 'rule', rule, 'log']) - if log_value == 'enable': - config.set(base + [family, hook, priority, 'rule', rule, 'log']) - # State - if config.exists(base + [family, hook, priority, 'rule', rule, 'state']): - flag_enable = 'False' - for state in ['established', 'invalid', 'new', 'related']: - if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]): - state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state]) - config.delete(base + [family, hook, priority, 'rule', rule, 'state', state]) - if state_value == 'enable': - config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False) - flag_enable = 'True' - if flag_enable == 'False': - config.delete(base + [family, hook, priority, 'rule', rule, 'state']) + # State Policy logs: + if config.exists(base + ['global-options', 'state-policy']): + for state in config.list_nodes(base + ['global-options', 'state-policy']): + if config.exists(base + ['global-options', 'state-policy', state, 'log']): + log_value = config.return_value(base + ['global-options', 'state-policy', state, 'log']) + config.delete(base + ['global-options', 'state-policy', state, 'log']) + if log_value == 'enable': + config.set(base + ['global-options', 'state-policy', state, 'log']) -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) + for family in ['ipv4', 'ipv6', 'bridge']: + if config.exists(base + [family]): + for hook in ['forward', 'input', 'output', 'name']: + if config.exists(base + [family, hook]): + for priority in config.list_nodes(base + [family, hook]): + if config.exists(base + [family, hook, priority, 'rule']): + for rule in config.list_nodes(base + [family, hook, priority, 'rule']): + # Log + if config.exists(base + [family, hook, priority, 'rule', rule, 'log']): + log_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'log']) + config.delete(base + [family, hook, priority, 'rule', rule, 'log']) + if log_value == 'enable': + config.set(base + [family, hook, priority, 'rule', rule, 'log']) + # State + if config.exists(base + [family, hook, priority, 'rule', rule, 'state']): + flag_enable = 'False' + for state in ['established', 'invalid', 'new', 'related']: + if config.exists(base + [family, hook, priority, 'rule', rule, 'state', state]): + state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state]) + config.delete(base + [family, hook, priority, 'rule', rule, 'state', state]) + if state_value == 'enable': + config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False) + flag_enable = 'True' + if flag_enable == 'False': + config.delete(base + [family, hook, priority, 'rule', rule, 'state']) diff --git a/src/migration-scripts/firewall/13-to-14 b/src/migration-scripts/firewall/13-to-14 index f45ff0674..723b0aea2 100755..100644 --- a/src/migration-scripts/firewall/13-to-14 +++ b/src/migration-scripts/firewall/13-to-14 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5834: Rename 'enable-default-log' to 'default-log' # From @@ -22,38 +21,19 @@ # set firewall ... filter default-log # set firewall ... name <name> default-log -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -for family in ['ipv4', 'ipv6', 'bridge']: - if config.exists(base + [family]): - for hook in ['forward', 'input', 'output', 'name']: - if config.exists(base + [family, hook]): - for priority in config.list_nodes(base + [family, hook]): - if config.exists(base + [family, hook, priority, 'enable-default-log']): - config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log') -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for family in ['ipv4', 'ipv6', 'bridge']: + if config.exists(base + [family]): + for hook in ['forward', 'input', 'output', 'name']: + if config.exists(base + [family, hook]): + for priority in config.list_nodes(base + [family, hook]): + if config.exists(base + [family, hook, priority, 'enable-default-log']): + config.rename(base + [family, hook, priority, 'enable-default-log'], 'default-log') diff --git a/src/migration-scripts/firewall/14-to-15 b/src/migration-scripts/firewall/14-to-15 index 735839365..e4a2aaee4 100755..100644 --- a/src/migration-scripts/firewall/14-to-15 +++ b/src/migration-scripts/firewall/14-to-15 @@ -1,46 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5535: Migrate <set system ip disable-directed-broadcast> to <set firewall global-options directed-broadcas [enable|disable] -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['firewall'] -if config.exists(['system', 'ip', 'disable-directed-broadcast']): - config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable') - config.delete(['system', 'ip', 'disable-directed-broadcast']) - -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)
\ No newline at end of file +def migrate(config: ConfigTree) -> None: + if config.exists(['system', 'ip', 'disable-directed-broadcast']): + config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable') + config.delete(['system', 'ip', 'disable-directed-broadcast']) diff --git a/src/migration-scripts/firewall/15-to-16 b/src/migration-scripts/firewall/15-to-16 index 28df1256e..8e28bba6f 100755..100644 --- a/src/migration-scripts/firewall/15-to-16 +++ b/src/migration-scripts/firewall/15-to-16 @@ -18,39 +18,20 @@ # from: set system conntrack timeout .. # to: set firewall global-options timeout ... -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() - firewall_base = ['firewall', 'global-options'] conntrack_base = ['system', 'conntrack', 'timeout'] -config = ConfigTree(config_file) - -if not config.exists(conntrack_base): - # Nothing to do - exit(0) -for protocol in ['icmp', 'tcp', 'udp', 'other']: - if config.exists(conntrack_base + [protocol]): - if not config.exists(firewall_base + ['timeout']): - config.set(firewall_base + ['timeout']) +def migrate(config: ConfigTree) -> None: + if not config.exists(conntrack_base): + # Nothing to do + return - config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol]) - config.delete(conntrack_base + [protocol]) + for protocol in ['icmp', 'tcp', 'udp', 'other']: + if config.exists(conntrack_base + [protocol]): + if not config.exists(firewall_base + ['timeout']): + config.set(firewall_base + ['timeout']) -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) + config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol]) + config.delete(conntrack_base + [protocol]) diff --git a/src/migration-scripts/firewall/5-to-6 b/src/migration-scripts/firewall/5-to-6 index e1eaea7a1..d01684787 100755..100644 --- a/src/migration-scripts/firewall/5-to-6 +++ b/src/migration-scripts/firewall/5-to-6 @@ -1,105 +1,85 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3090: migrate "firewall options interface <name> adjust-mss" to the # individual interface. -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree from vyos.ifconfig import Section -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 = ['firewall', 'options', 'interface'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -for interface in config.list_nodes(base): - if config.exists(base + [interface, 'disable']): - continue - if config.exists(base + [interface, 'adjust-mss']): - section = Section.section(interface) - tmp = config.return_value(base + [interface, 'adjust-mss']) - - vlan = interface.split('.') - base_interface_path = ['interfaces', section, vlan[0]] - - if len(vlan) == 1: - # Normal interface, no VLAN - config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp) - elif len(vlan) == 2: - # Regular VIF or VIF-S interface - we need to check the config - vif = vlan[1] - if config.exists(base_interface_path + ['vif', vif]): - config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp) - elif config.exists(base_interface_path + ['vif-s', vif]): - config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp) - elif len(vlan) == 3: - # VIF-S interface with VIF-C subinterface - vif_s = vlan[1] - vif_c = vlan[2] - config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp) - config.set_tag(base_interface_path + ['vif-s']) - config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c']) - - if config.exists(base + [interface, 'adjust-mss6']): - section = Section.section(interface) - tmp = config.return_value(base + [interface, 'adjust-mss6']) - - vlan = interface.split('.') - base_interface_path = ['interfaces', section, vlan[0]] - - if len(vlan) == 1: - # Normal interface, no VLAN - config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp) - elif len(vlan) == 2: - # Regular VIF or VIF-S interface - we need to check the config - vif = vlan[1] - if config.exists(base_interface_path + ['vif', vif]): - config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp) - config.set_tag(base_interface_path + ['vif']) - elif config.exists(base_interface_path + ['vif-s', vif]): - config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for interface in config.list_nodes(base): + if config.exists(base + [interface, 'disable']): + continue + + if config.exists(base + [interface, 'adjust-mss']): + section = Section.section(interface) + tmp = config.return_value(base + [interface, 'adjust-mss']) + + vlan = interface.split('.') + base_interface_path = ['interfaces', section, vlan[0]] + + if len(vlan) == 1: + # Normal interface, no VLAN + config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp) + elif len(vlan) == 2: + # Regular VIF or VIF-S interface - we need to check the config + vif = vlan[1] + if config.exists(base_interface_path + ['vif', vif]): + config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp) + elif config.exists(base_interface_path + ['vif-s', vif]): + config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp) + elif len(vlan) == 3: + # VIF-S interface with VIF-C subinterface + vif_s = vlan[1] + vif_c = vlan[2] + config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp) config.set_tag(base_interface_path + ['vif-s']) - elif len(vlan) == 3: - # VIF-S interface with VIF-C subinterface - vif_s = vlan[1] - vif_c = vlan[2] - config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp) - config.set_tag(base_interface_path + ['vif-s']) - config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c']) - -config.delete(['firewall', 'options']) + config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c']) + + if config.exists(base + [interface, 'adjust-mss6']): + section = Section.section(interface) + tmp = config.return_value(base + [interface, 'adjust-mss6']) + + vlan = interface.split('.') + base_interface_path = ['interfaces', section, vlan[0]] + + if len(vlan) == 1: + # Normal interface, no VLAN + config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp) + elif len(vlan) == 2: + # Regular VIF or VIF-S interface - we need to check the config + vif = vlan[1] + if config.exists(base_interface_path + ['vif', vif]): + config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp) + config.set_tag(base_interface_path + ['vif']) + elif config.exists(base_interface_path + ['vif-s', vif]): + config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp) + config.set_tag(base_interface_path + ['vif-s']) + elif len(vlan) == 3: + # VIF-S interface with VIF-C subinterface + vif_s = vlan[1] + vif_c = vlan[2] + config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp) + config.set_tag(base_interface_path + ['vif-s']) + config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c']) -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) + config.delete(['firewall', 'options']) diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7 index 938044c6d..1afbc780b 100755..100644 --- a/src/migration-scripts/firewall/6-to-7 +++ b/src/migration-scripts/firewall/6-to-7 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T2199: Remove unavailable nodes due to XML/Python implementation using nftables # monthdays: nftables does not have a monthdays equivalent @@ -23,28 +22,11 @@ import re -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() - max_len_description = 255 base = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) icmp_remove = ['any'] icmp_translations = { @@ -107,216 +89,216 @@ icmpv6_translations = { 'unknown-option': [4, 2] } -v4_found = False -v6_found = False v4_groups = ["address-group", "network-group", "port-group"] v6_groups = ["ipv6-address-group", "ipv6-network-group", "port-group"] -translated_dict = {} -if config.exists(base + ['group']): - for group_type in config.list_nodes(base + ['group']): - for group_name in config.list_nodes(base + ['group', group_type]): - name_description = base + ['group', group_type, group_name, 'description'] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + v4_found = False + v6_found = False + translated_dict = {} + + if config.exists(base + ['group']): + for group_type in config.list_nodes(base + ['group']): + for group_name in config.list_nodes(base + ['group', group_type]): + name_description = base + ['group', group_type, group_name, 'description'] + if config.exists(name_description): + tmp = config.return_value(name_description) + config.set(name_description, value=tmp[:max_len_description]) + if '+' in group_name: + replacement_string = "_" + if group_type in v4_groups and not v4_found: + v4_found = True + if group_type in v6_groups and not v6_found: + v6_found = True + new_group_name = group_name.replace('+', replacement_string) + while config.exists(base + ['group', group_type, new_group_name]): + replacement_string = replacement_string + "_" + new_group_name = group_name.replace('+', replacement_string) + translated_dict[group_name] = new_group_name + config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name]) + config.delete(base + ['group', group_type, group_name]) + + if config.exists(base + ['name']): + for name in config.list_nodes(base + ['name']): + name_description = base + ['name', name, 'description'] if config.exists(name_description): tmp = config.return_value(name_description) config.set(name_description, value=tmp[:max_len_description]) - if '+' in group_name: - replacement_string = "_" - if group_type in v4_groups and not v4_found: - v4_found = True - if group_type in v6_groups and not v6_found: - v6_found = True - new_group_name = group_name.replace('+', replacement_string) - while config.exists(base + ['group', group_type, new_group_name]): - replacement_string = replacement_string + "_" - new_group_name = group_name.replace('+', replacement_string) - translated_dict[group_name] = new_group_name - config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name]) - config.delete(base + ['group', group_type, group_name]) - -if config.exists(base + ['name']): - for name in config.list_nodes(base + ['name']): - name_description = base + ['name', name, 'description'] - if config.exists(name_description): - tmp = config.return_value(name_description) - config.set(name_description, value=tmp[:max_len_description]) - - if not config.exists(base + ['name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['name', name, 'rule']): - rule_description = base + ['name', name, 'rule', rule, 'description'] - if config.exists(rule_description): - tmp = config.return_value(rule_description) - config.set(rule_description, value=tmp[:max_len_description]) - - rule_recent = base + ['name', name, 'rule', rule, 'recent'] - rule_time = base + ['name', name, 'rule', rule, 'time'] - rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags'] - rule_icmp = base + ['name', name, 'rule', rule, 'icmp'] - - if config.exists(rule_time + ['monthdays']): - config.delete(rule_time + ['monthdays']) - - if config.exists(rule_time + ['utc']): - config.delete(rule_time + ['utc']) - - if config.exists(rule_recent + ['time']): - tmp = int(config.return_value(rule_recent + ['time'])) - unit = 'minute' - if tmp > 600: - unit = 'hour' - elif tmp < 10: - unit = 'second' - config.set(rule_recent + ['time'], value=unit) - - if config.exists(rule_tcp_flags): - tmp = config.return_value(rule_tcp_flags) - config.delete(rule_tcp_flags) - for flag in tmp.split(","): - if flag[0] == '!': - config.set(rule_tcp_flags + ['not', flag[1:].lower()]) - else: - config.set(rule_tcp_flags + [flag.lower()]) - - if config.exists(rule_icmp + ['type-name']): - tmp = config.return_value(rule_icmp + ['type-name']) - if tmp in icmp_remove: - config.delete(rule_icmp + ['type-name']) - elif tmp in icmp_translations: - translate = icmp_translations[tmp] - if isinstance(translate, str): - config.set(rule_icmp + ['type-name'], value=translate) - elif isinstance(translate, list): + + if not config.exists(base + ['name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['name', name, 'rule']): + rule_description = base + ['name', name, 'rule', rule, 'description'] + if config.exists(rule_description): + tmp = config.return_value(rule_description) + config.set(rule_description, value=tmp[:max_len_description]) + + rule_recent = base + ['name', name, 'rule', rule, 'recent'] + rule_time = base + ['name', name, 'rule', rule, 'time'] + rule_tcp_flags = base + ['name', name, 'rule', rule, 'tcp', 'flags'] + rule_icmp = base + ['name', name, 'rule', rule, 'icmp'] + + if config.exists(rule_time + ['monthdays']): + config.delete(rule_time + ['monthdays']) + + if config.exists(rule_time + ['utc']): + config.delete(rule_time + ['utc']) + + if config.exists(rule_recent + ['time']): + tmp = int(config.return_value(rule_recent + ['time'])) + unit = 'minute' + if tmp > 600: + unit = 'hour' + elif tmp < 10: + unit = 'second' + config.set(rule_recent + ['time'], value=unit) + + if config.exists(rule_tcp_flags): + tmp = config.return_value(rule_tcp_flags) + config.delete(rule_tcp_flags) + for flag in tmp.split(","): + if flag[0] == '!': + config.set(rule_tcp_flags + ['not', flag[1:].lower()]) + else: + config.set(rule_tcp_flags + [flag.lower()]) + + if config.exists(rule_icmp + ['type-name']): + tmp = config.return_value(rule_icmp + ['type-name']) + if tmp in icmp_remove: config.delete(rule_icmp + ['type-name']) - config.set(rule_icmp + ['type'], value=translate[0]) - config.set(rule_icmp + ['code'], value=translate[1]) - - for direction in ['destination', 'source']: - if config.exists(base + ['name', name, 'rule', rule, direction]): - if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found: - for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']): - group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type]) - if '+' in group_name: - if group_name[0] == "!": - new_group_name = "!" + translated_dict[group_name[1:]] - else: - new_group_name = translated_dict[group_name] - config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name) - - pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group'] - proto_base = base + ['name', name, 'rule', rule, 'protocol'] - if config.exists(pg_base) and not config.exists(proto_base): - config.set(proto_base, value='tcp_udp') - - if '+' in name: - replacement_string = "_" - new_name = name.replace('+', replacement_string) - while config.exists(base + ['name', new_name]): - replacement_string = replacement_string + "_" + elif tmp in icmp_translations: + translate = icmp_translations[tmp] + if isinstance(translate, str): + config.set(rule_icmp + ['type-name'], value=translate) + elif isinstance(translate, list): + config.delete(rule_icmp + ['type-name']) + config.set(rule_icmp + ['type'], value=translate[0]) + config.set(rule_icmp + ['code'], value=translate[1]) + + for direction in ['destination', 'source']: + if config.exists(base + ['name', name, 'rule', rule, direction]): + if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found: + for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']): + group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type]) + if '+' in group_name: + if group_name[0] == "!": + new_group_name = "!" + translated_dict[group_name[1:]] + else: + new_group_name = translated_dict[group_name] + config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name) + + pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group'] + proto_base = base + ['name', name, 'rule', rule, 'protocol'] + if config.exists(pg_base) and not config.exists(proto_base): + config.set(proto_base, value='tcp_udp') + + if '+' in name: + replacement_string = "_" new_name = name.replace('+', replacement_string) - config.copy(base + ['name', name], base + ['name', new_name]) - config.delete(base + ['name', name]) - -if config.exists(base + ['ipv6-name']): - for name in config.list_nodes(base + ['ipv6-name']): - name_description = base + ['ipv6-name', name, 'description'] - if config.exists(name_description): - tmp = config.return_value(name_description) - config.set(name_description, value=tmp[:max_len_description]) - - if not config.exists(base + ['ipv6-name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): - rule_description = base + ['ipv6-name', name, 'rule', rule, 'description'] - if config.exists(rule_description): - tmp = config.return_value(rule_description) - config.set(rule_description, value=tmp[:max_len_description]) - - rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent'] - rule_time = base + ['ipv6-name', name, 'rule', rule, 'time'] - rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags'] - rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6'] - - if config.exists(rule_time + ['monthdays']): - config.delete(rule_time + ['monthdays']) - - if config.exists(rule_time + ['utc']): - config.delete(rule_time + ['utc']) - - if config.exists(rule_recent + ['time']): - tmp = int(config.return_value(rule_recent + ['time'])) - unit = 'minute' - if tmp > 600: - unit = 'hour' - elif tmp < 10: - unit = 'second' - config.set(rule_recent + ['time'], value=unit) - - if config.exists(rule_tcp_flags): - tmp = config.return_value(rule_tcp_flags) - config.delete(rule_tcp_flags) - for flag in tmp.split(","): - if flag[0] == '!': - config.set(rule_tcp_flags + ['not', flag[1:].lower()]) - else: - config.set(rule_tcp_flags + [flag.lower()]) - - if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']): - tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol']) - if tmp == 'icmpv6': - config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp') - - if config.exists(rule_icmp + ['type']): - tmp = config.return_value(rule_icmp + ['type']) - type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp) - - if type_code_match: - config.set(rule_icmp + ['type'], value=type_code_match[1]) - if type_code_match[2]: - config.set(rule_icmp + ['code'], value=type_code_match[2]) - elif tmp in icmpv6_remove: - config.delete(rule_icmp + ['type']) - elif tmp in icmpv6_translations: - translate = icmpv6_translations[tmp] - if isinstance(translate, str): + while config.exists(base + ['name', new_name]): + replacement_string = replacement_string + "_" + new_name = name.replace('+', replacement_string) + config.copy(base + ['name', name], base + ['name', new_name]) + config.delete(base + ['name', name]) + + if config.exists(base + ['ipv6-name']): + for name in config.list_nodes(base + ['ipv6-name']): + name_description = base + ['ipv6-name', name, 'description'] + if config.exists(name_description): + tmp = config.return_value(name_description) + config.set(name_description, value=tmp[:max_len_description]) + + if not config.exists(base + ['ipv6-name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): + rule_description = base + ['ipv6-name', name, 'rule', rule, 'description'] + if config.exists(rule_description): + tmp = config.return_value(rule_description) + config.set(rule_description, value=tmp[:max_len_description]) + + rule_recent = base + ['ipv6-name', name, 'rule', rule, 'recent'] + rule_time = base + ['ipv6-name', name, 'rule', rule, 'time'] + rule_tcp_flags = base + ['ipv6-name', name, 'rule', rule, 'tcp', 'flags'] + rule_icmp = base + ['ipv6-name', name, 'rule', rule, 'icmpv6'] + + if config.exists(rule_time + ['monthdays']): + config.delete(rule_time + ['monthdays']) + + if config.exists(rule_time + ['utc']): + config.delete(rule_time + ['utc']) + + if config.exists(rule_recent + ['time']): + tmp = int(config.return_value(rule_recent + ['time'])) + unit = 'minute' + if tmp > 600: + unit = 'hour' + elif tmp < 10: + unit = 'second' + config.set(rule_recent + ['time'], value=unit) + + if config.exists(rule_tcp_flags): + tmp = config.return_value(rule_tcp_flags) + config.delete(rule_tcp_flags) + for flag in tmp.split(","): + if flag[0] == '!': + config.set(rule_tcp_flags + ['not', flag[1:].lower()]) + else: + config.set(rule_tcp_flags + [flag.lower()]) + + if config.exists(base + ['ipv6-name', name, 'rule', rule, 'protocol']): + tmp = config.return_value(base + ['ipv6-name', name, 'rule', rule, 'protocol']) + if tmp == 'icmpv6': + config.set(base + ['ipv6-name', name, 'rule', rule, 'protocol'], value='ipv6-icmp') + + if config.exists(rule_icmp + ['type']): + tmp = config.return_value(rule_icmp + ['type']) + type_code_match = re.match(r'^(\d+)(?:/(\d+))?$', tmp) + + if type_code_match: + config.set(rule_icmp + ['type'], value=type_code_match[1]) + if type_code_match[2]: + config.set(rule_icmp + ['code'], value=type_code_match[2]) + elif tmp in icmpv6_remove: config.delete(rule_icmp + ['type']) - config.set(rule_icmp + ['type-name'], value=translate) - elif isinstance(translate, list): - config.set(rule_icmp + ['type'], value=translate[0]) - config.set(rule_icmp + ['code'], value=translate[1]) - else: - config.rename(rule_icmp + ['type'], 'type-name') - - for direction in ['destination', 'source']: - if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]): - if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found: - for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']): - group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type]) - if '+' in group_name: - if group_name[0] == "!": - new_group_name = "!" + translated_dict[group_name[1:]] - else: - new_group_name = translated_dict[group_name] - config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name) - - pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group'] - proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol'] - if config.exists(pg_base) and not config.exists(proto_base): - config.set(proto_base, value='tcp_udp') - - if '+' in name: - replacement_string = "_" - new_name = name.replace('+', replacement_string) - while config.exists(base + ['ipv6-name', new_name]): - replacement_string = replacement_string + "_" + elif tmp in icmpv6_translations: + translate = icmpv6_translations[tmp] + if isinstance(translate, str): + config.delete(rule_icmp + ['type']) + config.set(rule_icmp + ['type-name'], value=translate) + elif isinstance(translate, list): + config.set(rule_icmp + ['type'], value=translate[0]) + config.set(rule_icmp + ['code'], value=translate[1]) + else: + config.rename(rule_icmp + ['type'], 'type-name') + + for direction in ['destination', 'source']: + if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]): + if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found: + for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']): + group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type]) + if '+' in group_name: + if group_name[0] == "!": + new_group_name = "!" + translated_dict[group_name[1:]] + else: + new_group_name = translated_dict[group_name] + config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name) + + pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group'] + proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol'] + if config.exists(pg_base) and not config.exists(proto_base): + config.set(proto_base, value='tcp_udp') + + if '+' in name: + replacement_string = "_" new_name = name.replace('+', replacement_string) - config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name]) - config.delete(base + ['ipv6-name', name]) -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) + while config.exists(base + ['ipv6-name', new_name]): + replacement_string = replacement_string + "_" + new_name = name.replace('+', replacement_string) + config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name]) + config.delete(base + ['ipv6-name', name]) diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8 index bbaba113a..f46994ce2 100755..100644 --- a/src/migration-scripts/firewall/7-to-8 +++ b/src/migration-scripts/firewall/7-to-8 @@ -1,43 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T2199: Migrate interface firewall nodes to firewall interfaces <ifname> <direction> name/ipv6-name <name> # T2199: Migrate zone-policy to firewall node -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 = ['firewall'] zone_base = ['zone-policy'] -config = ConfigTree(config_file) - -if not config.exists(base) and not config.exists(zone_base): - # Nothing to do - exit(0) def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None): if_path = ['interfaces', iftype, ifname] @@ -63,33 +45,31 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None): config.copy(if_path + ['firewall'], ['firewall', 'interface', ifname_full]) config.delete(if_path + ['firewall']) -for iftype in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', iftype]): - migrate_interface(config, iftype, ifname) +def migrate(config: ConfigTree) -> None: + if not config.exists(base) and not config.exists(zone_base): + # Nothing to do + return - if config.exists(['interfaces', iftype, ifname, 'vif']): - for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): - migrate_interface(config, iftype, ifname, vif=vif) + for iftype in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', iftype]): + migrate_interface(config, iftype, ifname) - if config.exists(['interfaces', iftype, ifname, 'vif-s']): - for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): - migrate_interface(config, iftype, ifname, vifs=vifs) + if config.exists(['interfaces', iftype, ifname, 'vif']): + for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): + migrate_interface(config, iftype, ifname, vif=vif) - if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc) + if config.exists(['interfaces', iftype, ifname, 'vif-s']): + for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): + migrate_interface(config, iftype, ifname, vifs=vifs) -if config.exists(zone_base + ['zone']): - config.set(['firewall', 'zone']) - config.set_tag(['firewall', 'zone']) + if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc) - for zone in config.list_nodes(zone_base + ['zone']): - config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone]) - config.delete(zone_base) + if config.exists(zone_base + ['zone']): + config.set(['firewall', 'zone']) + config.set_tag(['firewall', 'zone']) -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) + for zone in config.list_nodes(zone_base + ['zone']): + config.copy(zone_base + ['zone', zone], ['firewall', 'zone', zone]) + config.delete(zone_base) diff --git a/src/migration-scripts/firewall/8-to-9 b/src/migration-scripts/firewall/8-to-9 index 6e019beb2..3c9e84662 100755..100644 --- a/src/migration-scripts/firewall/8-to-9 +++ b/src/migration-scripts/firewall/8-to-9 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4780: Add firewall interface group # cli changes from: @@ -20,69 +19,50 @@ # To # set firewall [name | ipv6-name] <name> rule <number> [inbound-interface | outbound-interface] [interface-name | interface-group] <interface_name | interface_group> -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['name']): - for name in config.list_nodes(base + ['name']): - if not config.exists(base + ['name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['name', name, 'rule']): - rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface'] - rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface'] - - if config.exists(rule_iiface): - tmp = config.return_value(rule_iiface) - config.delete(rule_iiface) - config.set(rule_iiface + ['interface-name'], value=tmp) - - if config.exists(rule_oiface): - tmp = config.return_value(rule_oiface) - config.delete(rule_oiface) - config.set(rule_oiface + ['interface-name'], value=tmp) - - -if config.exists(base + ['ipv6-name']): - for name in config.list_nodes(base + ['ipv6-name']): - if not config.exists(base + ['ipv6-name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): - rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface'] - rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface'] - - if config.exists(rule_iiface): - tmp = config.return_value(rule_iiface) - config.delete(rule_iiface) - config.set(rule_iiface + ['interface-name'], value=tmp) - - if config.exists(rule_oiface): - tmp = config.return_value(rule_oiface) - config.delete(rule_oiface) - config.set(rule_oiface + ['interface-name'], 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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['name']): + for name in config.list_nodes(base + ['name']): + if not config.exists(base + ['name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['name', name, 'rule']): + rule_iiface = base + ['name', name, 'rule', rule, 'inbound-interface'] + rule_oiface = base + ['name', name, 'rule', rule, 'outbound-interface'] + + if config.exists(rule_iiface): + tmp = config.return_value(rule_iiface) + config.delete(rule_iiface) + config.set(rule_iiface + ['interface-name'], value=tmp) + + if config.exists(rule_oiface): + tmp = config.return_value(rule_oiface) + config.delete(rule_oiface) + config.set(rule_oiface + ['interface-name'], value=tmp) + + + if config.exists(base + ['ipv6-name']): + for name in config.list_nodes(base + ['ipv6-name']): + if not config.exists(base + ['ipv6-name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): + rule_iiface = base + ['ipv6-name', name, 'rule', rule, 'inbound-interface'] + rule_oiface = base + ['ipv6-name', name, 'rule', rule, 'outbound-interface'] + + if config.exists(rule_iiface): + tmp = config.return_value(rule_iiface) + config.delete(rule_iiface) + config.set(rule_iiface + ['interface-name'], value=tmp) + + if config.exists(rule_oiface): + tmp = config.return_value(rule_oiface) + config.delete(rule_oiface) + config.set(rule_oiface + ['interface-name'], value=tmp) diff --git a/src/migration-scripts/firewall/9-to-10 b/src/migration-scripts/firewall/9-to-10 index ce509a731..306a53a86 100755..100644 --- a/src/migration-scripts/firewall/9-to-10 +++ b/src/migration-scripts/firewall/9-to-10 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5050: Log options # cli changes from: @@ -20,58 +19,39 @@ # To # set firewall [name | ipv6-name] <name> rule <number> log-options level <log_level> -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 = ['firewall'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['name']): - for name in config.list_nodes(base + ['name']): - if not config.exists(base + ['name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['name', name, 'rule']): - log_options_base = base + ['name', name, 'rule', rule, 'log-options'] - rule_log_level = base + ['name', name, 'rule', rule, 'log-level'] - - if config.exists(rule_log_level): - tmp = config.return_value(rule_log_level) - config.delete(rule_log_level) - config.set(log_options_base + ['level'], value=tmp) - -if config.exists(base + ['ipv6-name']): - for name in config.list_nodes(base + ['ipv6-name']): - if not config.exists(base + ['ipv6-name', name, 'rule']): - continue - - for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): - log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options'] - rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level'] - - if config.exists(rule_log_level): - tmp = config.return_value(rule_log_level) - config.delete(rule_log_level) - config.set(log_options_base + ['level'], 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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['name']): + for name in config.list_nodes(base + ['name']): + if not config.exists(base + ['name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['name', name, 'rule']): + log_options_base = base + ['name', name, 'rule', rule, 'log-options'] + rule_log_level = base + ['name', name, 'rule', rule, 'log-level'] + + if config.exists(rule_log_level): + tmp = config.return_value(rule_log_level) + config.delete(rule_log_level) + config.set(log_options_base + ['level'], value=tmp) + + if config.exists(base + ['ipv6-name']): + for name in config.list_nodes(base + ['ipv6-name']): + if not config.exists(base + ['ipv6-name', name, 'rule']): + continue + + for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']): + log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options'] + rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level'] + + if config.exists(rule_log_level): + tmp = config.return_value(rule_log_level) + config.delete(rule_log_level) + config.set(log_options_base + ['level'], value=tmp) diff --git a/src/migration-scripts/flow-accounting/0-to-1 b/src/migration-scripts/flow-accounting/0-to-1 index 0f790fd9c..77670e3ef 100755..100644 --- a/src/migration-scripts/flow-accounting/0-to-1 +++ b/src/migration-scripts/flow-accounting/0-to-1 @@ -1,69 +1,51 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4099: flow-accounting: sync "source-ip" and "source-address" between netflow # and sflow ion CLI # T4105: flow-accounting: drop "sflow agent-address auto" -from sys import argv 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 = ['system', 'flow-accounting'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# T4099 -tmp = base + ['netflow', 'source-ip'] -if config.exists(tmp): - config.rename(tmp, 'source-address') - -# T4105 -tmp = base + ['sflow', 'agent-address'] -if config.exists(tmp): - value = config.return_value(tmp) - if value == 'auto': - # delete the "auto" - config.delete(tmp) - - # 1) check if BGP router-id is set - # 2) check if OSPF router-id is set - # 3) check if OSPFv3 router-id is set - router_id = None - for protocol in ['bgp', 'ospf', 'ospfv3']: - if config.exists(['protocols', protocol, 'parameters', 'router-id']): - router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id']) - break - if router_id: - config.set(tmp, value=router_id) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # T4099 + tmp = base + ['netflow', 'source-ip'] + if config.exists(tmp): + config.rename(tmp, 'source-address') + + # T4105 + tmp = base + ['sflow', 'agent-address'] + if config.exists(tmp): + value = config.return_value(tmp) + if value == 'auto': + # delete the "auto" + config.delete(tmp) + + # 1) check if BGP router-id is set + # 2) check if OSPF router-id is set + # 3) check if OSPFv3 router-id is set + router_id = None + for protocol in ['bgp', 'ospf', 'ospfv3']: + if config.exists(['protocols', protocol, 'parameters', 'router-id']): + router_id = config.return_value(['protocols', protocol, 'parameters', 'router-id']) + break + if router_id: + config.set(tmp, value=router_id) diff --git a/src/migration-scripts/https/0-to-1 b/src/migration-scripts/https/0-to-1 index 23809f5ad..52fe3f2ad 100755..100644 --- a/src/migration-scripts/https/0-to-1 +++ b/src/migration-scripts/https/0-to-1 @@ -1,42 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # * Move server block directives under 'virtual-host' tag node, instead of # relying on 'listen-address' tag node -import sys - from vyos.configtree import ConfigTree -if (len(sys.argv) < 2): - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +old_base = ['service', 'https', 'listen-address'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(old_base): + # Nothing to do + return -old_base = ['service', 'https', 'listen-address'] -if not config.exists(old_base): - # Nothing to do - sys.exit(0) -else: new_base = ['service', 'https', 'virtual-host'] config.set(new_base) config.set_tag(new_base) @@ -60,10 +48,3 @@ else: index += 1 config.delete(old_base) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/https/1-to-2 b/src/migration-scripts/https/1-to-2 index 1a2cdc1e7..dad7ac1f0 100755..100644 --- a/src/migration-scripts/https/1-to-2 +++ b/src/migration-scripts/https/1-to-2 @@ -1,42 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # * Move 'api virtual-host' list to 'api-restrict virtual-host' so it # is owned by service_https.py -import sys - from vyos.configtree import ConfigTree -if (len(sys.argv) < 2): - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +old_base = ['service', 'https', 'api', 'virtual-host'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(old_base): + # Nothing to do + return -old_base = ['service', 'https', 'api', 'virtual-host'] -if not config.exists(old_base): - # Nothing to do - sys.exit(0) -else: new_base = ['service', 'https', 'api-restrict', 'virtual-host'] config.set(new_base) @@ -45,10 +33,3 @@ else: config.set(new_base, value=name, replace=False) config.delete(old_base) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/https/2-to-3 b/src/migration-scripts/https/2-to-3 index 2beba6d2b..1125caebf 100755..100644 --- a/src/migration-scripts/https/2-to-3 +++ b/src/migration-scripts/https/2-to-3 @@ -1,23 +1,20 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # * Migrate system signed certificate to use PKI -import sys - from vyos.configtree import ConfigTree from vyos.pki import create_certificate from vyos.pki import create_certificate_request @@ -25,23 +22,9 @@ from vyos.pki import create_private_key from vyos.pki import encode_certificate from vyos.pki import encode_private_key -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'https', 'certificates'] pki_base = ['pki'] -if not config.exists(base + ['system-generated-certificate']): - sys.exit(0) - def wrapped_pem_to_config_value(pem): out = [] for line in pem.strip().split("\n"): @@ -50,37 +33,34 @@ def wrapped_pem_to_config_value(pem): out.append(line) return "".join(out) -if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base + ['system-generated-certificate']): + return -valid_days = 365 -if config.exists(base + ['system-generated-certificate', 'lifetime']): - valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime'])) + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) -key = create_private_key('rsa', 2048) -subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'} -cert_req = create_certificate_request(subject, key, ['vyos']) -cert = create_certificate(cert_req, cert_req, key, valid_days) + valid_days = 365 + if config.exists(base + ['system-generated-certificate', 'lifetime']): + valid_days = int(config.return_value(base + ['system-generated-certificate', 'lifetime'])) -if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + key = create_private_key('rsa', 2048) + subject = {'country': 'GB', 'state': 'N/A', 'locality': 'N/A', 'organization': 'VyOS', 'common_name': 'vyos'} + cert_req = create_certificate_request(subject, key, ['vyos']) + cert = create_certificate(cert_req, cert_req, key, valid_days) -if key: - key_pem = encode_private_key(key) - config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', 'generated_https', 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) -if cert and key: - config.set(base + ['certificate'], value='generated_https') -else: - print('Failed to migrate system-generated-certificate from https service') + if key: + key_pem = encode_private_key(key) + config.set(pki_base + ['certificate', 'generated_https', 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) -config.delete(base + ['system-generated-certificate']) + if cert and key: + config.set(base + ['certificate'], value='generated_https') + else: + print('Failed to migrate system-generated-certificate from https service') -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)) - sys.exit(1) + config.delete(base + ['system-generated-certificate']) diff --git a/src/migration-scripts/https/3-to-4 b/src/migration-scripts/https/3-to-4 index b3cfca201..c01236cc6 100755..100644 --- a/src/migration-scripts/https/3-to-4 +++ b/src/migration-scripts/https/3-to-4 @@ -1,53 +1,34 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4768 rename node 'gql' to 'graphql'. -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - old_base = ['service', 'https', 'api', 'gql'] -if not config.exists(old_base): - # Nothing to do - sys.exit(0) - new_base = ['service', 'https', 'api', 'graphql'] -config.set(new_base) -nodes = config.list_nodes(old_base) -for node in nodes: - config.copy(old_base + [node], new_base + [node]) +def migrate(config: ConfigTree) -> None: + if not config.exists(old_base): + # Nothing to do + return + + config.set(new_base) -config.delete(old_base) + nodes = config.list_nodes(old_base) + for node in nodes: + config.copy(old_base + [node], new_base + [node]) -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)) - sys.exit(1) + config.delete(old_base) diff --git a/src/migration-scripts/https/4-to-5 b/src/migration-scripts/https/4-to-5 index 0dfb6ac19..0f1c7901f 100755..100644 --- a/src/migration-scripts/https/4-to-5 +++ b/src/migration-scripts/https/4-to-5 @@ -1,62 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5762: http: api: smoketests fail as they can not establish IPv6 connection # to uvicorn backend server, always make the UNIX domain socket the # default way of communication -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'https'] -if not config.exists(base): - # Nothing to do - sys.exit(0) - -# Delete "socket" CLI option - we always use UNIX domain sockets for -# NGINX <-> API server communication -if config.exists(base + ['api', 'socket']): - config.delete(base + ['api', 'socket']) - -# There is no need for an API service port, as UNIX domain sockets -# are used -if config.exists(base + ['api', 'port']): - config.delete(base + ['api', 'port']) - -# rename listen-port -> port ver virtual-host -if config.exists(base + ['virtual-host']): - for vhost in config.list_nodes(base + ['virtual-host']): - if config.exists(base + ['virtual-host', vhost, 'listen-port']): - config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port') -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)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # Delete "socket" CLI option - we always use UNIX domain sockets for + # NGINX <-> API server communication + if config.exists(base + ['api', 'socket']): + config.delete(base + ['api', 'socket']) + + # There is no need for an API service port, as UNIX domain sockets + # are used + if config.exists(base + ['api', 'port']): + config.delete(base + ['api', 'port']) + + # rename listen-port -> port ver virtual-host + if config.exists(base + ['virtual-host']): + for vhost in config.list_nodes(base + ['virtual-host']): + if config.exists(base + ['virtual-host', vhost, 'listen-port']): + config.rename(base + ['virtual-host', vhost, 'listen-port'], 'port') diff --git a/src/migration-scripts/https/5-to-6 b/src/migration-scripts/https/5-to-6 index 72e9e31f7..6ef6976b6 100755..100644 --- a/src/migration-scripts/https/5-to-6 +++ b/src/migration-scripts/https/5-to-6 @@ -1,25 +1,23 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5886: Add support for ACME protocol (LetsEncrypt), migrate https certbot # to new "pki certificate" CLI tree # T5902: Remove virtual-host import os -import sys from vyos.configtree import ConfigTree from vyos.defaults import directories @@ -27,81 +25,65 @@ from vyos.utils.process import cmd vyos_certbot_dir = directories['certbot'] -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'https'] -if not config.exists(base): - # Nothing to do - sys.exit(0) - -if config.exists(base + ['certificates', 'certbot']): - # both domain-name and email must be set on CLI - ensured by previous verify() - domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name']) - email = config.return_value(base + ['certificates', 'certbot', 'email']) - config.delete(base + ['certificates', 'certbot']) - - # Set default certname based on domain-name - cert_name = 'https-' + domain_names[0].split('.')[0] - # Overwrite certname from previous certbot calls if available - # We can not use python code like os.scandir due to filesystem permissions. - # This must be run as root - certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing / - if os.path.exists(certbot_live): - tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d') - tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net'] - tmp.remove(certbot_live) - cert_name = tmp[0].replace(certbot_live, '') - config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email) - config.set_tag(['pki', 'certificate']) - for domain in domain_names: - config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False) - - # Update Webserver certificate - config.set(base + ['certificates', 'certificate'], value=cert_name) - -if config.exists(base + ['virtual-host']): - allow_client = [] - listen_port = [] - listen_address = [] - for virtual_host in config.list_nodes(base + ['virtual-host']): - allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address'] - if config.exists(allow_path): - tmp = config.return_values(allow_path) - allow_client.extend(tmp) - - port_path = base + ['virtual-host', virtual_host, 'port'] - if config.exists(port_path): - tmp = config.return_value(port_path) - listen_port.append(tmp) - - listen_address_path = base + ['virtual-host', virtual_host, 'listen-address'] - if config.exists(listen_address_path): - tmp = config.return_value(listen_address_path) - listen_address.append(tmp) - - config.delete(base + ['virtual-host']) - for client in allow_client: - config.set(base + ['allow-client', 'address'], value=client, replace=False) - - # clear listen-address if "all" were specified - if '*' in listen_address: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['certificates', 'certbot']): + # both domain-name and email must be set on CLI - ensured by previous verify() + domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name']) + email = config.return_value(base + ['certificates', 'certbot', 'email']) + config.delete(base + ['certificates', 'certbot']) + + # Set default certname based on domain-name + cert_name = 'https-' + domain_names[0].split('.')[0] + # Overwrite certname from previous certbot calls if available + # We can not use python code like os.scandir due to filesystem permissions. + # This must be run as root + certbot_live = f'{vyos_certbot_dir}/live/' # we need the trailing / + if os.path.exists(certbot_live): + tmp = cmd(f'sudo find {certbot_live} -maxdepth 1 -type d') + tmp = tmp.split() # tmp = ['/config/auth/letsencrypt/live', '/config/auth/letsencrypt/live/router.vyos.net'] + tmp.remove(certbot_live) + cert_name = tmp[0].replace(certbot_live, '') + + config.set(['pki', 'certificate', cert_name, 'acme', 'email'], value=email) + config.set_tag(['pki', 'certificate']) + for domain in domain_names: + config.set(['pki', 'certificate', cert_name, 'acme', 'domain-name'], value=domain, replace=False) + + # Update Webserver certificate + config.set(base + ['certificates', 'certificate'], value=cert_name) + + if config.exists(base + ['virtual-host']): + allow_client = [] + listen_port = [] listen_address = [] - for address in listen_address: - config.set(base + ['listen-address'], value=address, replace=False) - -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)) - sys.exit(1) + for virtual_host in config.list_nodes(base + ['virtual-host']): + allow_path = base + ['virtual-host', virtual_host, 'allow-client', 'address'] + if config.exists(allow_path): + tmp = config.return_values(allow_path) + allow_client.extend(tmp) + + port_path = base + ['virtual-host', virtual_host, 'port'] + if config.exists(port_path): + tmp = config.return_value(port_path) + listen_port.append(tmp) + + listen_address_path = base + ['virtual-host', virtual_host, 'listen-address'] + if config.exists(listen_address_path): + tmp = config.return_value(listen_address_path) + listen_address.append(tmp) + + config.delete(base + ['virtual-host']) + for client in allow_client: + config.set(base + ['allow-client', 'address'], value=client, replace=False) + + # clear listen-address if "all" were specified + if '*' in listen_address: + listen_address = [] + for address in listen_address: + config.set(base + ['listen-address'], value=address, replace=False) diff --git a/src/migration-scripts/ids/0-to-1 b/src/migration-scripts/ids/0-to-1 index 8b7850a1a..1b963e839 100755..100644 --- a/src/migration-scripts/ids/0-to-1 +++ b/src/migration-scripts/ids/0-to-1 @@ -1,56 +1,38 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit +# T4557: Migrate threshold and add new threshold types 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 = ['service', 'ids', 'ddos-protection'] -config = ConfigTree(config_file) - -if not config.exists(base + ['threshold']): - # Nothing to do - exit(0) -else: - if config.exists(base + ['threshold', 'fps']): - tmp = config.return_value(base + ['threshold', 'fps']) - config.delete(base + ['threshold', 'fps']) - config.set(base + ['threshold', 'general', 'fps'], value=tmp) - if config.exists(base + ['threshold', 'mbps']): - tmp = config.return_value(base + ['threshold', 'mbps']) - config.delete(base + ['threshold', 'mbps']) - config.set(base + ['threshold', 'general', 'mbps'], value=tmp) - if config.exists(base + ['threshold', 'pps']): - tmp = config.return_value(base + ['threshold', 'pps']) - config.delete(base + ['threshold', 'pps']) - config.set(base + ['threshold', 'general', 'pps'], value=tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base + ['threshold']): + # Nothing to do + return + else: + if config.exists(base + ['threshold', 'fps']): + tmp = config.return_value(base + ['threshold', 'fps']) + config.delete(base + ['threshold', 'fps']) + config.set(base + ['threshold', 'general', 'fps'], value=tmp) + if config.exists(base + ['threshold', 'mbps']): + tmp = config.return_value(base + ['threshold', 'mbps']) + config.delete(base + ['threshold', 'mbps']) + config.set(base + ['threshold', 'general', 'mbps'], value=tmp) + if config.exists(base + ['threshold', 'pps']): + tmp = config.return_value(base + ['threshold', 'pps']) + config.delete(base + ['threshold', 'pps']) + config.set(base + ['threshold', 'general', 'pps'], value=tmp) diff --git a/src/migration-scripts/interfaces/0-to-1 b/src/migration-scripts/interfaces/0-to-1 index 25f6842eb..7c135e76e 100755..100644 --- a/src/migration-scripts/interfaces/0-to-1 +++ b/src/migration-scripts/interfaces/0-to-1 @@ -1,11 +1,23 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Change syntax of bridge interface # - move interface based bridge-group to actual bridge (de-nest) # - make stp and igmp-snooping nodes valueless # https://vyos.dev/T1556 -import sys from vyos.configtree import ConfigTree def migrate_bridge(config, tree, intf): @@ -36,83 +48,66 @@ def migrate_bridge(config, tree, intf): config.delete(tree_bridge) -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'bridge'] if not config.exists(base): # Nothing to do - sys.exit(0) - else: - # - # make stp and igmp-snooping nodes valueless - # - for br in config.list_nodes(base): - # STP: check if enabled - if config.exists(base + [br, 'stp']): - stp_val = config.return_value(base + [br, 'stp']) - # STP: delete node with old syntax - config.delete(base + [br, 'stp']) - # STP: set new node - if enabled - if stp_val == "true": - config.set(base + [br, 'stp'], value=None) - - # igmp-snooping: check if enabled - if config.exists(base + [br, 'igmp-snooping', 'querier']): - igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier']) - # igmp-snooping: delete node with old syntax - config.delete(base + [br, 'igmp-snooping', 'querier']) - # igmp-snooping: set new node - if enabled - if igmp_val == "enable": - config.set(base + [br, 'igmp', 'querier'], value=None) - - # - # move interface based bridge-group to actual bridge (de-nest) - # - bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless'] - for type in bridge_types: - if not config.exists(['interfaces', type]): - continue - - for interface in config.list_nodes(['interfaces', type]): - # check if bridge-group exists - bridge_group = ['interfaces', type, interface] - if config.exists(bridge_group + ['bridge-group']): - migrate_bridge(config, bridge_group, interface) - - # We also need to migrate VLAN interfaces - vlan_base = ['interfaces', type, interface, 'vif'] - if config.exists(vlan_base): - for vlan in config.list_nodes(vlan_base): - intf = "{}.{}".format(interface, vlan) - migrate_bridge(config, vlan_base + [vlan], intf) - - # And then we have service VLANs (vif-s) interfaces - vlan_base = ['interfaces', type, interface, 'vif-s'] - if config.exists(vlan_base): - for vif_s in config.list_nodes(vlan_base): - intf = "{}.{}".format(interface, vif_s) - migrate_bridge(config, vlan_base + [vif_s], intf) - - # Every service VLAN can have multiple customer VLANs (vif-c) - vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] - if config.exists(vlan_c): - for vif_c in config.list_nodes(vlan_c): - intf = "{}.{}.{}".format(interface, vif_s, vif_c) - migrate_bridge(config, vlan_c + [vif_c], intf) - - 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)) - sys.exit(1) + return + + # + # make stp and igmp-snooping nodes valueless + # + for br in config.list_nodes(base): + # STP: check if enabled + if config.exists(base + [br, 'stp']): + stp_val = config.return_value(base + [br, 'stp']) + # STP: delete node with old syntax + config.delete(base + [br, 'stp']) + # STP: set new node - if enabled + if stp_val == "true": + config.set(base + [br, 'stp'], value=None) + + # igmp-snooping: check if enabled + if config.exists(base + [br, 'igmp-snooping', 'querier']): + igmp_val = config.return_value(base + [br, 'igmp-snooping', 'querier']) + # igmp-snooping: delete node with old syntax + config.delete(base + [br, 'igmp-snooping', 'querier']) + # igmp-snooping: set new node - if enabled + if igmp_val == "enable": + config.set(base + [br, 'igmp', 'querier'], value=None) + + # + # move interface based bridge-group to actual bridge (de-nest) + # + bridge_types = ['bonding', 'ethernet', 'l2tpv3', 'openvpn', 'vxlan', 'wireless'] + for type in bridge_types: + if not config.exists(['interfaces', type]): + continue + + for interface in config.list_nodes(['interfaces', type]): + # check if bridge-group exists + bridge_group = ['interfaces', type, interface] + if config.exists(bridge_group + ['bridge-group']): + migrate_bridge(config, bridge_group, interface) + + # We also need to migrate VLAN interfaces + vlan_base = ['interfaces', type, interface, 'vif'] + if config.exists(vlan_base): + for vlan in config.list_nodes(vlan_base): + intf = "{}.{}".format(interface, vlan) + migrate_bridge(config, vlan_base + [vlan], intf) + + # And then we have service VLANs (vif-s) interfaces + vlan_base = ['interfaces', type, interface, 'vif-s'] + if config.exists(vlan_base): + for vif_s in config.list_nodes(vlan_base): + intf = "{}.{}".format(interface, vif_s) + migrate_bridge(config, vlan_base + [vif_s], intf) + + # Every service VLAN can have multiple customer VLANs (vif-c) + vlan_c = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] + if config.exists(vlan_c): + for vif_c in config.list_nodes(vlan_c): + intf = "{}.{}.{}".format(interface, vif_s, vif_c) + migrate_bridge(config, vlan_c + [vif_c], intf) diff --git a/src/migration-scripts/interfaces/1-to-2 b/src/migration-scripts/interfaces/1-to-2 index c95623c2b..ebf02b028 100755..100644 --- a/src/migration-scripts/interfaces/1-to-2 +++ b/src/migration-scripts/interfaces/1-to-2 @@ -1,28 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Change syntax of bond interface # - move interface based bond-group to actual bond (de-nest) # https://vyos.dev/T1614 -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['interfaces', 'bonding'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + # # move interface based bond-group to actual bond (de-nest) # @@ -54,10 +57,3 @@ else: # # so we simply disable arp_interval by setting it to 0 and miimon will take care about the link config.set(base + [bond, 'arp-monitor', 'interval'], value='0') - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11 index cafaa3fa4..8a562f2d0 100755..100644 --- a/src/migration-scripts/interfaces/10-to-11 +++ b/src/migration-scripts/interfaces/10-to-11 @@ -1,41 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # rename WWAN (wirelessmodem) serial interface from non persistent ttyUSB2 to # a bus like name, e.g. "usb0b1.3p1.3" import os -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - 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 = ['interfaces', 'wirelessmodem'] - config = ConfigTree(config_file) - base = ['interfaces', 'wirelessmodem'] +def migrate(config: ConfigTree) -> None: if not config.exists(base): # Nothing to do - exit(0) + return for wwan in config.list_nodes(base): if config.exists(base + [wwan, 'device']): @@ -46,10 +36,3 @@ if __name__ == '__main__': device_file = os.path.realpath(os.path.join(root, file)) if os.path.basename(device_file) == device: config.set(base + [wwan, 'device'], value=file, replace=True) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/11-to-12 b/src/migration-scripts/interfaces/11-to-12 index e9eb7f939..132cecbb7 100755..100644 --- a/src/migration-scripts/interfaces/11-to-12 +++ b/src/migration-scripts/interfaces/11-to-12 @@ -1,37 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - rename 'dhcpv6-options prefix-delegation' from single node to a new tag node # 'dhcpv6-options pd 0' # - delete 'sla-len' from CLI - value is calculated on demand -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: for type in config.list_nodes(['interfaces']): for interface in config.list_nodes(['interfaces', type]): # cache current config tree @@ -49,10 +37,3 @@ if __name__ == '__main__': sla_config = new_base + [pd, 'interface', tmp, 'sla-len'] if config.exists(sla_config): config.delete(sla_config) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13 index ef1d93903..585deb898 100755..100644 --- a/src/migration-scripts/interfaces/12-to-13 +++ b/src/migration-scripts/interfaces/12-to-13 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T2903: Change vif-s ethertype from numeric number to literal # - 0x88a8 -> 802.1ad @@ -20,20 +19,9 @@ # - T2905: Change WWAN "ondemand" node to "connect-on-demand" to have identical # CLI nodes for both types of dialer interfaces -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: # # T2903 # @@ -61,11 +49,3 @@ if __name__ == '__main__': for interface in config.list_nodes(wwan_base): if config.exists(wwan_base + [interface, 'ondemand']): config.rename(wwan_base + [interface, 'ondemand'], 'connect-on-demand') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) - diff --git a/src/migration-scripts/interfaces/13-to-14 b/src/migration-scripts/interfaces/13-to-14 index b20d8b4db..45d8e3b5f 100755..100644 --- a/src/migration-scripts/interfaces/13-to-14 +++ b/src/migration-scripts/interfaces/13-to-14 @@ -1,39 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3043: rename Wireless interface security mode 'both' to 'wpa+wpa2' # T3043: move "system wifi-regulatory-domain" to indicidual wireless interface -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'wireless'] + if not config.exists(base): # Nothing to do - exit(0) + return country_code = '' cc_cli = ['system', 'wifi-regulatory-domain'] @@ -50,10 +40,3 @@ if __name__ == '__main__': if country_code: config.set(base + [wifi, 'country-code'], value=country_code) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/14-to-15 b/src/migration-scripts/interfaces/14-to-15 index e21251f86..d45d59bba 100755..100644 --- a/src/migration-scripts/interfaces/14-to-15 +++ b/src/migration-scripts/interfaces/14-to-15 @@ -1,39 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3048: remove smp-affinity node from ethernet and use tuned instead -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'ethernet'] if not config.exists(base): # Nothing to do - exit(0) + return migrate = False for interface in config.list_nodes(base): @@ -47,10 +36,3 @@ if __name__ == '__main__': if migrate: config.set(['system', 'options', 'performance'], value='throughput') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/15-to-16 b/src/migration-scripts/interfaces/15-to-16 index ae3441b9f..c9abdb5f8 100755..100644 --- a/src/migration-scripts/interfaces/15-to-16 +++ b/src/migration-scripts/interfaces/15-to-16 @@ -1,48 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # remove pppoe "ipv6 enable" option -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'pppoe'] if not config.exists(base): # Nothing to do - exit(0) + return for interface in config.list_nodes(base): ipv6_enable = base + [interface, 'ipv6', 'enable'] if config.exists(ipv6_enable): config.delete(ipv6_enable) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/16-to-17 b/src/migration-scripts/interfaces/16-to-17 index 75f160686..7d241ac68 100755..100644 --- a/src/migration-scripts/interfaces/16-to-17 +++ b/src/migration-scripts/interfaces/16-to-17 @@ -1,40 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Command line migration of port mirroring # https://vyos.dev/T3089 -import sys from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'ethernet'] if not config.exists(base): # Nothing to do - sys.exit(0) + return for interface in config.list_nodes(base): mirror_old_base = base + [interface, 'mirror'] @@ -43,10 +31,3 @@ if __name__ == '__main__': if config.exists(mirror_old_base): config.delete(mirror_old_base) config.set(mirror_old_base + ['ingress'],intf[0]) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/17-to-18 b/src/migration-scripts/interfaces/17-to-18 index 51486ac37..f45695a88 100755..100644 --- a/src/migration-scripts/interfaces/17-to-18 +++ b/src/migration-scripts/interfaces/17-to-18 @@ -1,37 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3043: Move "system wifi-regulatory-domain" to indicidual wireless interface. # Country Code will be migratred from upper to lower case. # T3140: Relax ethernet interface offload-options -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: # T3140: Cleanup ethernet offload-options, remove on/off value and use # valueless nodes instead. eth_base = ['interfaces', 'ethernet'] @@ -62,10 +50,3 @@ if __name__ == '__main__': if config.exists(ccode): tmp = config.return_value(ccode) config.set(ccode, value=tmp.lower(), replace=True) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index c3209f250..ae1a07adb 100755..100644 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -1,24 +1,20 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. import os -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree def replace_nat_interfaces(config, old, new): @@ -40,21 +36,11 @@ def replace_nat_interfaces(config, old, new): config.set(conf_rule + ['outbound-interface'], value=new) -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'wirelessmodem'] if not config.exists(base): # Nothing to do - exit(0) + return new_base = ['interfaces', 'wwan'] config.set(new_base) @@ -98,10 +84,3 @@ if __name__ == '__main__': # the new wwan interface use regular IP addressing config.set(new_base + [interface, 'address'], value='dhcp') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 index 05abae898..7ee6302e2 100755..100644 --- a/src/migration-scripts/interfaces/19-to-20 +++ b/src/migration-scripts/interfaces/19-to-20 @@ -1,34 +1,21 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: for type in ['tunnel', 'l2tpv3']: base = ['interfaces', type] if not config.exists(base): @@ -52,10 +39,3 @@ if __name__ == '__main__': remote_ip_path = base + [interface, 'remote-ip'] if config.exists(remote_ip_path): config.rename(remote_ip_path, 'remote') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/2-to-3 b/src/migration-scripts/interfaces/2-to-3 index 15c3bc8be..695dcbf7a 100755..100644 --- a/src/migration-scripts/interfaces/2-to-3 +++ b/src/migration-scripts/interfaces/2-to-3 @@ -1,28 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Change syntax of openvpn encryption settings # - move cipher from encryption to encryption cipher # https://vyos.dev/T1704 -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['interfaces', 'openvpn'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + + if not config.exists(base): + # Nothing to do + return # # move cipher from "encryption" to "encryption cipher" # @@ -35,9 +38,3 @@ else: config.delete(['interfaces', 'openvpn', intf, 'encryption']) # Add new syntax to config config.set(['interfaces', 'openvpn', intf, 'encryption', 'cipher'], value=cipher) - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21 index 14ad0fe4d..0b6895177 100755..100644 --- a/src/migration-scripts/interfaces/20-to-21 +++ b/src/migration-scripts/interfaces/20-to-21 @@ -1,120 +1,107 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3619: mirror Linux Kernel defaults for ethernet offloading options into VyOS # CLI. See https://vyos.dev/T3619#102254 for all the details. # T3787: Remove deprecated UDP fragmentation offloading option -from sys import argv - from vyos.ethtool import Ethtool 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() +from vyos.utils.network import interface_exists base = ['interfaces', 'ethernet'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) - -for ifname in config.list_nodes(base): - eth = Ethtool(ifname) - - # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is - # enabled via CLI but not supported by the NIC - we remove it from the CLI - configured = config.exists(base + [ifname, 'offload', 'gro']) - enabled, fixed = eth.get_generic_receive_offload() - if configured and fixed: - config.delete(base + [ifname, 'offload', 'gro']) - elif enabled and not fixed: - config.set(base + [ifname, 'offload', 'gro']) - - # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is - # enabled via CLI but not supported by the NIC - we remove it from the CLI - configured = config.exists(base + [ifname, 'offload', 'gso']) - enabled, fixed = eth.get_generic_segmentation_offload() - if configured and fixed: - config.delete(base + [ifname, 'offload', 'gso']) - elif enabled and not fixed: - config.set(base + [ifname, 'offload', 'gso']) - - # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is - # enabled via CLI but not supported by the NIC - we remove it from the CLI - configured = config.exists(base + [ifname, 'offload', 'lro']) - enabled, fixed = eth.get_large_receive_offload() - if configured and fixed: - config.delete(base + [ifname, 'offload', 'lro']) - elif enabled and not fixed: - config.set(base + [ifname, 'offload', 'lro']) - - # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is - # enabled via CLI but not supported by the NIC - we remove it from the CLI - configured = config.exists(base + [ifname, 'offload', 'sg']) - enabled, fixed = eth.get_scatter_gather() - if configured and fixed: - config.delete(base + [ifname, 'offload', 'sg']) - elif enabled and not fixed: - config.set(base + [ifname, 'offload', 'sg']) - - # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is - # enabled via CLI but not supported by the NIC - we remove it from the CLI - configured = config.exists(base + [ifname, 'offload', 'tso']) - enabled, fixed = eth.get_tcp_segmentation_offload() - if configured and fixed: - config.delete(base + [ifname, 'offload', 'tso']) - elif enabled and not fixed: - config.set(base + [ifname, 'offload', 'tso']) - - # Remove deprecated UDP fragmentation offloading option - if config.exists(base + [ifname, 'offload', 'ufo']): - config.delete(base + [ifname, 'offload', 'ufo']) - - # Also while processing the interface configuration, not all adapters support - # changing the speed and duplex settings. If the desired speed and duplex - # values do not work for the NIC driver, we change them back to the default - # value of "auto" - which will be applied if the CLI node is deleted. - speed_path = base + [ifname, 'speed'] - duplex_path = base + [ifname, 'duplex'] - # speed and duplex must always be set at the same time if not set to "auto" - if config.exists(speed_path) and config.exists(duplex_path): - speed = config.return_value(speed_path) - duplex = config.return_value(duplex_path) - if speed != 'auto' and duplex != 'auto': - if not eth.check_speed_duplex(speed, duplex): - config.delete(speed_path) - config.delete(duplex_path) - - # Also while processing the interface configuration, not all adapters support - # changing disabling flow-control - or change this setting. If disabling - # flow-control is not supported by the NIC, we remove the setting from CLI - flow_control_path = base + [ifname, 'disable-flow-control'] - if config.exists(flow_control_path): - if not eth.check_flow_control(): - config.delete(flow_control_path) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + for ifname in config.list_nodes(base): + # Bail out early if interface vanished from system + if not interface_exists(ifname): + continue + + eth = Ethtool(ifname) + + # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is + # enabled via CLI but not supported by the NIC - we remove it from the CLI + configured = config.exists(base + [ifname, 'offload', 'gro']) + enabled, fixed = eth.get_generic_receive_offload() + if configured and fixed: + config.delete(base + [ifname, 'offload', 'gro']) + elif enabled and not fixed: + config.set(base + [ifname, 'offload', 'gro']) + + # If GSO is enabled by the Kernel - we reflect this on the CLI. If GSO is + # enabled via CLI but not supported by the NIC - we remove it from the CLI + configured = config.exists(base + [ifname, 'offload', 'gso']) + enabled, fixed = eth.get_generic_segmentation_offload() + if configured and fixed: + config.delete(base + [ifname, 'offload', 'gso']) + elif enabled and not fixed: + config.set(base + [ifname, 'offload', 'gso']) + + # If LRO is enabled by the Kernel - we reflect this on the CLI. If LRO is + # enabled via CLI but not supported by the NIC - we remove it from the CLI + configured = config.exists(base + [ifname, 'offload', 'lro']) + enabled, fixed = eth.get_large_receive_offload() + if configured and fixed: + config.delete(base + [ifname, 'offload', 'lro']) + elif enabled and not fixed: + config.set(base + [ifname, 'offload', 'lro']) + + # If SG is enabled by the Kernel - we reflect this on the CLI. If SG is + # enabled via CLI but not supported by the NIC - we remove it from the CLI + configured = config.exists(base + [ifname, 'offload', 'sg']) + enabled, fixed = eth.get_scatter_gather() + if configured and fixed: + config.delete(base + [ifname, 'offload', 'sg']) + elif enabled and not fixed: + config.set(base + [ifname, 'offload', 'sg']) + + # If TSO is enabled by the Kernel - we reflect this on the CLI. If TSO is + # enabled via CLI but not supported by the NIC - we remove it from the CLI + configured = config.exists(base + [ifname, 'offload', 'tso']) + enabled, fixed = eth.get_tcp_segmentation_offload() + if configured and fixed: + config.delete(base + [ifname, 'offload', 'tso']) + elif enabled and not fixed: + config.set(base + [ifname, 'offload', 'tso']) + + # Remove deprecated UDP fragmentation offloading option + if config.exists(base + [ifname, 'offload', 'ufo']): + config.delete(base + [ifname, 'offload', 'ufo']) + + # Also while processing the interface configuration, not all adapters support + # changing the speed and duplex settings. If the desired speed and duplex + # values do not work for the NIC driver, we change them back to the default + # value of "auto" - which will be applied if the CLI node is deleted. + speed_path = base + [ifname, 'speed'] + duplex_path = base + [ifname, 'duplex'] + # speed and duplex must always be set at the same time if not set to "auto" + if config.exists(speed_path) and config.exists(duplex_path): + speed = config.return_value(speed_path) + duplex = config.return_value(duplex_path) + if speed != 'auto' and duplex != 'auto': + if not eth.check_speed_duplex(speed, duplex): + config.delete(speed_path) + config.delete(duplex_path) + + # Also while processing the interface configuration, not all adapters support + # changing disabling flow-control - or change this setting. If disabling + # flow-control is not supported by the NIC, we remove the setting from CLI + flow_control_path = base + [ifname, 'disable-flow-control'] + if config.exists(flow_control_path): + if not eth.check_flow_control(): + config.delete(flow_control_path) diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22 index 1838eb1c0..046eb10c6 100755..100644 --- a/src/migration-scripts/interfaces/21-to-22 +++ b/src/migration-scripts/interfaces/21-to-22 @@ -1,46 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) -base = ['interfaces', 'tunnel'] - -if not config.exists(base): - exit(0) +def migrate(config: ConfigTree) -> None: + base = ['interfaces', 'tunnel'] -for interface in config.list_nodes(base): - path = base + [interface, 'dhcp-interface'] - if config.exists(path): - tmp = config.return_value(path) - config.delete(path) - config.set(base + [interface, 'source-interface'], value=tmp) + if not config.exists(base): + return -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) + for interface in config.list_nodes(base): + path = base + [interface, 'dhcp-interface'] + if config.exists(path): + tmp = config.return_value(path) + config.delete(path) + config.set(base + [interface, 'source-interface'], value=tmp) diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23 index 04e023e77..31f7fa2ff 100755..100644 --- a/src/migration-scripts/interfaces/22-to-23 +++ b/src/migration-scripts/interfaces/22-to-23 @@ -1,39 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. + # Deletes Wireguard peers if they have the same public key as the router has. -import sys + from vyos.configtree import ConfigTree from vyos.utils.network import is_wireguard_key_pair -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'wireguard'] if not config.exists(base): # Nothing to do - sys.exit(0) + return + for interface in config.list_nodes(base): if not config.exists(base + [interface, 'private-key']): continue @@ -48,10 +38,3 @@ if __name__ == '__main__': if not config.exists(peer_base + ['disable']) \ and is_wireguard_key_pair(private_key, peer_public_key): config.set(peer_base + ['disable']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24 index 8b21fce51..b72ceee49 100755..100644 --- a/src/migration-scripts/interfaces/23-to-24 +++ b/src/migration-scripts/interfaces/23-to-24 @@ -1,21 +1,18 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit from vyos.configtree import ConfigTree def migrate_ospf(config, path, interface): @@ -74,17 +71,7 @@ def migrate_ripng(config, path, interface): if len(config.list_nodes(path[:-1])) == 0: config.delete(path[:-1]) -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: # # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" # @@ -136,10 +123,3 @@ if __name__ == '__main__': migrate_ripng(config, vif_s_ipv6_base, ifname) migrate_ospf(config, vif_s_ip_base, ifname) migrate_ospfv3(config, vif_s_ipv6_base, ifname) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25 index 8fd79ecc6..9f8cc80ec 100755..100644 --- a/src/migration-scripts/interfaces/24-to-25 +++ b/src/migration-scripts/interfaces/24-to-25 @@ -1,41 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # A VTI interface also requires an IPSec configuration - VyOS 1.2 supported # having a VTI interface in the CLI but no IPSec configuration - drop VTI # configuration if this is the case for VyOS 1.4 -import sys from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'vti'] if not config.exists(base): # Nothing to do - sys.exit(0) + return ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] for interface in config.list_nodes(base): @@ -51,10 +39,3 @@ if __name__ == '__main__': break if not found: config.delete(base + [interface]) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26 index 9aa6ea5e3..7a4032d10 100755..100644 --- a/src/migration-scripts/interfaces/25-to-26 +++ b/src/migration-scripts/interfaces/25-to-26 @@ -1,24 +1,22 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrate Wireguard to store keys in CLI # Migrate EAPoL to PKI configuration import os -import sys from vyos.configtree import ConfigTree from vyos.pki import CERT_BEGIN @@ -53,335 +51,318 @@ def read_file_for_pki(config_auth_path): return output -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - AUTH_DIR = '/config/auth' pki_base = ['pki'] -# OpenVPN -base = ['interfaces', 'openvpn'] +def migrate(config: ConfigTree) -> None: + # OpenVPN + base = ['interfaces', 'openvpn'] + + if config.exists(base): + for interface in config.list_nodes(base): + x509_base = base + [interface, 'tls'] + pki_name = f'openvpn_{interface}' + + if config.exists(base + [interface, 'shared-secret-key-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + config.set_tag(pki_base + ['openvpn', 'shared-secret']) + + key_file = config.return_value(base + [interface, 'shared-secret-key-file']) + key = read_file_for_pki(key_file) + key_pki_name = f'{pki_name}_shared' + + if key: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'shared-secret-key'], value=key_pki_name) + else: + print(f'Failed to migrate shared-secret-key on openvpn interface {interface}') + + config.delete(base + [interface, 'shared-secret-key-file']) + + if not config.exists(base + [interface, 'tls']): + continue + + if config.exists(base + [interface, 'tls', 'auth-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + config.set_tag(pki_base + ['openvpn', 'shared-secret']) + + key_file = config.return_value(base + [interface, 'tls', 'auth-file']) + key = read_file_for_pki(key_file) + key_pki_name = f'{pki_name}_auth' + + if key: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name) + else: + print(f'Failed to migrate auth-key on openvpn interface {interface}') + + config.delete(base + [interface, 'tls', 'auth-file']) + + if config.exists(base + [interface, 'tls', 'crypt-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + config.set_tag(pki_base + ['openvpn', 'shared-secret']) + + key_file = config.return_value(base + [interface, 'tls', 'crypt-file']) + key = read_file_for_pki(key_file) + key_pki_name = f'{pki_name}_crypt' + + if key: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name) + else: + print(f'Failed to migrate crypt-key on openvpn interface {interface}') + + config.delete(base + [interface, 'tls', 'crypt-file']) + + ca_certs = {} + + if config.exists(x509_base + ['ca-cert-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + cert_file = config.return_value(x509_base + ['ca-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + certs_str = f.read() + certs_data = certs_str.split(CERT_BEGIN) + index = 1 + for cert_data in certs_data[1:]: + cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False) + + if cert: + ca_certs[f'{pki_name}_{index}'] = cert + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False) + else: + print(f'Failed to migrate CA certificate on openvpn interface {interface}') + + index += 1 + else: + print(f'Failed to migrate CA certificate on openvpn interface {interface}') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['crl-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + crl_file = config.return_value(x509_base + ['crl-file']) + crl_path = os.path.join(AUTH_DIR, crl_file) + crl = None + crl_ca_name = None + + if os.path.isfile(crl_path): + if not os.access(crl_path, os.R_OK): + run(f'sudo chmod 644 {crl_path}') + + with open(crl_path, 'r') as f: + crl_data = f.read() + crl = load_crl(crl_data, wrap_tags=False) + + for ca_name, ca_cert in ca_certs.items(): + if verify_crl(crl, ca_cert): + crl_ca_name = ca_name + break + + if crl and crl_ca_name: + crl_pem = encode_certificate(crl) + config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) + else: + print(f'Failed to migrate CRL on openvpn interface {interface}') + + config.delete(x509_base + ['crl-file']) + + if config.exists(x509_base + ['cert-file']): + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) + + cert_file = config.return_value(x509_base + ['cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) + else: + print(f'Failed to migrate certificate on openvpn interface {interface}') + + config.delete(x509_base + ['cert-file']) + + if config.exists(x509_base + ['key-file']): + key_file = config.return_value(x509_base + ['key-file']) + key_path = os.path.join(AUTH_DIR, key_file) + key = None + + if os.path.isfile(key_path): + if not os.access(key_path, os.R_OK): + run(f'sudo chmod 644 {key_path}') + + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) + + if key: + key_pem = encode_private_key(key, passphrase=None) + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + else: + print(f'Failed to migrate private key on openvpn interface {interface}') + + config.delete(x509_base + ['key-file']) + + if config.exists(x509_base + ['dh-file']): + if not config.exists(pki_base + ['dh']): + config.set(pki_base + ['dh']) + config.set_tag(pki_base + ['dh']) + + dh_file = config.return_value(x509_base + ['dh-file']) + dh_path = os.path.join(AUTH_DIR, dh_file) + dh = None + + if os.path.isfile(dh_path): + if not os.access(dh_path, os.R_OK): + run(f'sudo chmod 644 {dh_path}') + + with open(dh_path, 'r') as f: + dh_data = f.read() + dh = load_dh_parameters(dh_data, wrap_tags=False) + + if dh: + dh_pem = encode_dh_parameters(dh) + config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem)) + config.set(x509_base + ['dh-params'], value=pki_name) + else: + print(f'Failed to migrate DH parameters on openvpn interface {interface}') + + config.delete(x509_base + ['dh-file']) + + # Wireguard + base = ['interfaces', 'wireguard'] + + if config.exists(base): + for interface in config.list_nodes(base): + private_key_path = base + [interface, 'private-key'] + + key_file = 'default' + if config.exists(private_key_path): + key_file = config.return_value(private_key_path) + + full_key_path = f'/config/auth/wireguard/{key_file}/private.key' + + if not os.path.exists(full_key_path): + print(f'Could not find wireguard private key for migration on interface "{interface}"') + continue + + with open(full_key_path, 'r') as f: + key_data = f.read().strip() + config.set(private_key_path, value=key_data) + + for peer in config.list_nodes(base + [interface, 'peer']): + config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key') + + # Ethernet EAPoL + base = ['interfaces', 'ethernet'] + + if config.exists(base): + for interface in config.list_nodes(base): + if not config.exists(base + [interface, 'eapol']): + continue + + x509_base = base + [interface, 'eapol'] + pki_name = f'eapol_{interface}' + + if config.exists(x509_base + ['ca-cert-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + cert_file = config.return_value(x509_base + ['ca-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=pki_name) + else: + print(f'Failed to migrate CA certificate on eapol config for interface {interface}') + + config.delete(x509_base + ['ca-cert-file']) -if config.exists(base): - for interface in config.list_nodes(base): - x509_base = base + [interface, 'tls'] - pki_name = f'openvpn_{interface}' + if config.exists(x509_base + ['cert-file']): + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) - if config.exists(base + [interface, 'shared-secret-key-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - config.set_tag(pki_base + ['openvpn', 'shared-secret']) + cert_file = config.return_value(x509_base + ['cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None - key_file = config.return_value(base + [interface, 'shared-secret-key-file']) - key = read_file_for_pki(key_file) - key_pki_name = f'{pki_name}_shared' + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') - if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'shared-secret-key'], value=key_pki_name) - else: - print(f'Failed to migrate shared-secret-key on openvpn interface {interface}') + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) - config.delete(base + [interface, 'shared-secret-key-file']) + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) + else: + print(f'Failed to migrate certificate on eapol config for interface {interface}') - if not config.exists(base + [interface, 'tls']): - continue + config.delete(x509_base + ['cert-file']) - if config.exists(base + [interface, 'tls', 'auth-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - config.set_tag(pki_base + ['openvpn', 'shared-secret']) - - key_file = config.return_value(base + [interface, 'tls', 'auth-file']) - key = read_file_for_pki(key_file) - key_pki_name = f'{pki_name}_auth' - - if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name) - else: - print(f'Failed to migrate auth-key on openvpn interface {interface}') - - config.delete(base + [interface, 'tls', 'auth-file']) - - if config.exists(base + [interface, 'tls', 'crypt-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - config.set_tag(pki_base + ['openvpn', 'shared-secret']) - - key_file = config.return_value(base + [interface, 'tls', 'crypt-file']) - key = read_file_for_pki(key_file) - key_pki_name = f'{pki_name}_crypt' - - if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name) - else: - print(f'Failed to migrate crypt-key on openvpn interface {interface}') - - config.delete(base + [interface, 'tls', 'crypt-file']) - - ca_certs = {} - - if config.exists(x509_base + ['ca-cert-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) - - cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - certs_str = f.read() - certs_data = certs_str.split(CERT_BEGIN) - index = 1 - for cert_data in certs_data[1:]: - cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False) - - if cert: - ca_certs[f'{pki_name}_{index}'] = cert - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False) - else: - print(f'Failed to migrate CA certificate on openvpn interface {interface}') - - index += 1 - else: - print(f'Failed to migrate CA certificate on openvpn interface {interface}') - - config.delete(x509_base + ['ca-cert-file']) - - if config.exists(x509_base + ['crl-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) - - crl_file = config.return_value(x509_base + ['crl-file']) - crl_path = os.path.join(AUTH_DIR, crl_file) - crl = None - crl_ca_name = None - - if os.path.isfile(crl_path): - if not os.access(crl_path, os.R_OK): - run(f'sudo chmod 644 {crl_path}') - - with open(crl_path, 'r') as f: - crl_data = f.read() - crl = load_crl(crl_data, wrap_tags=False) - - for ca_name, ca_cert in ca_certs.items(): - if verify_crl(crl, ca_cert): - crl_ca_name = ca_name - break - - if crl and crl_ca_name: - crl_pem = encode_certificate(crl) - config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) - else: - print(f'Failed to migrate CRL on openvpn interface {interface}') - - config.delete(x509_base + ['crl-file']) - - if config.exists(x509_base + ['cert-file']): - if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) - - cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) - else: - print(f'Failed to migrate certificate on openvpn interface {interface}') - - config.delete(x509_base + ['cert-file']) - - if config.exists(x509_base + ['key-file']): - key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - if key: - key_pem = encode_private_key(key, passphrase=None) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) - else: - print(f'Failed to migrate private key on openvpn interface {interface}') - - config.delete(x509_base + ['key-file']) - - if config.exists(x509_base + ['dh-file']): - if not config.exists(pki_base + ['dh']): - config.set(pki_base + ['dh']) - config.set_tag(pki_base + ['dh']) - - dh_file = config.return_value(x509_base + ['dh-file']) - dh_path = os.path.join(AUTH_DIR, dh_file) - dh = None - - if os.path.isfile(dh_path): - if not os.access(dh_path, os.R_OK): - run(f'sudo chmod 644 {dh_path}') - - with open(dh_path, 'r') as f: - dh_data = f.read() - dh = load_dh_parameters(dh_data, wrap_tags=False) - - if dh: - dh_pem = encode_dh_parameters(dh) - config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem)) - config.set(x509_base + ['dh-params'], value=pki_name) - else: - print(f'Failed to migrate DH parameters on openvpn interface {interface}') - - config.delete(x509_base + ['dh-file']) - -# Wireguard -base = ['interfaces', 'wireguard'] - -if config.exists(base): - for interface in config.list_nodes(base): - private_key_path = base + [interface, 'private-key'] - - key_file = 'default' - if config.exists(private_key_path): - key_file = config.return_value(private_key_path) - - full_key_path = f'/config/auth/wireguard/{key_file}/private.key' + if config.exists(x509_base + ['key-file']): + key_file = config.return_value(x509_base + ['key-file']) + key_path = os.path.join(AUTH_DIR, key_file) + key = None + + if os.path.isfile(key_path): + if not os.access(key_path, os.R_OK): + run(f'sudo chmod 644 {key_path}') - if not os.path.exists(full_key_path): - print(f'Could not find wireguard private key for migration on interface "{interface}"') - continue - - with open(full_key_path, 'r') as f: - key_data = f.read().strip() - config.set(private_key_path, value=key_data) - - for peer in config.list_nodes(base + [interface, 'peer']): - config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key') + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) -# Ethernet EAPoL -base = ['interfaces', 'ethernet'] - -if config.exists(base): - for interface in config.list_nodes(base): - if not config.exists(base + [interface, 'eapol']): - continue + if key: + key_pem = encode_private_key(key, passphrase=None) + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + else: + print(f'Failed to migrate private key on eapol config for interface {interface}') - x509_base = base + [interface, 'eapol'] - pki_name = f'eapol_{interface}' - - if config.exists(x509_base + ['ca-cert-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) - - cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=pki_name) - else: - print(f'Failed to migrate CA certificate on eapol config for interface {interface}') - - config.delete(x509_base + ['ca-cert-file']) - - if config.exists(x509_base + ['cert-file']): - if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) - - cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) - else: - print(f'Failed to migrate certificate on eapol config for interface {interface}') - - config.delete(x509_base + ['cert-file']) - - if config.exists(x509_base + ['key-file']): - key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - if key: - key_pem = encode_private_key(key, passphrase=None) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) - else: - print(f'Failed to migrate private key on eapol config for interface {interface}') - - config.delete(x509_base + ['key-file']) - -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)) - sys.exit(1) + config.delete(x509_base + ['key-file']) diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27 index 429ab650f..3f58de02c 100755..100644 --- a/src/migration-scripts/interfaces/26-to-27 +++ b/src/migration-scripts/interfaces/26-to-27 @@ -1,52 +1,35 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4384: pppoe: replace default-route CLI option with common CLI nodes already # present for DHCP -from sys import argv 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 = ['interfaces', 'pppoe'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) - -for ifname in config.list_nodes(base): - tmp_config = base + [ifname, 'default-route'] - if config.exists(tmp_config): - # Retrieve current config value - value = config.return_value(tmp_config) - # Delete old Config node - config.delete(tmp_config) - if value == 'none': - config.set(base + [ifname, 'no-default-route']) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + base = ['interfaces', 'pppoe'] + + if not config.exists(base): + return + + for ifname in config.list_nodes(base): + tmp_config = base + [ifname, 'default-route'] + if config.exists(tmp_config): + # Retrieve current config value + value = config.return_value(tmp_config) + # Delete old Config node + config.delete(tmp_config) + if value == 'none': + config.set(base + [ifname, 'no-default-route']) diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28 index 9f5e93b5f..eb9363e39 100755..100644 --- a/src/migration-scripts/interfaces/27-to-28 +++ b/src/migration-scripts/interfaces/27-to-28 @@ -1,48 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4995: pppoe, wwan, sstpc-client rename "authentication user" CLI node # to "authentication username" -from sys import argv - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -for type in ['pppoe', 'sstpc-client', 'wwam']: - base = ['interfaces', type] - if not config.exists(base): - continue - for interface in config.list_nodes(base): - auth_base = base + [interface, 'authentication', 'user'] - if config.exists(auth_base): - config.rename(auth_base, 'username') - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + for type in ['pppoe', 'sstpc-client', 'wwam']: + base = ['interfaces', type] + if not config.exists(base): + continue + for interface in config.list_nodes(base): + auth_base = base + [interface, 'authentication', 'user'] + if config.exists(auth_base): + config.rename(auth_base, 'username') diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29 index 0437977dc..886d49e2c 100755..100644 --- a/src/migration-scripts/interfaces/28-to-29 +++ b/src/migration-scripts/interfaces/28-to-29 @@ -1,52 +1,35 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5034: tunnel: rename "multicast enable" CLI node to "enable-multicast" # valueless node. -from sys import argv 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 = ['interfaces', 'tunnel'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) - -for ifname in config.list_nodes(base): - multicast_base = base + [ifname, 'multicast'] - if config.exists(multicast_base): - tmp = config.return_value(multicast_base) - print(tmp) - # Delete old Config node - config.delete(multicast_base) - if tmp == 'enable': - config.set(base + [ifname, 'enable-multicast']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + for ifname in config.list_nodes(base): + multicast_base = base + [ifname, 'multicast'] + if config.exists(multicast_base): + tmp = config.return_value(multicast_base) + print(tmp) + # Delete old Config node + config.delete(multicast_base) + if tmp == 'enable': + config.set(base + [ifname, 'enable-multicast']) diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30 index 80aad1d44..7b32d871e 100755..100644 --- a/src/migration-scripts/interfaces/29-to-30 +++ b/src/migration-scripts/interfaces/29-to-30 @@ -1,47 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5286: remove XDP support in favour of VPP -from sys import argv 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() - supports_xdp = ['bonding', 'ethernet'] -config = ConfigTree(config_file) - -for if_type in supports_xdp: - base = ['interfaces', if_type] - if not config.exists(base): - continue - for interface in config.list_nodes(base): - if_base = base + [interface] - if config.exists(if_base + ['xdp']): - config.delete(if_base + ['xdp']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + for if_type in supports_xdp: + base = ['interfaces', if_type] + if not config.exists(base): + continue + for interface in config.list_nodes(base): + if_base = base + [interface] + if config.exists(if_base + ['xdp']): + config.delete(if_base + ['xdp']) diff --git a/src/migration-scripts/interfaces/3-to-4 b/src/migration-scripts/interfaces/3-to-4 index c7fd7d01d..4e56200e1 100755..100644 --- a/src/migration-scripts/interfaces/3-to-4 +++ b/src/migration-scripts/interfaces/3-to-4 @@ -1,27 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Change syntax of wireless interfaces # Migrate boolean nodes to valueless -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['interfaces', 'wireless'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + for wifi in config.list_nodes(base): # as converting a node to bool is always the same, we can script it to_bool_nodes = ['capabilities ht 40MHz-incapable', @@ -88,10 +91,3 @@ else: # delete old radius-server nodes config.delete(base + [wifi, 'security', 'wpa', 'radius-server']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/30-to-31 b/src/migration-scripts/interfaces/30-to-31 index 894106ef4..7e509dd86 100755..100644 --- a/src/migration-scripts/interfaces/30-to-31 +++ b/src/migration-scripts/interfaces/30-to-31 @@ -1,71 +1,56 @@ #!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # -# Deletes Wireguard peers if they have the same public key as the router has. +# 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/>. + +# T5254: Fixed changing ethernet when it is a bond member import json -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.ifconfig import EthernetIf from vyos.ifconfig import BondIf from vyos.utils.dict import dict_to_paths_values -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['interfaces', 'bonding'] -file_name = argv[1] -with open(file_name, 'r') as f: - config_file = f.read() - base = ['interfaces', 'bonding'] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) -for bond in config.list_nodes(base): - member_base = base + [bond, 'member', 'interface'] - if config.exists(member_base): - for interface in config.return_values(member_base): - if_base = ['interfaces', 'ethernet', interface] - if config.exists(if_base): - config_ethernet = json.loads(config.get_subtree(if_base).to_json()) - eth_dict_paths = dict_to_paths_values(config_ethernet) - for option_path, option_value in eth_dict_paths.items(): - # If option is allowed for changing then continue - converted_path = option_path.replace('-','_') - if converted_path in EthernetIf.get_bond_member_allowed_options(): - continue - # if option is inherited from bond then continue - if converted_path in BondIf.get_inherit_bond_options(): - continue - option_path_list = option_path.split('.') - config.delete(if_base + option_path_list) - del option_path_list[-1] - # delete empty node from config - while len(option_path_list) > 0: - if config.list_nodes(if_base + option_path_list): - break + for bond in config.list_nodes(base): + member_base = base + [bond, 'member', 'interface'] + if config.exists(member_base): + for interface in config.return_values(member_base): + if_base = ['interfaces', 'ethernet', interface] + if config.exists(if_base): + config_ethernet = json.loads(config.get_subtree(if_base).to_json()) + eth_dict_paths = dict_to_paths_values(config_ethernet) + for option_path, option_value in eth_dict_paths.items(): + # If option is allowed for changing then continue + converted_path = option_path.replace('-','_') + if converted_path in EthernetIf.get_bond_member_allowed_options(): + continue + # if option is inherited from bond then continue + if converted_path in BondIf.get_inherit_bond_options(): + continue + option_path_list = option_path.split('.') config.delete(if_base + option_path_list) del option_path_list[-1] - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # delete empty node from config + while len(option_path_list) > 0: + if config.list_nodes(if_base + option_path_list): + break + config.delete(if_base + option_path_list) + del option_path_list[-1] diff --git a/src/migration-scripts/interfaces/31-to-32 b/src/migration-scripts/interfaces/31-to-32 index 0fc27b70a..24077ed24 100755..100644 --- a/src/migration-scripts/interfaces/31-to-32 +++ b/src/migration-scripts/interfaces/31-to-32 @@ -1,55 +1,37 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. + # T5671: change port to IANA assigned default port # T5759: change default MTU 1450 -> 1500 -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 = ['interfaces', 'vxlan'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) - -for vxlan in config.list_nodes(base): - if config.exists(base + [vxlan, 'external']): - config.delete(base + [vxlan, 'external']) - config.set(base + [vxlan, 'parameters', 'external']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - if not config.exists(base + [vxlan, 'port']): - config.set(base + [vxlan, 'port'], value='8472') + for vxlan in config.list_nodes(base): + if config.exists(base + [vxlan, 'external']): + config.delete(base + [vxlan, 'external']) + config.set(base + [vxlan, 'parameters', 'external']) - if not config.exists(base + [vxlan, 'mtu']): - config.set(base + [vxlan, 'mtu'], value='1450') + if not config.exists(base + [vxlan, 'port']): + config.set(base + [vxlan, 'port'], value='8472') -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if not config.exists(base + [vxlan, 'mtu']): + config.set(base + [vxlan, 'mtu'], value='1450') diff --git a/src/migration-scripts/interfaces/32-to-33 b/src/migration-scripts/interfaces/32-to-33 index caf588474..c7b1c5b36 100755..100644 --- a/src/migration-scripts/interfaces/32-to-33 +++ b/src/migration-scripts/interfaces/32-to-33 @@ -16,42 +16,25 @@ # # T6318: WiFi country-code should be set system-wide instead of per-device -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 = ['interfaces', 'wireless'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) - -installed = False -for interface in config.list_nodes(base): - cc_path = base + [interface, 'country-code'] - if config.exists(cc_path): - tmp = config.return_value(cc_path) - config.delete(cc_path) - - # There can be only ONE wireless country-code per device, everything - # else makes no sense as a WIFI router can not operate in two - # different countries - if not installed: - config.set(['system', 'wireless', 'country-code'], value=tmp) - installed = True - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + installed = False + for interface in config.list_nodes(base): + cc_path = base + [interface, 'country-code'] + if config.exists(cc_path): + tmp = config.return_value(cc_path) + config.delete(cc_path) + + # There can be only ONE wireless country-code per device, everything + # else makes no sense as a WIFI router can not operate in two + # different countries + if not installed: + config.set(['system', 'wireless', 'country-code'], value=tmp) + installed = True diff --git a/src/migration-scripts/interfaces/4-to-5 b/src/migration-scripts/interfaces/4-to-5 index 68d81e846..93fa7c393 100755..100644 --- a/src/migration-scripts/interfaces/4-to-5 +++ b/src/migration-scripts/interfaces/4-to-5 @@ -1,9 +1,21 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # De-nest PPPoE interfaces # Migrate boolean nodes to valueless -import sys from vyos.configtree import ConfigTree def migrate_dialer(config, tree, intf): @@ -55,18 +67,7 @@ def migrate_dialer(config, tree, intf): if config.exists(ipv6_ra): config.delete(ipv6_ra) - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = sys.argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: pppoe_links = ['bonding', 'ethernet'] for link_type in pppoe_links: @@ -103,10 +104,3 @@ if __name__ == '__main__': # Add interface description that this is required for PPPoE if not config.exists(vlan_if + ['description']): config.set(vlan_if + ['description'], value='PPPoE link interface') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6 index 9d9a49c2d..44c32ba63 100755..100644 --- a/src/migration-scripts/interfaces/5-to-6 +++ b/src/migration-scripts/interfaces/5-to-6 @@ -1,23 +1,21 @@ -#!/usr/bin/env python3 +# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrate IPv6 router advertisments from a nested interface configuration to # a denested "service router-advert" -import sys from vyos.configtree import ConfigTree def copy_rtradv(c, old_base, interface): @@ -97,17 +95,7 @@ def copy_rtradv(c, old_base, interface): if tmp == '0': c.delete(new_base + ['link-mtu']) -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = sys.argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: # list all individual interface types like dummy, ethernet and so on for if_type in config.list_nodes(['interfaces']): base_if_type = ['interfaces', if_type] @@ -124,10 +112,3 @@ if __name__ == '__main__': old_base = vif_base + [vif, 'ipv6', 'router-advert'] vlan_name = f'{intf}.{vif}' copy_rtradv(config, old_base, vlan_name) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/6-to-7 b/src/migration-scripts/interfaces/6-to-7 index 49b853d90..e60121eec 100755..100644 --- a/src/migration-scripts/interfaces/6-to-7 +++ b/src/migration-scripts/interfaces/6-to-7 @@ -1,39 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Remove network provider name from CLI and rather use provider APN from CLI -import sys from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = sys.argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'wirelessmodem'] if not config.exists(base): # Nothing to do - sys.exit(0) + return # list all individual wwan/wireless modem interfaces for i in config.list_nodes(base): @@ -54,10 +43,3 @@ if __name__ == '__main__': # uniform CLI experience if config.exists(iface + ['no-dns']): config.rename(iface + ['no-dns'], 'no-peer-dns') - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/interfaces/7-to-8 b/src/migration-scripts/interfaces/7-to-8 index 9343a48a8..43ae320ab 100755..100644 --- a/src/migration-scripts/interfaces/7-to-8 +++ b/src/migration-scripts/interfaces/7-to-8 @@ -1,25 +1,23 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Split WireGuard endpoint into address / port nodes to make use of common # validators import os -from sys import exit, argv from vyos.configtree import ConfigTree from vyos.utils.permission import chown from vyos.utils.permission import chmod_750 @@ -36,23 +34,14 @@ def migrate_default_keys(): os.rename(f'{kdir}/private.key', f'{location}/private.key') os.rename(f'{kdir}/public.key', f'{location}/public.key') -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: base = ['interfaces', 'wireguard'] migrate_default_keys() if not config.exists(base): # Nothing to do - exit(0) + return # list all individual wireguard interface isntance for i in config.list_nodes(base): @@ -68,10 +57,3 @@ if __name__ == '__main__': # setup new nodes config.set(base_peer + ['address'], value=address) config.set(base_peer + ['port'], value=port) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/8-to-9 b/src/migration-scripts/interfaces/8-to-9 index 960962be7..bae1b34fa 100755..100644 --- a/src/migration-scripts/interfaces/8-to-9 +++ b/src/migration-scripts/interfaces/8-to-9 @@ -1,37 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Rename link nodes to source-interface for the following interface types: # - vxlan # - pseudo-ethernet -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: for if_type in ['vxlan', 'pseudo-ethernet']: base = ['interfaces', if_type] if not config.exists(base): @@ -43,10 +31,3 @@ if __name__ == '__main__': iface = base + [i] if config.exists(iface + ['link']): config.rename(iface + ['link'], 'source-interface') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/interfaces/9-to-10 b/src/migration-scripts/interfaces/9-to-10 index e9b8cb784..cdfd7d432 100755..100644 --- a/src/migration-scripts/interfaces/9-to-10 +++ b/src/migration-scripts/interfaces/9-to-10 @@ -1,38 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - rename CLI node 'dhcpv6-options delgate' to 'dhcpv6-options prefix-delegation # interface' # - rename CLI node 'interface-id' for prefix-delegation to 'address' as it # represents the local interface IPv6 address assigned by DHCPv6-PD -from sys import exit, argv from vyos.configtree import ConfigTree -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: for intf_type in config.list_nodes(['interfaces']): for intf in config.list_nodes(['interfaces', intf_type]): # cache current config tree @@ -55,10 +43,3 @@ if __name__ == '__main__': # delete old noe config.delete(base_path) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/ipoe-server/1-to-2 b/src/migration-scripts/ipoe-server/1-to-2 index 6a7111541..034eacb10 100755..100644 --- a/src/migration-scripts/ipoe-server/1-to-2 +++ b/src/migration-scripts/ipoe-server/1-to-2 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T4703: merge vlan-id and vlan-range to vlan CLI node # L2|L3 -> l2|l3 @@ -28,87 +27,68 @@ # 1. The first pool that contains next-poll. # 2. Else, the first pool in the list -from sys import argv -from sys import exit from vyos.configtree import ConfigTree - -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'ipoe-server'] -if not config.exists(base): - exit(0) - -if config.exists(base + ['authentication', 'interface']): - for interface in config.list_nodes(base + ['authentication', 'interface']): - config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac') - - mac_base = base + ['authentication', 'interface', interface, 'mac'] - for mac in config.list_nodes(mac_base): - vlan_config = mac_base + [mac, 'vlan-id'] - if config.exists(vlan_config): - config.rename(vlan_config, 'vlan') - -for interface in config.list_nodes(base + ['interface']): - base_path = base + ['interface', interface] - for vlan in ['vlan-id', 'vlan-range']: - if config.exists(base_path + [vlan]): - for tmp in config.return_values(base_path + [vlan]): - config.set(base_path + ['vlan'], value=tmp, replace=False) - config.delete(base_path + [vlan]) - - if config.exists(base_path + ['network-mode']): - tmp = config.return_value(base_path + ['network-mode']) - config.delete(base_path + ['network-mode']) - # Change L2|L3 to lower case l2|l3 - config.set(base_path + ['mode'], value=tmp.lower()) - -pool_base = base + ['client-ip-pool'] -if config.exists(pool_base): - default_pool = '' - gateway = '' - - #named pool migration - namedpools_base = pool_base + ['name'] - - for pool_name in config.list_nodes(namedpools_base): - pool_path = namedpools_base + [pool_name] - if config.exists(pool_path + ['subnet']): - subnet = config.return_value(pool_path + ['subnet']) - config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False) - # Get netmask from subnet - mask = subnet.split("/")[1] - if config.exists(pool_path + ['next-pool']): - next_pool = config.return_value(pool_path + ['next-pool']) - config.set(pool_base + [pool_name, 'next-pool'], value=next_pool) - if not default_pool: - default_pool = pool_name - if config.exists(pool_path + ['gateway-address']) and mask: - gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}' - config.set(base + ['gateway-address'], value=gateway, replace=False) - - if not default_pool and config.list_nodes(namedpools_base): - default_pool = config.list_nodes(namedpools_base)[0] - - config.delete(namedpools_base) - - if default_pool: - config.set(base + ['default-pool'], value=default_pool) - # format as tag node - config.set_tag(pool_base) - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if config.exists(base + ['authentication', 'interface']): + for interface in config.list_nodes(base + ['authentication', 'interface']): + config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac') + + mac_base = base + ['authentication', 'interface', interface, 'mac'] + for mac in config.list_nodes(mac_base): + vlan_config = mac_base + [mac, 'vlan-id'] + if config.exists(vlan_config): + config.rename(vlan_config, 'vlan') + + for interface in config.list_nodes(base + ['interface']): + base_path = base + ['interface', interface] + for vlan in ['vlan-id', 'vlan-range']: + if config.exists(base_path + [vlan]): + for tmp in config.return_values(base_path + [vlan]): + config.set(base_path + ['vlan'], value=tmp, replace=False) + config.delete(base_path + [vlan]) + + if config.exists(base_path + ['network-mode']): + tmp = config.return_value(base_path + ['network-mode']) + config.delete(base_path + ['network-mode']) + # Change L2|L3 to lower case l2|l3 + config.set(base_path + ['mode'], value=tmp.lower()) + + pool_base = base + ['client-ip-pool'] + if config.exists(pool_base): + default_pool = '' + gateway = '' + + #named pool migration + namedpools_base = pool_base + ['name'] + + for pool_name in config.list_nodes(namedpools_base): + pool_path = namedpools_base + [pool_name] + if config.exists(pool_path + ['subnet']): + subnet = config.return_value(pool_path + ['subnet']) + config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False) + # Get netmask from subnet + mask = subnet.split("/")[1] + if config.exists(pool_path + ['next-pool']): + next_pool = config.return_value(pool_path + ['next-pool']) + config.set(pool_base + [pool_name, 'next-pool'], value=next_pool) + if not default_pool: + default_pool = pool_name + if config.exists(pool_path + ['gateway-address']) and mask: + gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}' + config.set(base + ['gateway-address'], value=gateway, replace=False) + + if not default_pool and config.list_nodes(namedpools_base): + default_pool = config.list_nodes(namedpools_base)[0] + + config.delete(namedpools_base) + + if default_pool: + config.set(base + ['default-pool'], value=default_pool) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/ipoe-server/2-to-3 b/src/migration-scripts/ipoe-server/2-to-3 index 0909315a8..dcd15e595 100755..100644 --- a/src/migration-scripts/ipoe-server/2-to-3 +++ b/src/migration-scripts/ipoe-server/2-to-3 @@ -1,58 +1,40 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrating to named ipv6 pools -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['service', 'ipoe-server'] +pool_base = base + ['client-ipv6-pool'] -file_name = argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -with open(file_name, 'r') as f: - config_file = f.read() + if not config.exists(pool_base): + return -config = ConfigTree(config_file) -base = ['service', 'ipoe-server'] -pool_base = base + ['client-ipv6-pool'] -if not config.exists(base): - exit(0) - -if not config.exists(pool_base): - exit(0) - -ipv6_pool_name = 'ipv6-pool' -config.copy(pool_base, pool_base + [ipv6_pool_name]) - -if config.exists(pool_base + ['prefix']): - config.delete(pool_base + ['prefix']) - config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) -if config.exists(pool_base + ['delegate']): - config.delete(pool_base + ['delegate']) - -# format as tag node -config.set_tag(pool_base) - -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) + ipv6_pool_name = 'ipv6-pool' + config.copy(pool_base, pool_base + [ipv6_pool_name]) + + if config.exists(pool_base + ['prefix']): + config.delete(pool_base + ['prefix']) + config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) + if config.exists(pool_base + ['delegate']): + config.delete(pool_base + ['delegate']) + + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/ipsec/10-to-11 b/src/migration-scripts/ipsec/10-to-11 index 509216267..6c4ccb553 100755..100644 --- a/src/migration-scripts/ipsec/10-to-11 +++ b/src/migration-scripts/ipsec/10-to-11 @@ -1,83 +1,63 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit +# T4916: Rewrite IPsec peer authentication and psk migration 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 = ['vpn', 'ipsec'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# PEER changes -if config.exists(base + ['site-to-site', 'peer']): - for peer in config.list_nodes(base + ['site-to-site', 'peer']): - peer_base = base + ['site-to-site', 'peer', peer] - - # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx' - # => 'ipsec authentication psk <tag> secret xxx' - if config.exists(peer_base + ['authentication', 'pre-shared-secret']): - tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret']) - config.delete(peer_base + ['authentication', 'pre-shared-secret']) - config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp) - # format as tag node to avoid loading problems - config.set_tag(base + ['authentication', 'psk']) - - # Get id's from peers for "ipsec auth psk <tag> id xxx" - if config.exists(peer_base + ['authentication', 'local-id']): - local_id = config.return_value(peer_base + ['authentication', 'local-id']) - config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False) - if config.exists(peer_base + ['authentication', 'remote-id']): - remote_id = config.return_value(peer_base + ['authentication', 'remote-id']) - config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False) - - if config.exists(peer_base + ['local-address']): - tmp = config.return_value(peer_base + ['local-address']) - config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False) - if config.exists(peer_base + ['remote-address']): - tmp = config.return_values(peer_base + ['remote-address']) - if tmp: - for remote_addr in tmp: - if remote_addr == 'any': - remote_addr = '%any' - config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False) - - # get DHCP peer interface as psk dhcp-interface - if config.exists(peer_base + ['dhcp-interface']): - tmp = config.return_value(peer_base + ['dhcp-interface']) - config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # PEER changes + if config.exists(base + ['site-to-site', 'peer']): + for peer in config.list_nodes(base + ['site-to-site', 'peer']): + peer_base = base + ['site-to-site', 'peer', peer] + + # replace: 'ipsec site-to-site peer <tag> authentication pre-shared-secret xxx' + # => 'ipsec authentication psk <tag> secret xxx' + if config.exists(peer_base + ['authentication', 'pre-shared-secret']): + tmp = config.return_value(peer_base + ['authentication', 'pre-shared-secret']) + config.delete(peer_base + ['authentication', 'pre-shared-secret']) + config.set(base + ['authentication', 'psk', peer, 'secret'], value=tmp) + # format as tag node to avoid loading problems + config.set_tag(base + ['authentication', 'psk']) + + # Get id's from peers for "ipsec auth psk <tag> id xxx" + if config.exists(peer_base + ['authentication', 'local-id']): + local_id = config.return_value(peer_base + ['authentication', 'local-id']) + config.set(base + ['authentication', 'psk', peer, 'id'], value=local_id, replace=False) + if config.exists(peer_base + ['authentication', 'remote-id']): + remote_id = config.return_value(peer_base + ['authentication', 'remote-id']) + config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_id, replace=False) + + if config.exists(peer_base + ['local-address']): + tmp = config.return_value(peer_base + ['local-address']) + config.set(base + ['authentication', 'psk', peer, 'id'], value=tmp, replace=False) + if config.exists(peer_base + ['remote-address']): + tmp = config.return_values(peer_base + ['remote-address']) + if tmp: + for remote_addr in tmp: + if remote_addr == 'any': + remote_addr = '%any' + config.set(base + ['authentication', 'psk', peer, 'id'], value=remote_addr, replace=False) + + # get DHCP peer interface as psk dhcp-interface + if config.exists(peer_base + ['dhcp-interface']): + tmp = config.return_value(peer_base + ['dhcp-interface']) + config.set(base + ['authentication', 'psk', peer, 'dhcp-interface'], value=tmp) diff --git a/src/migration-scripts/ipsec/11-to-12 b/src/migration-scripts/ipsec/11-to-12 index 4833d0876..fc65f1825 100755..100644 --- a/src/migration-scripts/ipsec/11-to-12 +++ b/src/migration-scripts/ipsec/11-to-12 @@ -1,51 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Remove legacy ipsec.conf and ipsec.secrets - Not supported with swanctl -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 = ['vpn', 'ipsec'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -if config.exists(base + ['include-ipsec-conf']): - config.delete(base + ['include-ipsec-conf']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -if config.exists(base + ['include-ipsec-secrets']): - config.delete(base + ['include-ipsec-secrets']) + if config.exists(base + ['include-ipsec-conf']): + config.delete(base + ['include-ipsec-conf']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if config.exists(base + ['include-ipsec-secrets']): + config.delete(base + ['include-ipsec-secrets']) diff --git a/src/migration-scripts/ipsec/12-to-13 b/src/migration-scripts/ipsec/12-to-13 index d90c70314..ffe766eb2 100755..100644 --- a/src/migration-scripts/ipsec/12-to-13 +++ b/src/migration-scripts/ipsec/12-to-13 @@ -1,43 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Changed value of dead-peer-detection.action from hold to trap # Changed value of close-action from hold to trap and from restart to start -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 = ['vpn', 'ipsec', 'ike-group'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + for ike_group in config.list_nodes(base): base_dpd_action = base + [ike_group, 'dead-peer-detection', 'action'] base_close_action = base + [ike_group, 'close-action'] @@ -48,10 +35,3 @@ else: config.set(base_close_action, 'trap', replace=True) if config.return_value(base_close_action) == 'restart': config.set(base_close_action, 'start', replace=True) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) diff --git a/src/migration-scripts/ipsec/4-to-5 b/src/migration-scripts/ipsec/4-to-5 index 772d05787..a88a543d3 100755..100644 --- a/src/migration-scripts/ipsec/4-to-5 +++ b/src/migration-scripts/ipsec/4-to-5 @@ -1,47 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2019 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # log-modes have changed, keyword all to any -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -ctree = ConfigTree(config_file) - -if not ctree.exists(['vpn', 'ipsec', 'logging','log-modes']): - # Nothing to do - sys.exit(0) -else: - lmodes = ctree.return_values(['vpn', 'ipsec', 'logging','log-modes']) - for mode in lmodes: - if mode == 'all': - ctree.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True) +def migrate(config: ConfigTree) -> None: + if not config.exists(['vpn', 'ipsec', 'logging','log-modes']): + # Nothing to do + return - try: - open(file_name,'w').write(ctree.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - sys.exit(1) + lmodes = config.return_values(['vpn', 'ipsec', 'logging','log-modes']) + for mode in lmodes: + if mode == 'all': + config.set(['vpn', 'ipsec', 'logging','log-modes'], value='any', replace=True) diff --git a/src/migration-scripts/ipsec/5-to-6 b/src/migration-scripts/ipsec/5-to-6 index 7d7c777c6..373428d61 100755..100644 --- a/src/migration-scripts/ipsec/5-to-6 +++ b/src/migration-scripts/ipsec/5-to-6 @@ -1,93 +1,73 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Remove deprecated strongSwan options from VyOS CLI # - vpn ipsec nat-traversal enable # - vpn ipsec nat-networks allowed-network -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 = ['vpn', 'ipsec'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# Delete CLI nodes whose config options got removed by strongSwan -for cli_node in ['nat-traversal', 'nat-networks']: - if config.exists(base + [cli_node]): - config.delete(base + [cli_node]) - -# Remove options only valid in Openswan -if config.exists(base + ['site-to-site', 'peer']): - for peer in config.list_nodes(base + ['site-to-site', 'peer']): - if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']): - continue - for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']): - # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6 - nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks'] - if config.exists(nat_networks): - config.delete(nat_networks) - - # allow-nat-networks - Also sets a value only valid in Openswan - public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks'] - if config.exists(public_networks): - config.delete(public_networks) - -# Rename "logging log-level" and "logging log-modes" to something more human friendly -log = base + ['logging'] -if config.exists(log): - config.rename(log, 'log') - log = base + ['log'] - -log_level = log + ['log-level'] -if config.exists(log_level): - config.rename(log_level, 'level') - -log_mode = log + ['log-modes'] -if config.exists(log_mode): - config.rename(log_mode, 'subsystem') - -# Rename "ipsec-interfaces interface" to "interface" -base_interfaces = base + ['ipsec-interfaces', 'interface'] -if config.exists(base_interfaces): - config.copy(base_interfaces, base + ['interface']) - config.delete(base + ['ipsec-interfaces']) - -# Remove deprecated "auto-update" option -tmp = base + ['auto-update'] -if config.exists(tmp): - config.delete(tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # Delete CLI nodes whose config options got removed by strongSwan + for cli_node in ['nat-traversal', 'nat-networks']: + if config.exists(base + [cli_node]): + config.delete(base + [cli_node]) + + # Remove options only valid in Openswan + if config.exists(base + ['site-to-site', 'peer']): + for peer in config.list_nodes(base + ['site-to-site', 'peer']): + if not config.exists(base + ['site-to-site', 'peer', peer, 'tunnel']): + continue + for tunnel in config.list_nodes(base + ['site-to-site', 'peer', peer, 'tunnel']): + # allow-public-networks - Sets a value in ipsec.conf that was only ever valid in Openswan on kernel 2.6 + nat_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-nat-networks'] + if config.exists(nat_networks): + config.delete(nat_networks) + + # allow-nat-networks - Also sets a value only valid in Openswan + public_networks = base + ['site-to-site', 'peer', peer, 'tunnel', tunnel, 'allow-public-networks'] + if config.exists(public_networks): + config.delete(public_networks) + + # Rename "logging log-level" and "logging log-modes" to something more human friendly + log = base + ['logging'] + if config.exists(log): + config.rename(log, 'log') + log = base + ['log'] + + log_level = log + ['log-level'] + if config.exists(log_level): + config.rename(log_level, 'level') + + log_mode = log + ['log-modes'] + if config.exists(log_mode): + config.rename(log_mode, 'subsystem') + + # Rename "ipsec-interfaces interface" to "interface" + base_interfaces = base + ['ipsec-interfaces', 'interface'] + if config.exists(base_interfaces): + config.copy(base_interfaces, base + ['interface']) + config.delete(base + ['ipsec-interfaces']) + + # Remove deprecated "auto-update" option + tmp = base + ['auto-update'] + if config.exists(tmp): + config.delete(tmp) diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7 index f8b6de560..5679477c0 100755..100644 --- a/src/migration-scripts/ipsec/6-to-7 +++ b/src/migration-scripts/ipsec/6-to-7 @@ -1,26 +1,22 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrate /config/auth certificates and keys into PKI configuration import os -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree from vyos.pki import load_certificate from vyos.pki import load_crl @@ -29,27 +25,27 @@ from vyos.pki import encode_certificate from vyos.pki import encode_private_key from vyos.utils.process import run -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() - pki_base = ['pki'] ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] -config = ConfigTree(config_file) -changes_made = False - AUTH_DIR = '/config/auth' def wrapped_pem_to_config_value(pem): return "".join(pem.strip().split("\n")[1:-1]) -if config.exists(ipsec_site_base): +def migrate(config: ConfigTree) -> None: + if not config.exists(ipsec_site_base): + return + + migration_needed = False + for peer in config.list_nodes(ipsec_site_base): + if config.exists(ipsec_site_base + [peer, 'authentication', 'x509']): + migration_needed = True + break + + if not migration_needed: + return + config.set(pki_base + ['ca']) config.set_tag(pki_base + ['ca']) @@ -60,8 +56,6 @@ if config.exists(ipsec_site_base): if not config.exists(ipsec_site_base + [peer, 'authentication', 'x509']): continue - changes_made = True - peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509'] pki_name = 'peer_' + peer.replace(".", "-").replace("@", "") @@ -159,11 +153,3 @@ if config.exists(ipsec_site_base): print(f'Failed to migrate private key on peer "{peer}"') config.delete(peer_x509_base + ['key']) - -if changes_made: - 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)) - sys.exit(1) diff --git a/src/migration-scripts/ipsec/7-to-8 b/src/migration-scripts/ipsec/7-to-8 index 9acc737d5..481f00d29 100755..100644 --- a/src/migration-scripts/ipsec/7-to-8 +++ b/src/migration-scripts/ipsec/7-to-8 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrate rsa keys into PKI configuration @@ -22,29 +21,15 @@ import struct from cryptography.hazmat.primitives.asymmetric import rsa -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree from vyos.pki import load_private_key from vyos.pki import encode_public_key from vyos.pki import encode_private_key -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() - pki_base = ['pki'] ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] rsa_keys_base = ['vpn', 'rsa-keys'] -config = ConfigTree(config_file) - LOCAL_KEY_PATHS = ['/config/auth/', '/config/ipsec.d/rsa-keys/'] def migrate_from_vyatta_key(data): @@ -60,65 +45,59 @@ def wrapped_pem_to_config_value(pem): local_key_name = 'localhost' -if config.exists(rsa_keys_base): - if not config.exists(pki_base + ['key-pair']): - config.set(pki_base + ['key-pair']) - config.set_tag(pki_base + ['key-pair']) - - if config.exists(rsa_keys_base + ['local-key', 'file']): - local_file = config.return_value(rsa_keys_base + ['local-key', 'file']) - local_path = None - local_key = None - - for path in LOCAL_KEY_PATHS: - full_path = os.path.join(path, local_file) - if os.path.exists(full_path): - local_path = full_path - break - - if local_path: - with open(local_path, 'r') as f: - local_key_data = f.read() - local_key = load_private_key(local_key_data, wrap_tags=False) - - if local_key: - local_key_pem = encode_private_key(local_key) - config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem)) - else: - print('Failed to migrate local RSA key') - - if config.exists(rsa_keys_base + ['rsa-key-name']): - for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']): - if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']): - continue +def migrate(config: ConfigTree) -> None: + if config.exists(rsa_keys_base): + if not config.exists(pki_base + ['key-pair']): + config.set(pki_base + ['key-pair']) + config.set_tag(pki_base + ['key-pair']) + + if config.exists(rsa_keys_base + ['local-key', 'file']): + local_file = config.return_value(rsa_keys_base + ['local-key', 'file']) + local_path = None + local_key = None + + for path in LOCAL_KEY_PATHS: + full_path = os.path.join(path, local_file) + if os.path.exists(full_path): + local_path = full_path + break + + if local_path: + with open(local_path, 'r') as f: + local_key_data = f.read() + local_key = load_private_key(local_key_data, wrap_tags=False) + + if local_key: + local_key_pem = encode_private_key(local_key) + config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem)) + else: + print('Failed to migrate local RSA key') - vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']) - public_key = migrate_from_vyatta_key(vyatta_key) + if config.exists(rsa_keys_base + ['rsa-key-name']): + for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']): + if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']): + continue - if public_key: - public_key_pem = encode_public_key(public_key) - config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem)) - else: - print(f'Failed to migrate rsa-key "{rsa_name}"') + vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']) + public_key = migrate_from_vyatta_key(vyatta_key) - config.delete(rsa_keys_base) + if public_key: + public_key_pem = encode_public_key(public_key) + config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem)) + else: + print(f'Failed to migrate rsa-key "{rsa_name}"') -if config.exists(ipsec_site_base): - for peer in config.list_nodes(ipsec_site_base): - mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode']) + config.delete(rsa_keys_base) - if mode != 'rsa': - continue + if config.exists(ipsec_site_base): + for peer in config.list_nodes(ipsec_site_base): + mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode']) - config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name) + if mode != 'rsa': + continue - remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name']) - config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name) - config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name']) + config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name) -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)) - sys.exit(1) + remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name']) + config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name) + config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name']) diff --git a/src/migration-scripts/ipsec/8-to-9 b/src/migration-scripts/ipsec/8-to-9 index c08411f83..7f325139f 100755..100644 --- a/src/migration-scripts/ipsec/8-to-9 +++ b/src/migration-scripts/ipsec/8-to-9 @@ -1,48 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit +# T4288 : close-action is missing in swanctl.conf 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 = ['vpn', 'ipsec', 'ike-group'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + for ike_group in config.list_nodes(base): base_closeaction = base + [ike_group, 'close-action'] if config.exists(base_closeaction) and config.return_value(base_closeaction) == 'clear': config.set(base_closeaction, 'none', replace=True) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) diff --git a/src/migration-scripts/ipsec/9-to-10 b/src/migration-scripts/ipsec/9-to-10 index bc10e1997..321a75973 100755..100644 --- a/src/migration-scripts/ipsec/9-to-10 +++ b/src/migration-scripts/ipsec/9-to-10 @@ -1,131 +1,114 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -import re +# T4118: Change vpn ipsec syntax for IKE ESP and peer +# T4879: IPsec migration script remote-id for peer name eq address -from sys import argv -from sys import exit +import re 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 = ['vpn', 'ipsec'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# IKE changes, T4118: -if config.exists(base + ['ike-group']): - for ike_group in config.list_nodes(base + ['ike-group']): - # replace 'ipsec ike-group <tag> mobike disable' - # => 'ipsec ike-group <tag> disable-mobike' - mobike = base + ['ike-group', ike_group, 'mobike'] - if config.exists(mobike): - if config.return_value(mobike) == 'disable': - config.set(base + ['ike-group', ike_group, 'disable-mobike']) - config.delete(mobike) - - # replace 'ipsec ike-group <tag> ikev2-reauth yes' - # => 'ipsec ike-group <tag> ikev2-reauth' - reauth = base + ['ike-group', ike_group, 'ikev2-reauth'] - if config.exists(reauth): - if config.return_value(reauth) == 'yes': - config.delete(reauth) - config.set(reauth) - else: - config.delete(reauth) - -# ESP changes -# replace 'ipsec esp-group <tag> compression enable' -# => 'ipsec esp-group <tag> compression' -if config.exists(base + ['esp-group']): - for esp_group in config.list_nodes(base + ['esp-group']): - compression = base + ['esp-group', esp_group, 'compression'] - if config.exists(compression): - if config.return_value(compression) == 'enable': - config.delete(compression) - config.set(compression) - else: - config.delete(compression) - -# PEER changes -if config.exists(base + ['site-to-site', 'peer']): - for peer in config.list_nodes(base + ['site-to-site', 'peer']): - peer_base = base + ['site-to-site', 'peer', peer] - - # replace: 'peer <tag> id x' - # => 'peer <tag> local-id x' - if config.exists(peer_base + ['authentication', 'id']): - config.rename(peer_base + ['authentication', 'id'], 'local-id') - - # For the peer '@foo' set remote-id 'foo' if remote-id is not defined - # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined - if not config.exists(peer_base + ['authentication', 'remote-id']): - tmp = peer.replace('@', '') if peer.startswith('@') else peer - config.set(peer_base + ['authentication', 'remote-id'], value=tmp) - - # replace: 'peer <tag> force-encapsulation enable' - # => 'peer <tag> force-udp-encapsulation' - force_enc = peer_base + ['force-encapsulation'] - if config.exists(force_enc): - if config.return_value(force_enc) == 'enable': - config.delete(force_enc) - config.set(peer_base + ['force-udp-encapsulation']) - else: - config.delete(force_enc) - - # add option: 'peer <tag> remote-address x.x.x.x' - remote_address = peer - if peer.startswith('@'): - remote_address = 'any' - config.set(peer_base + ['remote-address'], value=remote_address) - # Peer name it is swanctl connection name and shouldn't contain dots or colons - # rename peer: - # peer 192.0.2.1 => peer peer_192-0-2-1 - # peer 2001:db8::2 => peer peer_2001-db8--2 - # peer @foo => peer peer_foo - re_peer_name = re.sub(':|\.', '-', peer) - if re_peer_name.startswith('@'): - re_peer_name = re.sub('@', '', re_peer_name) - new_peer_name = f'peer_{re_peer_name}' - - config.rename(peer_base, new_peer_name) - -# remote-access/road-warrior changes -if config.exists(base + ['remote-access', 'connection']): - for connection in config.list_nodes(base + ['remote-access', 'connection']): - ra_base = base + ['remote-access', 'connection', connection] - # replace: 'remote-access connection <tag> authentication id x' - # => 'remote-access connection <tag> authentication local-id x' - if config.exists(ra_base + ['authentication', 'id']): - config.rename(ra_base + ['authentication', 'id'], 'local-id') -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # IKE changes, T4118: + if config.exists(base + ['ike-group']): + for ike_group in config.list_nodes(base + ['ike-group']): + # replace 'ipsec ike-group <tag> mobike disable' + # => 'ipsec ike-group <tag> disable-mobike' + mobike = base + ['ike-group', ike_group, 'mobike'] + if config.exists(mobike): + if config.return_value(mobike) == 'disable': + config.set(base + ['ike-group', ike_group, 'disable-mobike']) + config.delete(mobike) + + # replace 'ipsec ike-group <tag> ikev2-reauth yes' + # => 'ipsec ike-group <tag> ikev2-reauth' + reauth = base + ['ike-group', ike_group, 'ikev2-reauth'] + if config.exists(reauth): + if config.return_value(reauth) == 'yes': + config.delete(reauth) + config.set(reauth) + else: + config.delete(reauth) + + # ESP changes + # replace 'ipsec esp-group <tag> compression enable' + # => 'ipsec esp-group <tag> compression' + if config.exists(base + ['esp-group']): + for esp_group in config.list_nodes(base + ['esp-group']): + compression = base + ['esp-group', esp_group, 'compression'] + if config.exists(compression): + if config.return_value(compression) == 'enable': + config.delete(compression) + config.set(compression) + else: + config.delete(compression) + + # PEER changes + if config.exists(base + ['site-to-site', 'peer']): + for peer in config.list_nodes(base + ['site-to-site', 'peer']): + peer_base = base + ['site-to-site', 'peer', peer] + + # replace: 'peer <tag> id x' + # => 'peer <tag> local-id x' + if config.exists(peer_base + ['authentication', 'id']): + config.rename(peer_base + ['authentication', 'id'], 'local-id') + + # For the peer '@foo' set remote-id 'foo' if remote-id is not defined + # For the peer '192.0.2.1' set remote-id '192.0.2.1' if remote-id is not defined + if not config.exists(peer_base + ['authentication', 'remote-id']): + tmp = peer.replace('@', '') if peer.startswith('@') else peer + config.set(peer_base + ['authentication', 'remote-id'], value=tmp) + + # replace: 'peer <tag> force-encapsulation enable' + # => 'peer <tag> force-udp-encapsulation' + force_enc = peer_base + ['force-encapsulation'] + if config.exists(force_enc): + if config.return_value(force_enc) == 'enable': + config.delete(force_enc) + config.set(peer_base + ['force-udp-encapsulation']) + else: + config.delete(force_enc) + + # add option: 'peer <tag> remote-address x.x.x.x' + remote_address = peer + if peer.startswith('@'): + remote_address = 'any' + config.set(peer_base + ['remote-address'], value=remote_address) + # Peer name it is swanctl connection name and shouldn't contain dots or colons + # rename peer: + # peer 192.0.2.1 => peer peer_192-0-2-1 + # peer 2001:db8::2 => peer peer_2001-db8--2 + # peer @foo => peer peer_foo + re_peer_name = re.sub(':|\.', '-', peer) + if re_peer_name.startswith('@'): + re_peer_name = re.sub('@', '', re_peer_name) + new_peer_name = f'peer_{re_peer_name}' + + config.rename(peer_base, new_peer_name) + + # remote-access/road-warrior changes + if config.exists(base + ['remote-access', 'connection']): + for connection in config.list_nodes(base + ['remote-access', 'connection']): + ra_base = base + ['remote-access', 'connection', connection] + # replace: 'remote-access connection <tag> authentication id x' + # => 'remote-access connection <tag> authentication local-id x' + if config.exists(ra_base + ['authentication', 'id']): + config.rename(ra_base + ['authentication', 'id'], 'local-id') diff --git a/src/migration-scripts/isis/0-to-1 b/src/migration-scripts/isis/0-to-1 index 0149c0c1f..e24288558 100755..100644 --- a/src/migration-scripts/isis/0-to-1 +++ b/src/migration-scripts/isis/0-to-1 @@ -1,56 +1,36 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process -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 = ['protocols', 'isis'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -# We need a temporary copy of the config -tmp_base = ['protocols', 'isis2'] -config.copy(base, tmp_base) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -# Now it's save to delete the old configuration -config.delete(base) + # We need a temporary copy of the config + tmp_base = ['protocols', 'isis2'] + config.copy(base, tmp_base) -# Rename temporary copy to new final config (IS-IS domain key is static and no -# longer required to be set via CLI) -config.rename(tmp_base, 'isis') + # Now it's save to delete the old configuration + config.delete(base) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # Rename temporary copy to new final config (IS-IS domain key is static and no + # longer required to be set via CLI) + config.rename(tmp_base, 'isis') diff --git a/src/migration-scripts/isis/1-to-2 b/src/migration-scripts/isis/1-to-2 index 9c110bf2a..0fc92a6de 100755..100644 --- a/src/migration-scripts/isis/1-to-2 +++ b/src/migration-scripts/isis/1-to-2 @@ -1,46 +1,27 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4739 refactor, and remove "on" from segment routing from the configuration -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -# Check if ISIS segment routing is configured. Then check if segment routing "on" exists, then delete the "on" as it is no longer needed. This is for global configuration. -if config.exists(['protocols', 'isis']): - if config.exists(['protocols', 'isis', 'segment-routing']): - if config.exists(['protocols', 'isis', 'segment-routing', 'enable']): - config.delete(['protocols', 'isis', 'segment-routing', 'enable']) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + # Check if ISIS segment routing is configured. Then check if segment + # routing "on" exists, then delete the "on" as it is no longer needed. + # This is for global configuration. + if config.exists(['protocols', 'isis']): + if config.exists(['protocols', 'isis', 'segment-routing']): + if config.exists(['protocols', 'isis', 'segment-routing', 'enable']): + config.delete(['protocols', 'isis', 'segment-routing', 'enable']) diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3 index 78e3c1715..afb9f2340 100755..100644 --- a/src/migration-scripts/isis/2-to-3 +++ b/src/migration-scripts/isis/2-to-3 @@ -1,63 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5150: Rework CLI definitions to apply route-maps between routing daemons # and zebra/kernel -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - isis_base = ['protocols', 'isis'] -# Check if IS-IS is configured - if so, migrate the CLI node -if config.exists(isis_base): - if config.exists(isis_base + ['route-map']): - tmp = config.return_value(isis_base + ['route-map']) - - config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp) - config.set_tag(['system', 'ip', 'protocol']) - config.delete(isis_base + ['route-map']) - -# Check if vrf names are configured. Check if IS-IS is configured - if so, -# migrate the CLI node(s) -if config.exists(['vrf', 'name']): - for vrf in config.list_nodes(['vrf', 'name']): - vrf_base = ['vrf', 'name', vrf] - if config.exists(vrf_base + ['protocols', 'isis', 'route-map']): - tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map']) - - config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp) - config.set_tag(vrf_base + ['ip', 'protocol', 'isis']) - config.delete(vrf_base + ['protocols', 'isis', 'route-map']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + # Check if IS-IS is configured - if so, migrate the CLI node + if config.exists(isis_base): + if config.exists(isis_base + ['route-map']): + tmp = config.return_value(isis_base + ['route-map']) + + config.set(['system', 'ip', 'protocol', 'isis', 'route-map'], value=tmp) + config.set_tag(['system', 'ip', 'protocol']) + config.delete(isis_base + ['route-map']) + + # Check if vrf names are configured. Check if IS-IS is configured - if so, + # migrate the CLI node(s) + if config.exists(['vrf', 'name']): + for vrf in config.list_nodes(['vrf', 'name']): + vrf_base = ['vrf', 'name', vrf] + if config.exists(vrf_base + ['protocols', 'isis', 'route-map']): + tmp = config.return_value(vrf_base + ['protocols', 'isis', 'route-map']) + + config.set(vrf_base + ['ip', 'protocol', 'isis', 'route-map'], value=tmp) + config.set_tag(vrf_base + ['ip', 'protocol', 'isis']) + config.delete(vrf_base + ['protocols', 'isis', 'route-map']) diff --git a/src/migration-scripts/l2tp/0-to-1 b/src/migration-scripts/l2tp/0-to-1 index 15d229822..f0cb6af96 100755..100644 --- a/src/migration-scripts/l2tp/0-to-1 +++ b/src/migration-scripts/l2tp/0-to-1 @@ -1,29 +1,32 @@ -#!/usr/bin/env python3 - +# Copyright 2018-2024 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/>. + +# T987: Unclutter L2TP/IPSec RADIUS configuration nodes # Unclutter L2TP VPN configuiration - move radius-server top level tag # nodes to a regular node which now also configures the radius source address # used when querying a radius server -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(cfg_base): + # Nothing to do + return -cfg_base = ['vpn', 'l2tp', 'remote-access', 'authentication'] -if not config.exists(cfg_base): - # Nothing to do - sys.exit(0) -else: # Migrate "vpn l2tp authentication radius-source-address" to new # "vpn l2tp authentication radius source-address" if config.exists(cfg_base + ['radius-source-address']): @@ -51,10 +54,3 @@ else: # delete top level tag node if config.exists(cfg_base + ['radius-server']): config.delete(cfg_base + ['radius-server']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/l2tp/1-to-2 b/src/migration-scripts/l2tp/1-to-2 index 2ffb91c53..468d564ac 100755..100644 --- a/src/migration-scripts/l2tp/1-to-2 +++ b/src/migration-scripts/l2tp/1-to-2 @@ -1,33 +1,28 @@ -#!/usr/bin/env python3 - -# Delete depricated outside-nexthop address - -import sys +# Copyright 2019-2024 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/>. + +# T1858: Delete deprecated outside-nexthop from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +cfg_base = ['vpn', 'l2tp', 'remote-access'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(cfg_base): + # Nothing to do + return -cfg_base = ['vpn', 'l2tp', 'remote-access'] -if not config.exists(cfg_base): - # Nothing to do - sys.exit(0) -else: if config.exists(cfg_base + ['outside-nexthop']): config.delete(cfg_base + ['outside-nexthop']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3 index 8527c2d4a..00fabb6b6 100755..100644 --- a/src/migration-scripts/l2tp/2-to-3 +++ b/src/migration-scripts/l2tp/2-to-3 @@ -1,40 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -# - remove primary/secondary identifier from nameserver -# - TODO: remove radius server req-limit +# T2264: combine IPv4/IPv6 name-server CLI syntax +# T2264: combine WINS CLI syntax +# T2264: remove RADIUS req-limit node +# T2264: migrate IPv6 prefix node to common CLI style -from sys import argv, exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] +base = ['vpn', 'l2tp', 'remote-access'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['vpn', 'l2tp', 'remote-access'] -if not config.exists(base): - # Nothing to do - exit(0) -else: # Migrate IPv4 DNS servers dns_base = base + ['dns-servers'] if config.exists(dns_base): @@ -98,10 +90,3 @@ else: prefix = p.split(',')[0] mask = p.split(',')[1] config.set(ipv6_base + ['delegate', prefix, 'delegate-prefix'], value=mask) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4 index 14b86ff04..01c3fa844 100755..100644 --- a/src/migration-scripts/l2tp/3-to-4 +++ b/src/migration-scripts/l2tp/3-to-4 @@ -1,26 +1,22 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -# - remove primary/secondary identifier from nameserver -# - TODO: remove radius server req-limit +# T2816: T3642: Move IPSec/L2TP code into vpn_ipsec.py and update to use PKI. import os -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.pki import load_certificate from vyos.pki import load_private_key @@ -28,141 +24,125 @@ from vyos.pki import encode_certificate from vyos.pki import encode_private_key from vyos.utils.process import run -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings'] pki_base = ['pki'] -if not config.exists(base): - exit(0) - AUTH_DIR = '/config/auth' def wrapped_pem_to_config_value(pem): return "".join(pem.strip().split("\n")[1:-1]) -if not config.exists(base + ['authentication', 'x509']): - exit(0) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if not config.exists(base + ['authentication', 'x509']): + return + + x509_base = base + ['authentication', 'x509'] + pki_name = 'l2tp_remote_access' + + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) + + if config.exists(x509_base + ['ca-cert-file']): + cert_file = config.return_value(x509_base + ['ca-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=pki_name) + else: + print(f'Failed to migrate CA certificate on l2tp remote-access config') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['crl-file']): + crl_file = config.return_value(x509_base + ['crl-file']) + crl_path = os.path.join(AUTH_DIR, crl_file) + crl = None + + if os.path.isfile(crl_path): + if not os.access(crl_path, os.R_OK): + run(f'sudo chmod 644 {crl_path}') + + with open(crl_path, 'r') as f: + crl_data = f.read() + crl = load_certificate(crl_data, wrap_tags=False) + + if crl: + crl_pem = encode_certificate(crl) + config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) + else: + print(f'Failed to migrate CRL on l2tp remote-access config') + + config.delete(x509_base + ['crl-file']) + + if config.exists(x509_base + ['server-cert-file']): + cert_file = config.return_value(x509_base + ['server-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) + else: + print(f'Failed to migrate certificate on l2tp remote-access config') + + config.delete(x509_base + ['server-cert-file']) + + if config.exists(x509_base + ['server-key-file']): + key_file = config.return_value(x509_base + ['server-key-file']) + key_passphrase = None -x509_base = base + ['authentication', 'x509'] -pki_name = 'l2tp_remote_access' + if config.exists(x509_base + ['server-key-password']): + key_passphrase = config.return_value(x509_base + ['server-key-password']) -if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) + key_path = os.path.join(AUTH_DIR, key_file) + key = None -if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) + if os.path.isfile(key_path): + if not os.access(key_path, os.R_OK): + run(f'sudo chmod 644 {key_path}') -if config.exists(x509_base + ['ca-cert-file']): - cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=pki_name) - else: - print(f'Failed to migrate CA certificate on l2tp remote-access config') - - config.delete(x509_base + ['ca-cert-file']) - -if config.exists(x509_base + ['crl-file']): - crl_file = config.return_value(x509_base + ['crl-file']) - crl_path = os.path.join(AUTH_DIR, crl_file) - crl = None - - if os.path.isfile(crl_path): - if not os.access(crl_path, os.R_OK): - run(f'sudo chmod 644 {crl_path}') - - with open(crl_path, 'r') as f: - crl_data = f.read() - crl = load_certificate(crl_data, wrap_tags=False) - - if crl: - crl_pem = encode_certificate(crl) - config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) - else: - print(f'Failed to migrate CRL on l2tp remote-access config') - - config.delete(x509_base + ['crl-file']) - -if config.exists(x509_base + ['server-cert-file']): - cert_file = config.return_value(x509_base + ['server-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) - else: - print(f'Failed to migrate certificate on l2tp remote-access config') - - config.delete(x509_base + ['server-cert-file']) - -if config.exists(x509_base + ['server-key-file']): - key_file = config.return_value(x509_base + ['server-key-file']) - key_passphrase = None - - if config.exists(x509_base + ['server-key-password']): - key_passphrase = config.return_value(x509_base + ['server-key-password']) - - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False) - - if key: - key_pem = encode_private_key(key, passphrase=key_passphrase) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) - - if key_passphrase: - config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected']) - config.set(x509_base + ['private-key-passphrase'], value=key_passphrase) - else: - print(f'Failed to migrate private key on l2tp remote-access config') - - config.delete(x509_base + ['server-key-file']) - if config.exists(x509_base + ['server-key-password']): - config.delete(x509_base + ['server-key-password']) - -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) + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False) + + if key: + key_pem = encode_private_key(key, passphrase=key_passphrase) + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + + if key_passphrase: + config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected']) + config.set(x509_base + ['private-key-passphrase'], value=key_passphrase) + else: + print(f'Failed to migrate private key on l2tp remote-access config') + + config.delete(x509_base + ['server-key-file']) + if config.exists(x509_base + ['server-key-password']): + config.delete(x509_base + ['server-key-password']) diff --git a/src/migration-scripts/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5 index b7f4d2677..56d451b8d 100755..100644 --- a/src/migration-scripts/l2tp/4-to-5 +++ b/src/migration-scripts/l2tp/4-to-5 @@ -1,85 +1,68 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - move all pool to named pools # 'start-stop' migrate to namedpool 'default-range-pool' # 'subnet' migrate to namedpool 'default-subnet-pool' # 'default-subnet-pool' is the next pool for 'default-range-pool' -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.base import Warning -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access'] pool_base = base + ['client-ip-pool'] -if not config.exists(base): - exit(0) -if not config.exists(pool_base): - exit(0) -default_pool = '' -range_pool_name = 'default-range-pool' +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): - def is_legalrange(ip1: str, ip2: str, mask: str): - from ipaddress import IPv4Interface - interface1 = IPv4Interface(f'{ip1}/{mask}') + if not config.exists(pool_base): + return - interface2 = IPv4Interface(f'{ip2}/{mask}') - return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip + default_pool = '' + range_pool_name = 'default-range-pool' - start_ip = config.return_value(pool_base + ['start']) - stop_ip = config.return_value(pool_base + ['stop']) - if is_legalrange(start_ip, stop_ip,'24'): - ip_range = f'{start_ip}-{stop_ip}' - config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) - default_pool = range_pool_name - else: - Warning( - f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') + if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): + def is_legalrange(ip1: str, ip2: str, mask: str): + from ipaddress import IPv4Interface + interface1 = IPv4Interface(f'{ip1}/{mask}') + + interface2 = IPv4Interface(f'{ip2}/{mask}') + return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip - config.delete(pool_base + ['start']) - config.delete(pool_base + ['stop']) + start_ip = config.return_value(pool_base + ['start']) + stop_ip = config.return_value(pool_base + ['stop']) + if is_legalrange(start_ip, stop_ip,'24'): + ip_range = f'{start_ip}-{stop_ip}' + config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) + default_pool = range_pool_name + else: + Warning( + f'L2TP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') -if config.exists(pool_base + ['subnet']): - for subnet in config.return_values(pool_base + ['subnet']): - config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) + config.delete(pool_base + ['start']) + config.delete(pool_base + ['stop']) - config.delete(pool_base + ['subnet']) - default_pool = range_pool_name + if config.exists(pool_base + ['subnet']): + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) -if default_pool: - config.set(base + ['default-pool'], value=default_pool) -# format as tag node -config.set_tag(pool_base) + config.delete(pool_base + ['subnet']) + default_pool = range_pool_name -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) + if default_pool: + config.set(base + ['default-pool'], value=default_pool) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/l2tp/5-to-6 b/src/migration-scripts/l2tp/5-to-6 index ac40b89c8..cc9f948a6 100755..100644 --- a/src/migration-scripts/l2tp/5-to-6 +++ b/src/migration-scripts/l2tp/5-to-6 @@ -1,106 +1,88 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access'] -if not config.exists(base): - exit(0) - -#migrate idle to ppp option lcp-echo-timeout -idle_path = base + ['idle'] -if config.exists(idle_path): - config.set(base + ['ppp-options', 'lcp-echo-timeout'], - value=config.return_value(idle_path)) - config.delete(idle_path) - -#migrate mppe from authentication to ppp-otion -mppe_path = base + ['authentication', 'mppe'] -if config.exists(mppe_path): - config.set(base + ['ppp-options', 'mppe'], - value=config.return_value(mppe_path)) - config.delete(mppe_path) - -#migrate require to protocol -require_path = base + ['authentication', 'require'] -if config.exists(require_path): - protocols = list(config.return_values(require_path)) - for protocol in protocols: - config.set(base + ['authentication', 'protocols'], value=protocol, - replace=False) - config.delete(require_path) -else: - config.set(base + ['authentication', 'protocols'], value='mschap-v2') - -#migrate default gateway if not exist -if not config.exists(base + ['gateway-address']): - config.set(base + ['gateway-address'], value='10.255.255.0') - -#migrate authentication radius timeout -rad_timeout_path = base + ['authentication', 'radius', 'timeout'] -if config.exists(rad_timeout_path): - if int(config.return_value(rad_timeout_path)) > 60: - config.set(rad_timeout_path, value=60) - -#migrate authentication radius acct timeout -rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout'] -if config.exists(rad_acct_timeout_path): - if int(config.return_value(rad_acct_timeout_path)) > 60: - config.set(rad_acct_timeout_path,value=60) - -#migrate authentication radius max-try -rad_max_try_path = base + ['authentication', 'radius', 'max-try'] -if config.exists(rad_max_try_path): - if int(config.return_value(rad_max_try_path)) > 20: - config.set(rad_max_try_path, value=20) - -#migrate dae-server to dynamic-author -dae_path_old = base + ['authentication', 'radius', 'dae-server'] -dae_path_new = base + ['authentication', 'radius', 'dynamic-author'] - -if config.exists(dae_path_old + ['ip-address']): - config.set(dae_path_new + ['server'], - value=config.return_value(dae_path_old + ['ip-address'])) - -if config.exists(dae_path_old + ['port']): - config.set(dae_path_new + ['port'], - value=config.return_value(dae_path_old + ['port'])) - -if config.exists(dae_path_old + ['secret']): - config.set(dae_path_new + ['key'], - value=config.return_value(dae_path_old + ['secret'])) - -if config.exists(dae_path_old): - config.delete(dae_path_old) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + #migrate idle to ppp option lcp-echo-timeout + idle_path = base + ['idle'] + if config.exists(idle_path): + config.set(base + ['ppp-options', 'lcp-echo-timeout'], + value=config.return_value(idle_path)) + config.delete(idle_path) + + #migrate mppe from authentication to ppp-otion + mppe_path = base + ['authentication', 'mppe'] + if config.exists(mppe_path): + config.set(base + ['ppp-options', 'mppe'], + value=config.return_value(mppe_path)) + config.delete(mppe_path) + + #migrate require to protocol + require_path = base + ['authentication', 'require'] + if config.exists(require_path): + protocols = list(config.return_values(require_path)) + for protocol in protocols: + config.set(base + ['authentication', 'protocols'], value=protocol, + replace=False) + config.delete(require_path) + else: + config.set(base + ['authentication', 'protocols'], value='mschap-v2') + + #migrate default gateway if not exist + if not config.exists(base + ['gateway-address']): + config.set(base + ['gateway-address'], value='10.255.255.0') + + #migrate authentication radius timeout + rad_timeout_path = base + ['authentication', 'radius', 'timeout'] + if config.exists(rad_timeout_path): + if int(config.return_value(rad_timeout_path)) > 60: + config.set(rad_timeout_path, value=60) + + #migrate authentication radius acct timeout + rad_acct_timeout_path = base + ['authentication', 'radius', 'acct-timeout'] + if config.exists(rad_acct_timeout_path): + if int(config.return_value(rad_acct_timeout_path)) > 60: + config.set(rad_acct_timeout_path,value=60) + + #migrate authentication radius max-try + rad_max_try_path = base + ['authentication', 'radius', 'max-try'] + if config.exists(rad_max_try_path): + if int(config.return_value(rad_max_try_path)) > 20: + config.set(rad_max_try_path, value=20) + + #migrate dae-server to dynamic-author + dae_path_old = base + ['authentication', 'radius', 'dae-server'] + dae_path_new = base + ['authentication', 'radius', 'dynamic-author'] + + if config.exists(dae_path_old + ['ip-address']): + config.set(dae_path_new + ['server'], + value=config.return_value(dae_path_old + ['ip-address'])) + + if config.exists(dae_path_old + ['port']): + config.set(dae_path_new + ['port'], + value=config.return_value(dae_path_old + ['port'])) + + if config.exists(dae_path_old + ['secret']): + config.set(dae_path_new + ['key'], + value=config.return_value(dae_path_old + ['secret'])) + + if config.exists(dae_path_old): + config.delete(dae_path_old) diff --git a/src/migration-scripts/l2tp/6-to-7 b/src/migration-scripts/l2tp/6-to-7 index 1c536585c..4dba5974e 100755..100644 --- a/src/migration-scripts/l2tp/6-to-7 +++ b/src/migration-scripts/l2tp/6-to-7 @@ -1,57 +1,39 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrating to named ipv6 pools -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access'] pool_base = base + ['client-ipv6-pool'] -if not config.exists(base): - exit(0) -if not config.exists(pool_base): - exit(0) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -ipv6_pool_name = 'ipv6-pool' -config.copy(pool_base, pool_base + [ipv6_pool_name]) + if not config.exists(pool_base): + return -if config.exists(pool_base + ['prefix']): - config.delete(pool_base + ['prefix']) - config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) -if config.exists(pool_base + ['delegate']): - config.delete(pool_base + ['delegate']) -# format as tag node -config.set_tag(pool_base) + ipv6_pool_name = 'ipv6-pool' + config.copy(pool_base, pool_base + [ipv6_pool_name]) -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) + if config.exists(pool_base + ['prefix']): + config.delete(pool_base + ['prefix']) + config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) + if config.exists(pool_base + ['delegate']): + config.delete(pool_base + ['delegate']) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/l2tp/7-to-8 b/src/migration-scripts/l2tp/7-to-8 index e429ed057..527906fc8 100755..100644 --- a/src/migration-scripts/l2tp/7-to-8 +++ b/src/migration-scripts/l2tp/7-to-8 @@ -1,65 +1,47 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrate from 'ccp-disable' to 'ppp-options.disable-ccp' # Migration ipv6 options -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access'] -if not config.exists(base): - exit(0) - -#CCP migration -if config.exists(base + ['ccp-disable']): - config.delete(base + ['ccp-disable']) - config.set(base + ['ppp-options', 'disable-ccp']) - -#IPV6 options migrations -if config.exists(base + ['ppp-options','ipv6-peer-intf-id']): - intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id']) - if intf_peer_id == 'ipv4': - intf_peer_id = 'ipv4-addr' - config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True) - config.delete(base + ['ppp-options','ipv6-peer-intf-id']) - -if config.exists(base + ['ppp-options','ipv6-intf-id']): - intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id']) - config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True) - config.delete(base + ['ppp-options','ipv6-intf-id']) - -if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']): - config.set(base + ['ppp-options','ipv6-accept-peer-interface-id']) - config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + #CCP migration + if config.exists(base + ['ccp-disable']): + config.delete(base + ['ccp-disable']) + config.set(base + ['ppp-options', 'disable-ccp']) + + #IPV6 options migrations + if config.exists(base + ['ppp-options','ipv6-peer-intf-id']): + intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id']) + if intf_peer_id == 'ipv4': + intf_peer_id = 'ipv4-addr' + config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True) + config.delete(base + ['ppp-options','ipv6-peer-intf-id']) + + if config.exists(base + ['ppp-options','ipv6-intf-id']): + intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id']) + config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True) + config.delete(base + ['ppp-options','ipv6-intf-id']) + + if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']): + config.set(base + ['ppp-options','ipv6-accept-peer-interface-id']) + config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id']) diff --git a/src/migration-scripts/l2tp/8-to-9 b/src/migration-scripts/l2tp/8-to-9 index 672180e25..e6b689e80 100755..100644 --- a/src/migration-scripts/l2tp/8-to-9 +++ b/src/migration-scripts/l2tp/8-to-9 @@ -1,46 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Deleted 'dhcp-interface' from l2tp -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'l2tp', 'remote-access'] -if not config.exists(base): - exit(0) -# deleting unused dhcp-interface -if config.exists(base + ['dhcp-interface']): - config.delete(base + ['dhcp-interface']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -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) + # deleting unused dhcp-interface + if config.exists(base + ['dhcp-interface']): + config.delete(base + ['dhcp-interface']) diff --git a/src/migration-scripts/lldp/0-to-1 b/src/migration-scripts/lldp/0-to-1 index a99356062..c16e7e84b 100755..100644 --- a/src/migration-scripts/lldp/0-to-1 +++ b/src/migration-scripts/lldp/0-to-1 @@ -1,49 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Delete "set service lldp interface <interface> location civic-based" option # as it was broken most of the time anyways -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +base = ['service', 'lldp', 'interface'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['service', 'lldp', 'interface'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: # Delete nodes with abandoned CLI syntax for interface in config.list_nodes(base): if config.exists(base + [interface, 'location', 'civic-based']): config.delete(base + [interface, 'location', 'civic-based']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/lldp/1-to-2 b/src/migration-scripts/lldp/1-to-2 index 35efb25db..7f233a725 100755..100644 --- a/src/migration-scripts/lldp/1-to-2 +++ b/src/migration-scripts/lldp/1-to-2 @@ -1,48 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5855: migrate "set service lldp snmp enable" -> `set service lldp snmp" -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'lldp'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -if config.exists(base + ['snmp']): - enabled = config.exists(base + ['snmp', 'enable']) - config.delete(base + ['snmp']) - if enabled: config.set(base + ['snmp']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -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)) - sys.exit(1) + if config.exists(base + ['snmp']): + enabled = config.exists(base + ['snmp', 'enable']) + config.delete(base + ['snmp']) + if enabled: config.set(base + ['snmp']) diff --git a/src/migration-scripts/monitoring/0-to-1 b/src/migration-scripts/monitoring/0-to-1 index 384d22f8c..92f824325 100755..100644 --- a/src/migration-scripts/monitoring/0-to-1 +++ b/src/migration-scripts/monitoring/0-to-1 @@ -14,58 +14,53 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process +# Copyright 2022-2024 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/>. -from sys import argv -from sys import exit +# T3417: migrate IS-IS tagNode to node as we can only have one IS-IS process 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 = ['service', 'monitoring', 'telegraf'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['authentication', 'organization']): - tmp = config.return_value(base + ['authentication', 'organization']) - config.delete(base + ['authentication', 'organization']) - config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp) -if config.exists(base + ['authentication', 'token']): - tmp = config.return_value(base + ['authentication', 'token']) - config.delete(base + ['authentication', 'token']) - config.set(base + ['influxdb', 'authentication', 'token'], value=tmp) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -if config.exists(base + ['bucket']): - tmp = config.return_value(base + ['bucket']) - config.delete(base + ['bucket']) - config.set(base + ['influxdb', 'bucket'], value=tmp) + if config.exists(base + ['authentication', 'organization']): + tmp = config.return_value(base + ['authentication', 'organization']) + config.delete(base + ['authentication', 'organization']) + config.set(base + ['influxdb', 'authentication', 'organization'], value=tmp) -if config.exists(base + ['port']): - tmp = config.return_value(base + ['port']) - config.delete(base + ['port']) - config.set(base + ['influxdb', 'port'], value=tmp) + if config.exists(base + ['authentication', 'token']): + tmp = config.return_value(base + ['authentication', 'token']) + config.delete(base + ['authentication', 'token']) + config.set(base + ['influxdb', 'authentication', 'token'], value=tmp) -if config.exists(base + ['url']): - tmp = config.return_value(base + ['url']) - config.delete(base + ['url']) - config.set(base + ['influxdb', 'url'], value=tmp) + if config.exists(base + ['bucket']): + tmp = config.return_value(base + ['bucket']) + config.delete(base + ['bucket']) + config.set(base + ['influxdb', 'bucket'], value=tmp) + if config.exists(base + ['port']): + tmp = config.return_value(base + ['port']) + config.delete(base + ['port']) + config.set(base + ['influxdb', 'port'], value=tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if config.exists(base + ['url']): + tmp = config.return_value(base + ['url']) + config.delete(base + ['url']) + config.set(base + ['influxdb', 'url'], value=tmp) diff --git a/src/migration-scripts/nat/4-to-5 b/src/migration-scripts/nat/4-to-5 index ce215d455..e1919da50 100755..100644 --- a/src/migration-scripts/nat/4-to-5 +++ b/src/migration-scripts/nat/4-to-5 @@ -1,40 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Drop the enable/disable from the nat "log" node. If log node is specified # it is "enabled" -from sys import argv,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() +def migrate(config: ConfigTree) -> None: + if not config.exists(['nat']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['nat']): - # Nothing to do - exit(0) -else: for direction in ['source', 'destination']: # If a node doesn't exist, we obviously have nothing to do. if not config.exists(['nat', direction]): @@ -55,10 +43,3 @@ else: config.delete(base + ['log']) if tmp == 'enable': config.set(base + ['log']) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/nat/5-to-6 b/src/migration-scripts/nat/5-to-6 index cfe98ddcf..a583d4eb6 100755..100644 --- a/src/migration-scripts/nat/5-to-6 +++ b/src/migration-scripts/nat/5-to-6 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5643: move from 'set nat [source|destination] rule X [inbound-interface|outbound interface] <iface>' # to @@ -23,7 +22,7 @@ # 'set nat [source|destination] rule X [source| destination| translation] address <IP/Netmask| !IP/Netmask>' import ipaddress -from sys import argv,exit + from vyos.configtree import ConfigTree @@ -62,21 +61,10 @@ def _func_T6100(conf, base_path): return -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) - +def migrate(config: ConfigTree) -> None: if not config.exists(['nat']): # Nothing to do - exit(0) + return for direction in ['source', 'destination']: # If a node doesn't exist, we obviously have nothing to do. @@ -92,10 +80,3 @@ if __name__ == '__main__': base = ['nat', direction, 'rule', rule] _func_T5643(config,base) _func_T6100(config,base) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7 index a2e735394..81b413e36 100755..100644 --- a/src/migration-scripts/nat/6-to-7 +++ b/src/migration-scripts/nat/6-to-7 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5681: Firewall re-writing. Simplify cli when mathcing interface # From @@ -23,49 +22,31 @@ # 'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>' # Also remove command if interface == any -from sys import argv,exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['nat']): - # Nothing to do - exit(0) - -for direction in ['source', 'destination']: - # If a node doesn't exist, we obviously have nothing to do. - if not config.exists(['nat', direction]): - continue - - # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, - # but there are no rules under it. - if not config.list_nodes(['nat', direction]): - continue - - for rule in config.list_nodes(['nat', direction, 'rule']): - base = ['nat', direction, 'rule', rule] - for iface in ['inbound-interface','outbound-interface']: - if config.exists(base + [iface]): - if config.exists(base + [iface, 'interface-name']): - tmp = config.return_value(base + [iface, 'interface-name']) - if tmp != 'any': - config.delete(base + [iface, 'interface-name']) - config.set(base + [iface, 'name'], value=tmp) - else: - config.delete(base + [iface]) - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(['nat']): + # Nothing to do + return + + for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. + if not config.exists(['nat', direction]): + continue + + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat', direction]): + continue + + for rule in config.list_nodes(['nat', direction, 'rule']): + base = ['nat', direction, 'rule', rule] + for iface in ['inbound-interface','outbound-interface']: + if config.exists(base + [iface]): + if config.exists(base + [iface, 'interface-name']): + tmp = config.return_value(base + [iface, 'interface-name']) + if tmp != 'any': + config.delete(base + [iface, 'interface-name']) + config.set(base + [iface, 'name'], value=tmp) + else: + config.delete(base + [iface]) diff --git a/src/migration-scripts/nat/7-to-8 b/src/migration-scripts/nat/7-to-8 index ab2ffa6d3..9ae389ef1 100755..100644 --- a/src/migration-scripts/nat/7-to-8 +++ b/src/migration-scripts/nat/7-to-8 @@ -1,62 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6345: random - In kernel 5.0 and newer this is the same as fully-random. # In earlier kernels the port mapping will be randomized using a seeded # MD5 hash mix using source and destination address and destination port. # drop fully-random from CLI -from sys import argv,exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['nat']): - # Nothing to do - exit(0) - -for direction in ['source', 'destination']: - # If a node doesn't exist, we obviously have nothing to do. - if not config.exists(['nat', direction]): - continue - - # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, - # but there are no rules under it. - if not config.list_nodes(['nat', direction]): - continue - - for rule in config.list_nodes(['nat', direction, 'rule']): - port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping'] - if config.exists(port_mapping): - tmp = config.return_value(port_mapping) - if tmp == 'fully-random': - config.set(port_mapping, value='random') - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(['nat']): + # Nothing to do + return + + for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. + if not config.exists(['nat', direction]): + continue + + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat', direction]): + continue + + for rule in config.list_nodes(['nat', direction, 'rule']): + port_mapping = ['nat', direction, 'rule', rule, 'translation', 'options', 'port-mapping'] + if config.exists(port_mapping): + tmp = config.return_value(port_mapping) + if tmp == 'fully-random': + config.set(port_mapping, value='random') diff --git a/src/migration-scripts/nat66/0-to-1 b/src/migration-scripts/nat66/0-to-1 index 444b2315f..b3c6bf4cc 100755..100644 --- a/src/migration-scripts/nat66/0-to-1 +++ b/src/migration-scripts/nat66/0-to-1 @@ -1,33 +1,20 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv,exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - def merge_npt(config,base,rule): merge_base = ['nat66','source','rule',rule] # Configure migration functions @@ -51,21 +38,15 @@ def merge_npt(config,base,rule): tmp = config.return_value(base + ['translation','prefix']) config.set(merge_base + ['translation','address'],value=tmp) -if not config.exists(['nat', 'nptv6']): - # Nothing to do - exit(0) - -for rule in config.list_nodes(['nat', 'nptv6', 'rule']): - base = ['nat', 'nptv6', 'rule', rule] - # Merge 'nat nptv6' to 'nat66 source' - merge_npt(config,base,rule) +def migrate(config: ConfigTree) -> None: + if not config.exists(['nat', 'nptv6']): + # Nothing to do + return -# Delete the original NPT configuration -config.delete(['nat','nptv6']); + for rule in config.list_nodes(['nat', 'nptv6', 'rule']): + base = ['nat', 'nptv6', 'rule', rule] + # Merge 'nat nptv6' to 'nat66 source' + merge_npt(config,base,rule) -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) + # Delete the original NPT configuration + config.delete(['nat','nptv6']); diff --git a/src/migration-scripts/nat66/1-to-2 b/src/migration-scripts/nat66/1-to-2 index b7d4e3f6b..f49940ae0 100755..100644 --- a/src/migration-scripts/nat66/1-to-2 +++ b/src/migration-scripts/nat66/1-to-2 @@ -14,50 +14,48 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +# Copyright 2023-2024 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/>. + # T5681: Firewall re-writing. Simplify cli when mathcing interface # From # 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] <iface>' # to # 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] name <iface>' -from sys import argv,exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) -if not config.exists(['nat66']): - # Nothing to do - exit(0) - -for direction in ['source', 'destination']: - # If a node doesn't exist, we obviously have nothing to do. - if not config.exists(['nat66', direction]): - continue - - # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, - # but there are no rules under it. - if not config.list_nodes(['nat66', direction]): - continue - - for rule in config.list_nodes(['nat66', direction, 'rule']): - base = ['nat66', direction, 'rule', rule] - for iface in ['inbound-interface','outbound-interface']: - if config.exists(base + [iface]): - tmp = config.return_value(base + [iface]) - config.delete(base + [iface]) - config.set(base + [iface, 'name'], 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) +def migrate(config: ConfigTree) -> None: + if not config.exists(['nat66']): + # Nothing to do + return + + for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. + if not config.exists(['nat66', direction]): + continue + + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat66', direction]): + continue + + for rule in config.list_nodes(['nat66', direction, 'rule']): + base = ['nat66', direction, 'rule', rule] + for iface in ['inbound-interface','outbound-interface']: + if config.exists(base + [iface]): + tmp = config.return_value(base + [iface]) + config.delete(base + [iface]) + config.set(base + [iface, 'name'], value=tmp) diff --git a/src/migration-scripts/nat66/2-to-3 b/src/migration-scripts/nat66/2-to-3 index f34f170b3..55d5f4b2b 100755..100644 --- a/src/migration-scripts/nat66/2-to-3 +++ b/src/migration-scripts/nat66/2-to-3 @@ -1,61 +1,45 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from sys import argv,exit -from vyos.configtree import ConfigTree +# 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/>. -if len(argv) < 2: - print("Must specify file name!") - exit(1) +# T2898: add ndp-proxy service -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +from vyos.configtree import ConfigTree base = ['nat66', 'source'] new_base = ['service', 'ndp-proxy', 'interface'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) - -for rule in config.list_nodes(base + ['rule']): - base_rule = base + ['rule', rule] - - interface = None - if config.exists(base_rule + ['outbound-interface', 'name']): - interface = config.return_value(base_rule + ['outbound-interface', 'name']) - else: - continue - - prefix_base = base_rule + ['source', 'prefix'] - if config.exists(prefix_base): - prefix = config.return_value(prefix_base) - config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static') - config.set_tag(new_base) - config.set_tag(new_base + [interface, 'prefix']) - - if config.exists(base_rule + ['disable']): - config.set(new_base + [interface, 'prefix', prefix, 'disable']) - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for rule in config.list_nodes(base + ['rule']): + base_rule = base + ['rule', rule] + + interface = None + if config.exists(base_rule + ['outbound-interface', 'name']): + interface = config.return_value(base_rule + ['outbound-interface', 'name']) + else: + continue + + prefix_base = base_rule + ['source', 'prefix'] + if config.exists(prefix_base): + prefix = config.return_value(prefix_base) + config.set(new_base + [interface, 'prefix', prefix, 'mode'], value='static') + config.set_tag(new_base) + config.set_tag(new_base + [interface, 'prefix']) + + if config.exists(base_rule + ['disable']): + config.set(new_base + [interface, 'prefix', prefix, 'disable']) diff --git a/src/migration-scripts/ntp/0-to-1 b/src/migration-scripts/ntp/0-to-1 index cbce45b9b..01f5a460a 100755..100644 --- a/src/migration-scripts/ntp/0-to-1 +++ b/src/migration-scripts/ntp/0-to-1 @@ -1,36 +1,32 @@ #!/usr/bin/env python3 -# Delete "set system ntp server <n> dynamic" option +# Copyright 2018-2024 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/>. -import sys +# Delete "set system ntp server <n> dynamic" option from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(['system', 'ntp', 'server']): + # Nothing to do + return -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['system', 'ntp', 'server']): - # Nothing to do - sys.exit(0) -else: # Delete abandoned leaf node if found inside tag node for # "set system ntp server <n> dynamic" base = ['system', 'ntp', 'server'] for server in config.list_nodes(base): if config.exists(base + [server, 'dynamic']): config.delete(base + [server, 'dynamic']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2 index fd1f15d91..fd7b08221 100755..100644 --- a/src/migration-scripts/ntp/1-to-2 +++ b/src/migration-scripts/ntp/1-to-2 @@ -1,72 +1,53 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3008: move from ntpd to chrony and migrate "system ntp" to "service ntp" -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base_path = ['system', 'ntp'] new_base_path = ['service', 'ntp'] -if not config.exists(base_path): - # Nothing to do - sys.exit(0) - -# config.copy does not recursively create a path, so create ['service'] if -# it doesn't yet exist, such as for config.boot.default -if not config.exists(['service']): - config.set(['service']) - -# copy "system ntp" to "service ntp" -config.copy(base_path, new_base_path) -config.delete(base_path) - -# chrony does not support the preempt option, drop it -for server in config.list_nodes(new_base_path + ['server']): - server_base = new_base_path + ['server', server] - if config.exists(server_base + ['preempt']): - config.delete(server_base + ['preempt']) - -# Rename "allow-clients" -> "allow-client" -if config.exists(new_base_path + ['allow-clients']): - config.rename(new_base_path + ['allow-clients'], 'allow-client') - -# By default VyOS 1.3 allowed NTP queries for all networks - in chrony we -# explicitly disable this behavior and clients need to be specified using the -# allow-client CLI option. In order to be fully backwards compatible, we specify -# 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly. -if not config.exists(new_base_path + ['allow-client']): - config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False) - config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False) -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)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return + + # config.copy does not recursively create a path, so create ['service'] if + # it doesn't yet exist, such as for config.boot.default + if not config.exists(['service']): + config.set(['service']) + + # copy "system ntp" to "service ntp" + config.copy(base_path, new_base_path) + config.delete(base_path) + + # chrony does not support the preempt option, drop it + for server in config.list_nodes(new_base_path + ['server']): + server_base = new_base_path + ['server', server] + if config.exists(server_base + ['preempt']): + config.delete(server_base + ['preempt']) + + # Rename "allow-clients" -> "allow-client" + if config.exists(new_base_path + ['allow-clients']): + config.rename(new_base_path + ['allow-clients'], 'allow-client') + + # By default VyOS 1.3 allowed NTP queries for all networks - in chrony we + # explicitly disable this behavior and clients need to be specified using the + # allow-client CLI option. In order to be fully backwards compatible, we specify + # 0.0.0.0/0 and ::/0 as allow networks if not specified otherwise explicitly. + if not config.exists(new_base_path + ['allow-client']): + config.set(new_base_path + ['allow-client', 'address'], value='0.0.0.0/0', replace=False) + config.set(new_base_path + ['allow-client', 'address'], value='::/0', replace=False) diff --git a/src/migration-scripts/ntp/2-to-3 b/src/migration-scripts/ntp/2-to-3 index a4351845e..bbda90351 100755..100644 --- a/src/migration-scripts/ntp/2-to-3 +++ b/src/migration-scripts/ntp/2-to-3 @@ -1,62 +1,43 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright 2023-2024 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 -# published by the Free Software Foundation. +# 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 program is distributed in the hope that it will be useful, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5154: allow only one ip address per family for parameter 'listen-address' # Allow only one interface for parameter 'interface' # If more than one are specified, remove such entries -import sys - from vyos.configtree import ConfigTree from vyos.template import is_ipv4 from vyos.template import is_ipv6 -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base_path = ['service', 'ntp'] -if not config.exists(base_path): - # Nothing to do - sys.exit(0) -if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1): - for addr in config.return_values(base_path + ['listen-address']): - if is_ipv4(addr): - config.delete_value(base_path + ['listen-address'], addr) +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return -if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1): - for addr in config.return_values(base_path + ['listen-address']): - if is_ipv6(addr): - config.delete_value(base_path + ['listen-address'], addr) + if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv4(addr)]) > 1): + for addr in config.return_values(base_path + ['listen-address']): + if is_ipv4(addr): + config.delete_value(base_path + ['listen-address'], addr) -if config.exists(base_path + ['interface']): - if len(config.return_values(base_path + ['interface'])) > 1: - config.delete(base_path + ['interface']) + if config.exists(base_path + ['listen-address']) and (len([addr for addr in config.return_values(base_path + ['listen-address']) if is_ipv6(addr)]) > 1): + for addr in config.return_values(base_path + ['listen-address']): + if is_ipv6(addr): + config.delete_value(base_path + ['listen-address'], addr) -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)) - sys.exit(1) + if config.exists(base_path + ['interface']): + if len(config.return_values(base_path + ['interface'])) > 1: + config.delete(base_path + ['interface']) diff --git a/src/migration-scripts/openconnect/0-to-1 b/src/migration-scripts/openconnect/0-to-1 index c64b16cb2..aa5a97eee 100755..100644 --- a/src/migration-scripts/openconnect/0-to-1 +++ b/src/migration-scripts/openconnect/0-to-1 @@ -1,25 +1,22 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - Update SSL to use PKI configuration import os -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.pki import load_certificate from vyos.pki import load_private_key @@ -27,109 +24,93 @@ from vyos.pki import encode_certificate from vyos.pki import encode_private_key from vyos.utils.process import run -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'openconnect'] pki_base = ['pki'] -if not config.exists(base): - exit(0) - AUTH_DIR = '/config/auth' def wrapped_pem_to_config_value(pem): return "".join(pem.strip().split("\n")[1:-1]) -if not config.exists(base + ['ssl']): - exit(0) - -x509_base = base + ['ssl'] -pki_name = 'openconnect' - -if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) - -if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) - -if config.exists(x509_base + ['ca-cert-file']): - cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=pki_name) - else: - print(f'Failed to migrate CA certificate on openconnect config') - - config.delete(x509_base + ['ca-cert-file']) - -if config.exists(x509_base + ['cert-file']): - cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) - else: - print(f'Failed to migrate certificate on openconnect config') - - config.delete(x509_base + ['cert-file']) - -if config.exists(x509_base + ['key-file']): - key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - if key: - key_pem = encode_private_key(key, passphrase=None) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) - else: - print(f'Failed to migrate private key on openconnect config') - - config.delete(x509_base + ['key-file']) - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if not config.exists(base + ['ssl']): + return + + x509_base = base + ['ssl'] + pki_name = 'openconnect' + + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) + + if config.exists(x509_base + ['ca-cert-file']): + cert_file = config.return_value(x509_base + ['ca-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=pki_name) + else: + print(f'Failed to migrate CA certificate on openconnect config') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['cert-file']): + cert_file = config.return_value(x509_base + ['cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) + else: + print(f'Failed to migrate certificate on openconnect config') + + config.delete(x509_base + ['cert-file']) + + if config.exists(x509_base + ['key-file']): + key_file = config.return_value(x509_base + ['key-file']) + key_path = os.path.join(AUTH_DIR, key_file) + key = None + + if os.path.isfile(key_path): + if not os.access(key_path, os.R_OK): + run(f'sudo chmod 644 {key_path}') + + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) + + if key: + key_pem = encode_private_key(key, passphrase=None) + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + else: + print(f'Failed to migrate private key on openconnect config') + + config.delete(x509_base + ['key-file']) diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2 index 7978aa56e..4f74b44df 100755..100644 --- a/src/migration-scripts/openconnect/1-to-2 +++ b/src/migration-scripts/openconnect/1-to-2 @@ -1,42 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Delete depricated outside-nexthop address -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - cfg_base = ['vpn', 'openconnect'] -if not config.exists(cfg_base): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(cfg_base): + # Nothing to do + return + if config.exists(cfg_base + ['authentication', 'mode']): if config.return_value(cfg_base + ['authentication', 'mode']) == 'radius': # if "mode value radius", change to "mode + valueless node radius" @@ -46,9 +33,3 @@ else: # if "mode local", change to "mode + node local value password" config.delete_value(cfg_base + ['authentication', 'mode'], 'local') config.set(cfg_base + ['authentication', 'mode', 'local'], value='password') - 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)) - sys.exit(1) diff --git a/src/migration-scripts/openconnect/2-to-3 b/src/migration-scripts/openconnect/2-to-3 index e78fc8a91..00e13ecb0 100755..100644 --- a/src/migration-scripts/openconnect/2-to-3 +++ b/src/migration-scripts/openconnect/2-to-3 @@ -1,50 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4982: Retain prior default TLS version (v1.0) when upgrading installations with existing openconnect configurations -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - - -config = ConfigTree(config_file) cfg_base = ['vpn', 'openconnect'] -# bail out early if service is unconfigured -if not config.exists(cfg_base): - sys.exit(0) - -# new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility -tls_min_path = cfg_base + ['tls-version-min'] -if not config.exists(tls_min_path): - config.set(tls_min_path, value='1.0') +def migrate(config: ConfigTree) -> None: + # bail out early if service is unconfigured + if not config.exists(cfg_base): + return -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)) - sys.exit(1) + # new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility + tls_min_path = cfg_base + ['tls-version-min'] + if not config.exists(tls_min_path): + config.set(tls_min_path, value='1.0') diff --git a/src/migration-scripts/openvpn/0-to-1 b/src/migration-scripts/openvpn/0-to-1 index 24bb38d3c..e5db731ed 100755..100644 --- a/src/migration-scripts/openvpn/0-to-1 +++ b/src/migration-scripts/openvpn/0-to-1 @@ -1,26 +1,27 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 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/>. # Removes outdated ciphers (DES and Blowfish) from OpenVPN configs -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['interfaces', 'openvpn']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['interfaces', 'openvpn']): - # Nothing to do - sys.exit(0) -else: ovpn_intfs = config.list_nodes(['interfaces', 'openvpn']) for i in ovpn_intfs: # Remove DES and Blowfish from 'encryption cipher' @@ -40,10 +41,3 @@ else: if config.exists(['interfaces', 'openvpn', i, 'encryption']) and \ (config.list_nodes(['interfaces', 'openvpn', i, 'encryption']) == []): config.delete(['interfaces', 'openvpn', i, 'encryption']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/openvpn/1-to-2 b/src/migration-scripts/openvpn/1-to-2 index 1f82a2128..b7b7d4c77 100755..100644 --- a/src/migration-scripts/openvpn/1-to-2 +++ b/src/migration-scripts/openvpn/1-to-2 @@ -17,25 +17,13 @@ # Removes --cipher option (deprecated) from OpenVPN configs # and moves it to --data-ciphers for server and client modes -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['interfaces', 'openvpn']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['interfaces', 'openvpn']): - # Nothing to do - sys.exit(0) -else: ovpn_intfs = config.list_nodes(['interfaces', 'openvpn']) for i in ovpn_intfs: # Remove 'encryption cipher' and add this value to 'encryption ncp-ciphers' @@ -65,10 +53,3 @@ else: for c in ncp_ciphers: config.set(ncp_cipher_path, value=c, replace=False) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1 index 4085423a2..a1f810960 100755..100644 --- a/src/migration-scripts/ospf/0-to-1 +++ b/src/migration-scripts/ospf/0-to-1 @@ -1,22 +1,20 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3753: upgrade to FRR8 and move CLI options to better fit with the new FRR CLI -from sys import argv from vyos.configtree import ConfigTree def ospf_passive_migration(config, ospf_base): @@ -40,45 +38,29 @@ def ospf_passive_migration(config, ospf_base): config.set_tag(ospf_base + ['interface']) config.delete(ospf_base + ['passive-interface-exclude']) -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - ospfv3_base = ['protocols', 'ospfv3'] -if config.exists(ospfv3_base): - area_base = ospfv3_base + ['area'] - if config.exists(area_base): - for area in config.list_nodes(area_base): - if not config.exists(area_base + [area, 'interface']): - continue - for interface in config.return_values(area_base + [area, 'interface']): - config.set(ospfv3_base + ['interface', interface, 'area'], value=area) - config.set_tag(ospfv3_base + ['interface']) +def migrate(config: ConfigTree) -> None: + if config.exists(ospfv3_base): + area_base = ospfv3_base + ['area'] + if config.exists(area_base): + for area in config.list_nodes(area_base): + if not config.exists(area_base + [area, 'interface']): + continue - config.delete(area_base + [area, 'interface']) + for interface in config.return_values(area_base + [area, 'interface']): + config.set(ospfv3_base + ['interface', interface, 'area'], value=area) + config.set_tag(ospfv3_base + ['interface']) -# Migrate OSPF syntax in default VRF -ospf_base = ['protocols', 'ospf'] -ospf_passive_migration(config, ospf_base) + config.delete(area_base + [area, 'interface']) -vrf_base = ['vrf', 'name'] -if config.exists(vrf_base): - for vrf in config.list_nodes(vrf_base): - vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf'] - if config.exists(vrf_ospf_base): - ospf_passive_migration(config, vrf_ospf_base) + # Migrate OSPF syntax in default VRF + ospf_base = ['protocols', 'ospf'] + ospf_passive_migration(config, ospf_base) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + vrf_base = ['vrf', 'name'] + if config.exists(vrf_base): + for vrf in config.list_nodes(vrf_base): + vrf_ospf_base = vrf_base + [vrf, 'protocols', 'ospf'] + if config.exists(vrf_ospf_base): + ospf_passive_migration(config, vrf_ospf_base) diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2 index ba9499c60..5368d8dd7 100755..100644 --- a/src/migration-scripts/ospf/1-to-2 +++ b/src/migration-scripts/ospf/1-to-2 @@ -1,80 +1,60 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5150: Rework CLI definitions to apply route-maps between routing daemons # and zebra/kernel -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - ospf_base = ['protocols', 'ospf'] -# Check if OSPF is configured - if so, migrate the CLI node -if config.exists(ospf_base): - if config.exists(ospf_base + ['route-map']): - tmp = config.return_value(ospf_base + ['route-map']) - - config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp) - config.set_tag(['system', 'ip', 'protocol']) - config.delete(ospf_base + ['route-map']) - -ospfv3_base = ['protocols', 'ospfv3'] -# Check if OSPFv3 is configured - if so, migrate the CLI node -if config.exists(ospfv3_base): - if config.exists(ospfv3_base + ['route-map']): - tmp = config.return_value(ospfv3_base + ['route-map']) - - config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) - config.set_tag(['system', 'ipv6', 'protocol']) - config.delete(ospfv3_base + ['route-map']) - -# Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so, -# migrate the CLI node(s) -if config.exists(['vrf', 'name']): - for vrf in config.list_nodes(['vrf', 'name']): - vrf_base = ['vrf', 'name', vrf] - if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']): - tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map']) - - config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp) - config.set_tag(vrf_base + ['ip', 'protocol', 'ospf']) - config.delete(vrf_base + ['protocols', 'ospf', 'route-map']) - - if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']): - tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map']) - - config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) - config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6']) - config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + # Check if OSPF is configured - if so, migrate the CLI node + if config.exists(ospf_base): + if config.exists(ospf_base + ['route-map']): + tmp = config.return_value(ospf_base + ['route-map']) + + config.set(['system', 'ip', 'protocol', 'ospf', 'route-map'], value=tmp) + config.set_tag(['system', 'ip', 'protocol']) + config.delete(ospf_base + ['route-map']) + + ospfv3_base = ['protocols', 'ospfv3'] + # Check if OSPFv3 is configured - if so, migrate the CLI node + if config.exists(ospfv3_base): + if config.exists(ospfv3_base + ['route-map']): + tmp = config.return_value(ospfv3_base + ['route-map']) + + config.set(['system', 'ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) + config.set_tag(['system', 'ipv6', 'protocol']) + config.delete(ospfv3_base + ['route-map']) + + # Check if vrf names are configured. Check if OSPF/OSPFv3 is configured - if so, + # migrate the CLI node(s) + if config.exists(['vrf', 'name']): + for vrf in config.list_nodes(['vrf', 'name']): + vrf_base = ['vrf', 'name', vrf] + if config.exists(vrf_base + ['protocols', 'ospf', 'route-map']): + tmp = config.return_value(vrf_base + ['protocols', 'ospf', 'route-map']) + + config.set(vrf_base + ['ip', 'protocol', 'ospf', 'route-map'], value=tmp) + config.set_tag(vrf_base + ['ip', 'protocol', 'ospf']) + config.delete(vrf_base + ['protocols', 'ospf', 'route-map']) + + if config.exists(vrf_base + ['protocols', 'ospfv3', 'route-map']): + tmp = config.return_value(vrf_base + ['protocols', 'ospfv3', 'route-map']) + + config.set(vrf_base + ['ipv6', 'protocol', 'ospfv3', 'route-map'], value=tmp) + config.set_tag(vrf_base + ['ipv6', 'protocol', 'ospfv6']) + config.delete(vrf_base + ['protocols', 'ospfv3', 'route-map']) diff --git a/src/migration-scripts/pim/0-to-1 b/src/migration-scripts/pim/0-to-1 index bf8af733c..ce24b23ba 100755..100644 --- a/src/migration-scripts/pim/0-to-1 +++ b/src/migration-scripts/pim/0-to-1 @@ -1,72 +1,54 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5736: igmp: migrate "protocols igmp" to "protocols pim" -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['protocols', 'igmp'] pim_base = ['protocols', 'pim'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -for interface in config.list_nodes(base + ['interface']): - base_igmp_iface = base + ['interface', interface] - pim_base_iface = pim_base + ['interface', interface] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - # Create IGMP note under PIM interface - if not config.exists(pim_base_iface + ['igmp']): - config.set(pim_base_iface + ['igmp']) + for interface in config.list_nodes(base + ['interface']): + base_igmp_iface = base + ['interface', interface] + pim_base_iface = pim_base + ['interface', interface] - if config.exists(base_igmp_iface + ['join']): - config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join']) - config.set_tag(pim_base_iface + ['igmp', 'join']) + # Create IGMP note under PIM interface + if not config.exists(pim_base_iface + ['igmp']): + config.set(pim_base_iface + ['igmp']) - new_join_base = pim_base_iface + ['igmp', 'join'] - for address in config.list_nodes(new_join_base): - if config.exists(new_join_base + [address, 'source']): - config.rename(new_join_base + [address, 'source'], 'source-address') + if config.exists(base_igmp_iface + ['join']): + config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join']) + config.set_tag(pim_base_iface + ['igmp', 'join']) - if config.exists(base_igmp_iface + ['query-interval']): - config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval']) + new_join_base = pim_base_iface + ['igmp', 'join'] + for address in config.list_nodes(new_join_base): + if config.exists(new_join_base + [address, 'source']): + config.rename(new_join_base + [address, 'source'], 'source-address') - if config.exists(base_igmp_iface + ['query-max-response-time']): - config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time']) + if config.exists(base_igmp_iface + ['query-interval']): + config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval']) - if config.exists(base_igmp_iface + ['version']): - config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version']) + if config.exists(base_igmp_iface + ['query-max-response-time']): + config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time']) -config.delete(base) + if config.exists(base_igmp_iface + ['version']): + config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version']) -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)) - sys.exit(1) + config.delete(base) diff --git a/src/migration-scripts/policy/0-to-1 b/src/migration-scripts/policy/0-to-1 index 8508b734a..837946c37 100755..100644 --- a/src/migration-scripts/policy/0-to-1 +++ b/src/migration-scripts/policy/0-to-1 @@ -1,65 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3631: route-map: migrate "set extcommunity-rt" and "set extcommunity-soo" # to "set extcommunity rt|soo" to match FRR syntax - -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): - if not config.exists(base + [route_map, 'rule']): - continue - for rule in config.list_nodes(base + [route_map, 'rule']): - base_rule = base + [route_map, 'rule', rule] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - if config.exists(base_rule + ['set', 'extcommunity-rt']): - tmp = config.return_value(base_rule + ['set', 'extcommunity-rt']) - config.delete(base_rule + ['set', 'extcommunity-rt']) - config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp) + for route_map in config.list_nodes(base): + if not config.exists(base + [route_map, 'rule']): + continue + for rule in config.list_nodes(base + [route_map, 'rule']): + base_rule = base + [route_map, 'rule', rule] + if config.exists(base_rule + ['set', 'extcommunity-rt']): + tmp = config.return_value(base_rule + ['set', 'extcommunity-rt']) + config.delete(base_rule + ['set', 'extcommunity-rt']) + config.set(base_rule + ['set', 'extcommunity', 'rt'], value=tmp) - if config.exists(base_rule + ['set', 'extcommunity-soo']): - tmp = config.return_value(base_rule + ['set', 'extcommunity-soo']) - config.delete(base_rule + ['set', 'extcommunity-soo']) - config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if config.exists(base_rule + ['set', 'extcommunity-soo']): + tmp = config.return_value(base_rule + ['set', 'extcommunity-soo']) + config.delete(base_rule + ['set', 'extcommunity-soo']) + config.set(base_rule + ['set', 'extcommunity', 'soo'], value=tmp) diff --git a/src/migration-scripts/policy/1-to-2 b/src/migration-scripts/policy/1-to-2 index c7a983bba..ba3e48db0 100755..100644 --- a/src/migration-scripts/policy/1-to-2 +++ b/src/migration-scripts/policy/1-to-2 @@ -1,86 +1,67 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4170: rename "policy ipv6-route" to "policy route6" to match common # IPv4/IPv6 schema # T4178: Update tcp flags to use multi value node -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'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -if config.exists(base + ['ipv6-route']): - config.rename(base + ['ipv6-route'],'route6') - config.set_tag(['policy', 'route6']) + if config.exists(base + ['ipv6-route']): + config.rename(base + ['ipv6-route'],'route6') + config.set_tag(['policy', 'route6']) -for route in ['route', 'route6']: - if config.exists(base + [route]): - for name in config.list_nodes(base + [route]): - if config.exists(base + [route, name, 'rule']): - for rule in config.list_nodes(base + [route, name, 'rule']): - rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags'] + for route in ['route', 'route6']: + if config.exists(base + [route]): + for name in config.list_nodes(base + [route]): + if config.exists(base + [route, name, 'rule']): + for rule in config.list_nodes(base + [route, name, 'rule']): + rule_tcp_flags = base + [route, name, 'rule', rule, 'tcp', 'flags'] - if config.exists(rule_tcp_flags): - tmp = config.return_value(rule_tcp_flags) - config.delete(rule_tcp_flags) - for flag in tmp.split(","): + if config.exists(rule_tcp_flags): + tmp = config.return_value(rule_tcp_flags) + config.delete(rule_tcp_flags) for flag in tmp.split(","): - if flag[0] == '!': - config.set(rule_tcp_flags + ['not', flag[1:].lower()]) - else: - config.set(rule_tcp_flags + [flag.lower()]) + for flag in tmp.split(","): + if flag[0] == '!': + config.set(rule_tcp_flags + ['not', flag[1:].lower()]) + else: + config.set(rule_tcp_flags + [flag.lower()]) -if config.exists(['interfaces']): - def if_policy_rename(config, path): - if config.exists(path + ['policy', 'ipv6-route']): - config.rename(path + ['policy', 'ipv6-route'], 'route6') + if config.exists(['interfaces']): + def if_policy_rename(config, path): + if config.exists(path + ['policy', 'ipv6-route']): + config.rename(path + ['policy', 'ipv6-route'], 'route6') - for if_type in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', if_type]): - if_path = ['interfaces', if_type, ifname] - if_policy_rename(config, if_path) + for if_type in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', if_type]): + if_path = ['interfaces', if_type, ifname] + if_policy_rename(config, if_path) - for vif_type in ['vif', 'vif-s']: - if config.exists(if_path + [vif_type]): - for vifname in config.list_nodes(if_path + [vif_type]): - if_policy_rename(config, if_path + [vif_type, vifname]) + for vif_type in ['vif', 'vif-s']: + if config.exists(if_path + [vif_type]): + for vifname in config.list_nodes(if_path + [vif_type]): + if_policy_rename(config, if_path + [vif_type, vifname]) - if config.exists(if_path + [vif_type, vifname, 'vif-c']): - for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']): - if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname]) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if config.exists(if_path + [vif_type, vifname, 'vif-c']): + for vifcname in config.list_nodes(if_path + [vif_type, vifname, 'vif-c']): + if_policy_rename(config, if_path + [vif_type, vifname, 'vif-c', vifcname]) diff --git a/src/migration-scripts/policy/2-to-3 b/src/migration-scripts/policy/2-to-3 index 8a62c8e6f..399a55387 100755..100644 --- a/src/migration-scripts/policy/2-to-3 +++ b/src/migration-scripts/policy/2-to-3 @@ -1,58 +1,38 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3976: change cli # from: set policy route-map FOO rule 10 match ipv6 nexthop 'h:h:h:h:h:h:h:h' # to: set policy route-map FOO rule 10 match ipv6 nexthop address 'h:h:h:h:h:h:h:h' -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): - if not config.exists(base + [route_map, 'rule']): - continue - for rule in config.list_nodes(base + [route_map, 'rule']): - base_rule = base + [route_map, 'rule', rule] - - if config.exists(base_rule + ['match', 'ipv6', 'nexthop']): - tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop']) - config.delete(base_rule + ['match', 'ipv6', 'nexthop']) - config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1)
\ No newline at end of file +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for route_map in config.list_nodes(base): + if not config.exists(base + [route_map, 'rule']): + continue + for rule in config.list_nodes(base + [route_map, 'rule']): + base_rule = base + [route_map, 'rule', rule] + + if config.exists(base_rule + ['match', 'ipv6', 'nexthop']): + tmp = config.return_value(base_rule + ['match', 'ipv6', 'nexthop']) + config.delete(base_rule + ['match', 'ipv6', 'nexthop']) + config.set(base_rule + ['match', 'ipv6', 'nexthop', 'address'], value=tmp) diff --git a/src/migration-scripts/policy/3-to-4 b/src/migration-scripts/policy/3-to-4 index 476fa3af2..5d4959def 100755..100644 --- a/src/migration-scripts/policy/3-to-4 +++ b/src/migration-scripts/policy/3-to-4 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4660: change cli # from: set policy route-map FOO rule 10 set community 'TEXT' @@ -33,9 +32,6 @@ # Multiple value # to: set policy route-map FOO rule 10 set extcommunity [rt|soo] <community> -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree @@ -96,67 +92,52 @@ def extcommunity_migrate(config: ConfigTree, rule: list[str]) -> None: config.set(rule + ['soo'], value=community, replace=False) -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name: str = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base: list[str] = ['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): - if not config.exists(base + [route_map, 'rule']): - continue - for rule in config.list_nodes(base + [route_map, 'rule']): - base_rule: list[str] = base + [route_map, 'rule', rule, 'set'] - - # IF additive presents in coummunity then comm-list is redundant - isAdditive: bool = True - #### Change Set community ######## - if config.exists(base_rule + ['community']): - isAdditive = community_migrate(config, - base_rule + ['community']) - - #### Change Set community-list delete migrate ######## - if config.exists(base_rule + ['comm-list', 'comm-list']): - if isAdditive: - tmp = config.return_value( - base_rule + ['comm-list', 'comm-list']) - config.delete(base_rule + ['comm-list']) - config.set(base_rule + ['community', 'delete'], value=tmp) - else: - config.delete(base_rule + ['comm-list']) - - isAdditive = False - #### Change Set large-community ######## - if config.exists(base_rule + ['large-community']): - isAdditive = community_migrate(config, - base_rule + ['large-community']) - - #### Change Set large-community delete by List ######## - if config.exists(base_rule + ['large-comm-list-delete']): - if isAdditive: - tmp = config.return_value( - base_rule + ['large-comm-list-delete']) - config.delete(base_rule + ['large-comm-list-delete']) - config.set(base_rule + ['large-community', 'delete'], - value=tmp) - else: - config.delete(base_rule + ['large-comm-list-delete']) - - #### Change Set extcommunity ######## - extcommunity_migrate(config, base_rule + ['extcommunity']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for route_map in config.list_nodes(base): + if not config.exists(base + [route_map, 'rule']): + continue + for rule in config.list_nodes(base + [route_map, 'rule']): + base_rule: list[str] = base + [route_map, 'rule', rule, 'set'] + + # IF additive presents in coummunity then comm-list is redundant + isAdditive: bool = True + #### Change Set community ######## + if config.exists(base_rule + ['community']): + isAdditive = community_migrate(config, + base_rule + ['community']) + + #### Change Set community-list delete migrate ######## + if config.exists(base_rule + ['comm-list', 'comm-list']): + if isAdditive: + tmp = config.return_value( + base_rule + ['comm-list', 'comm-list']) + config.delete(base_rule + ['comm-list']) + config.set(base_rule + ['community', 'delete'], value=tmp) + else: + config.delete(base_rule + ['comm-list']) + + isAdditive = False + #### Change Set large-community ######## + if config.exists(base_rule + ['large-community']): + isAdditive = community_migrate(config, + base_rule + ['large-community']) + + #### Change Set large-community delete by List ######## + if config.exists(base_rule + ['large-comm-list-delete']): + if isAdditive: + tmp = config.return_value( + base_rule + ['large-comm-list-delete']) + config.delete(base_rule + ['large-comm-list-delete']) + config.set(base_rule + ['large-community', 'delete'], + value=tmp) + else: + config.delete(base_rule + ['large-comm-list-delete']) + + #### Change Set extcommunity ######## + extcommunity_migrate(config, base_rule + ['extcommunity']) diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5 index 738850f67..0ecfdfd5e 100755..100644 --- a/src/migration-scripts/policy/4-to-5 +++ b/src/migration-scripts/policy/4-to-5 @@ -1,39 +1,24 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T2199: Migrate interface policy nodes to policy route <name> interface <ifname> -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() - base4 = ['policy', 'route'] base6 = ['policy', 'route6'] -config = ConfigTree(config_file) - def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None): """Delete unexpected policy on interfaces in cases when @@ -55,35 +40,6 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None config.delete(if_path + ['policy']) - -if not config.exists(base4) and not config.exists(base6): - # Delete orphaned nodes on interfaces T5941 - for iftype in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', iftype]): - delete_orphaned_interface_policy(config, iftype, ifname) - - if config.exists(['interfaces', iftype, ifname, 'vif']): - for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): - delete_orphaned_interface_policy(config, iftype, ifname, vif=vif) - - if config.exists(['interfaces', iftype, ifname, 'vif-s']): - for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): - delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs) - - if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc) - - 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) - - # Nothing to do - exit(0) - def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None): if_path = ['interfaces', iftype, ifname] ifname_full = ifname @@ -111,25 +67,40 @@ def migrate_interface(config, iftype, ifname, vif=None, vifs=None, vifc=None): config.delete(if_path + ['policy']) -for iftype in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', iftype]): - migrate_interface(config, iftype, ifname) +def migrate(config: ConfigTree) -> None: + if not config.exists(base4) and not config.exists(base6): + # Delete orphaned nodes on interfaces T5941 + for iftype in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', iftype]): + delete_orphaned_interface_policy(config, iftype, ifname) + + if config.exists(['interfaces', iftype, ifname, 'vif']): + for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): + delete_orphaned_interface_policy(config, iftype, ifname, vif=vif) - if config.exists(['interfaces', iftype, ifname, 'vif']): - for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): - migrate_interface(config, iftype, ifname, vif=vif) + if config.exists(['interfaces', iftype, ifname, 'vif-s']): + for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): + delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs) - if config.exists(['interfaces', iftype, ifname, 'vif-s']): - for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): - migrate_interface(config, iftype, ifname, vifs=vifs) + if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc) - if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc) + # Nothing to do + return + + for iftype in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', iftype]): + migrate_interface(config, iftype, ifname) -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) + if config.exists(['interfaces', iftype, ifname, 'vif']): + for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): + migrate_interface(config, iftype, ifname, vif=vif) + + if config.exists(['interfaces', iftype, ifname, 'vif-s']): + for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): + migrate_interface(config, iftype, ifname, vifs=vifs) + + if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + migrate_interface(config, iftype, ifname, vifs=vifs, vifc=vifc) diff --git a/src/migration-scripts/policy/5-to-6 b/src/migration-scripts/policy/5-to-6 index 86287d578..acba0b4be 100755..100644 --- a/src/migration-scripts/policy/5-to-6 +++ b/src/migration-scripts/policy/5-to-6 @@ -1,62 +1,42 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5165: Migrate policy local-route rule <tag> destination|source -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() - base4 = ['policy', 'local-route'] base6 = ['policy', 'local-route6'] -config = ConfigTree(config_file) - -if not config.exists(base4) and not config.exists(base6): - # Nothing to do - exit(0) - -# replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>' -# => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>' -for base in [base4, base6]: - if config.exists(base + ['rule']): - for rule in config.list_nodes(base + ['rule']): - dst_path = base + ['rule', rule, 'destination'] - src_path = base + ['rule', rule, 'source'] - # Destination - if config.exists(dst_path): - for dst_addr in config.return_values(dst_path): - config.set(dst_path + ['address'], value=dst_addr, replace=False) - # Source - if config.exists(src_path): - for src_addr in config.return_values(src_path): - config.set(src_path + ['address'], value=src_addr, replace=False) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base4) and not config.exists(base6): + # Nothing to do + return + + # replace 'policy local-route{v6} rule <tag> destination|source <x.x.x.x>' + # => 'policy local-route{v6} rule <tag> destination|source address <x.x.x.x>' + for base in [base4, base6]: + if config.exists(base + ['rule']): + for rule in config.list_nodes(base + ['rule']): + dst_path = base + ['rule', rule, 'destination'] + src_path = base + ['rule', rule, 'source'] + # Destination + if config.exists(dst_path): + for dst_addr in config.return_values(dst_path): + config.set(dst_path + ['address'], value=dst_addr, replace=False) + # Source + if config.exists(src_path): + for src_addr in config.return_values(src_path): + config.set(src_path + ['address'], value=src_addr, replace=False) diff --git a/src/migration-scripts/policy/6-to-7 b/src/migration-scripts/policy/6-to-7 index cdefc6837..69aa703c5 100755..100644 --- a/src/migration-scripts/policy/6-to-7 +++ b/src/migration-scripts/policy/6-to-7 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5729: Switch to valueless whenever is possible. # From @@ -22,55 +21,36 @@ # set policy [route | route6] ... rule <rule> log # Remove command if log=disable -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'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -for family in ['route', 'route6']: - if config.exists(base + [family]): - - for policy_name in config.list_nodes(base + [family]): - if config.exists(base + [family, policy_name, 'rule']): - for rule in config.list_nodes(base + [family, policy_name, 'rule']): - # Log - if config.exists(base + [family, policy_name, 'rule', rule, 'log']): - log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log']) - config.delete(base + [family, policy_name, 'rule', rule, 'log']) - if log_value == 'enable': - config.set(base + [family, policy_name, 'rule', rule, 'log']) - # State - if config.exists(base + [family, policy_name, 'rule', rule, 'state']): - flag_enable = 'False' - for state in ['established', 'invalid', 'new', 'related']: - if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]): - state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state]) - config.delete(base + [family, policy_name, 'rule', rule, 'state', state]) - if state_value == 'enable': - config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False) - flag_enable = 'True' - if flag_enable == 'False': - config.delete(base + [family, policy_name, 'rule', rule, 'state']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for family in ['route', 'route6']: + if config.exists(base + [family]): + + for policy_name in config.list_nodes(base + [family]): + if config.exists(base + [family, policy_name, 'rule']): + for rule in config.list_nodes(base + [family, policy_name, 'rule']): + # Log + if config.exists(base + [family, policy_name, 'rule', rule, 'log']): + log_value = config.return_value(base + [family, policy_name, 'rule', rule, 'log']) + config.delete(base + [family, policy_name, 'rule', rule, 'log']) + if log_value == 'enable': + config.set(base + [family, policy_name, 'rule', rule, 'log']) + # State + if config.exists(base + [family, policy_name, 'rule', rule, 'state']): + flag_enable = 'False' + for state in ['established', 'invalid', 'new', 'related']: + if config.exists(base + [family, policy_name, 'rule', rule, 'state', state]): + state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state]) + config.delete(base + [family, policy_name, 'rule', rule, 'state', state]) + if state_value == 'enable': + config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False) + flag_enable = 'True' + if flag_enable == 'False': + config.delete(base + [family, policy_name, 'rule', rule, 'state']) diff --git a/src/migration-scripts/policy/7-to-8 b/src/migration-scripts/policy/7-to-8 index 73eece1a6..a887f37fe 100755..100644 --- a/src/migration-scripts/policy/7-to-8 +++ b/src/migration-scripts/policy/7-to-8 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5834: Rename 'enable-default-log' to 'default-log' # From @@ -20,37 +19,18 @@ # To # set policy [route | route 6] <route> default-log -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'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -for family in ['route', 'route6']: - if config.exists(base + [family]): +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return - for policy_name in config.list_nodes(base + [family]): - if config.exists(base + [family, policy_name, 'enable-default-log']): - config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log') + for family in ['route', 'route6']: + if config.exists(base + [family]): -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) + for policy_name in config.list_nodes(base + [family]): + if config.exists(base + [family, policy_name, 'enable-default-log']): + config.rename(base + [family, policy_name, 'enable-default-log'], 'default-log') diff --git a/src/migration-scripts/pppoe-server/0-to-1 b/src/migration-scripts/pppoe-server/0-to-1 index 4d36f8545..8c9a24fbe 100755..100644 --- a/src/migration-scripts/pppoe-server/0-to-1 +++ b/src/migration-scripts/pppoe-server/0-to-1 @@ -1,50 +1,33 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Convert "service pppoe-server authentication radius-server node key" # to: "service pppoe-server authentication radius-server node secret" -from sys import argv, 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() - -ctree = ConfigTree(config_file) base = ['service', 'pppoe-server', 'authentication', 'radius-server'] -if not ctree.exists(base): - # Nothing to do - exit(0) -else: +def migrate(ctree: ConfigTree) -> None: + if not ctree.exists(base): + # Nothing to do + return + nodes = ctree.list_nodes(base) for node in nodes: if ctree.exists(base + [node, 'key']): val = ctree.return_value(base + [node, 'key']) ctree.set(base + [node, 'secret'], value=val, replace=False) ctree.delete(base + [node, 'key']) - - try: - open(file_name,'w').write(ctree.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/pppoe-server/1-to-2 b/src/migration-scripts/pppoe-server/1-to-2 index b266893c0..c9c968bff 100755..100644 --- a/src/migration-scripts/pppoe-server/1-to-2 +++ b/src/migration-scripts/pppoe-server/1-to-2 @@ -1,39 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # change mppe node to a leaf node with value prefer -from sys import argv, exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] +base = ['service', 'pppoe-server'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['service', 'pppoe-server'] -if not config.exists(base): - # Nothing to do - exit(0) -else: mppe_base = base + ['ppp-options', 'mppe'] if config.exists(mppe_base): # get current values @@ -49,10 +39,3 @@ else: config.set(mppe_base, value='prefer') elif 'deny' in tmp: config.set(mppe_base, value='deny') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/pppoe-server/2-to-3 b/src/migration-scripts/pppoe-server/2-to-3 index a7be060df..160cffdf8 100755..100644 --- a/src/migration-scripts/pppoe-server/2-to-3 +++ b/src/migration-scripts/pppoe-server/2-to-3 @@ -1,48 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Convert "service pppoe-server interface ethX" to: "service pppoe-server interface ethX {}" -from sys import argv, 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() - -ctree = ConfigTree(config_file) cbase = ['service', 'pppoe-server','interface'] -if not ctree.exists(cbase): - exit(0) -else: +def migrate(ctree: ConfigTree) -> None: + if not ctree.exists(cbase): + return + nics = ctree.return_values(cbase) # convert leafNode to a tagNode ctree.set(cbase) ctree.set_tag(cbase) for nic in nics: ctree.set(cbase + [nic]) - - try: - open(file_name,'w').write(ctree.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/pppoe-server/3-to-4 b/src/migration-scripts/pppoe-server/3-to-4 index 477ed6f22..29dd62201 100755..100644 --- a/src/migration-scripts/pppoe-server/3-to-4 +++ b/src/migration-scripts/pppoe-server/3-to-4 @@ -1,39 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - remove primary/secondary identifier from nameserver -from sys import argv, exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'pppoe-server'] -if not config.exists(base): - # Nothing to do - exit(0) -else: + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return # Migrate IPv4 DNS servers dns_base = base + ['dns-servers'] @@ -130,10 +119,3 @@ else: prefix = p.split(',')[0] mask = p.split(',')[1] config.set(ipv6_base + ['delegate', prefix, 'delegation-prefix'], value=mask) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/pppoe-server/4-to-5 b/src/migration-scripts/pppoe-server/4-to-5 index 5850db673..03fbfb247 100755..100644 --- a/src/migration-scripts/pppoe-server/4-to-5 +++ b/src/migration-scripts/pppoe-server/4-to-5 @@ -1,49 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - rename local-ip to gateway-address from vyos.configtree import ConfigTree -from sys import argv -from sys import exit - -if len(argv) < 2: - print("Must specify file name!") - exit(1) -file_name = argv[1] +base_path = ['service', 'pppoe-server'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return -config = ConfigTree(config_file) -base_path = ['service', 'pppoe-server'] -if not config.exists(base_path): - # Nothing to do - exit(0) -else: config_gw = base_path + ['local-ip'] if config.exists(config_gw): config.rename(config_gw, 'gateway-address') config.delete(config_gw) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) - diff --git a/src/migration-scripts/pppoe-server/5-to-6 b/src/migration-scripts/pppoe-server/5-to-6 index e079ae684..13de8f8d2 100755..100644 --- a/src/migration-scripts/pppoe-server/5-to-6 +++ b/src/migration-scripts/pppoe-server/5-to-6 @@ -1,52 +1,33 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T4703: merge vlan-id and vlan-range to vlan CLI node from vyos.configtree import ConfigTree -from sys import argv -from sys import exit - -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base_path = ['service', 'pppoe-server', 'interface'] -if not config.exists(base_path): - # Nothing to do - exit(0) - -for interface in config.list_nodes(base_path): - for vlan in ['vlan-id', 'vlan-range']: - if config.exists(base_path + [interface, vlan]): - print(interface, vlan) - for tmp in config.return_values(base_path + [interface, vlan]): - config.set(base_path + [interface, 'vlan'], value=tmp, replace=False) - config.delete(base_path + [interface, vlan]) - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return + + for interface in config.list_nodes(base_path): + for vlan in ['vlan-id', 'vlan-range']: + if config.exists(base_path + [interface, vlan]): + print(interface, vlan) + for tmp in config.return_values(base_path + [interface, vlan]): + config.set(base_path + [interface, 'vlan'], value=tmp, replace=False) + config.delete(base_path + [interface, vlan]) diff --git a/src/migration-scripts/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7 index d51c1c9d8..79745a0c6 100755..100644 --- a/src/migration-scripts/pppoe-server/6-to-7 +++ b/src/migration-scripts/pppoe-server/6-to-7 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - move all pool to named pools # 'start-stop' migrate to namedpool 'default-range-pool' @@ -24,94 +23,77 @@ # If there are not named pools, namedless pool will be default. # 2. If authentication mode = 'radius' then namedless pool will be default -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.base import Warning -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'pppoe-server'] pool_base = base + ['client-ip-pool'] -if not config.exists(base): - exit(0) - -if not config.exists(pool_base): - exit(0) - -default_pool = '' -range_pool_name = 'default-range-pool' - -#Default nameless pools migrations -if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): - def is_legalrange(ip1: str, ip2: str, mask: str): - from ipaddress import IPv4Interface - interface1 = IPv4Interface(f'{ip1}/{mask}') - interface2 = IPv4Interface(f'{ip2}/{mask}') - return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip - start_ip = config.return_value(pool_base + ['start']) - stop_ip = config.return_value(pool_base + ['stop']) - if is_legalrange(start_ip, stop_ip, '24'): - ip_range = f'{start_ip}-{stop_ip}' - config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if not config.exists(pool_base): + return + + default_pool = '' + range_pool_name = 'default-range-pool' + + #Default nameless pools migrations + if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): + def is_legalrange(ip1: str, ip2: str, mask: str): + from ipaddress import IPv4Interface + interface1 = IPv4Interface(f'{ip1}/{mask}') + interface2 = IPv4Interface(f'{ip2}/{mask}') + return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip + + start_ip = config.return_value(pool_base + ['start']) + stop_ip = config.return_value(pool_base + ['stop']) + if is_legalrange(start_ip, stop_ip, '24'): + ip_range = f'{start_ip}-{stop_ip}' + config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) + default_pool = range_pool_name + else: + Warning( + f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') + config.delete(pool_base + ['start']) + config.delete(pool_base + ['stop']) + + if config.exists(pool_base + ['subnet']): default_pool = range_pool_name - else: - Warning( - f'PPPoE client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') - config.delete(pool_base + ['start']) - config.delete(pool_base + ['stop']) - -if config.exists(pool_base + ['subnet']): - default_pool = range_pool_name - for subnet in config.return_values(pool_base + ['subnet']): - config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) - config.delete(pool_base + ['subnet']) - -gateway = '' -if config.exists(base + ['gateway-address']): - gateway = config.return_value(base + ['gateway-address']) - -#named pool migration -namedpools_base = pool_base + ['name'] -if config.exists(namedpools_base): - if config.exists(base + ['authentication', 'mode']): - if config.return_value(base + ['authentication', 'mode']) == 'local': - if config.list_nodes(namedpools_base): - default_pool = config.list_nodes(namedpools_base)[0] - - for pool_name in config.list_nodes(namedpools_base): - pool_path = namedpools_base + [pool_name] - if config.exists(pool_path + ['subnet']): - subnet = config.return_value(pool_path + ['subnet']) - config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False) - if config.exists(pool_path + ['next-pool']): - next_pool = config.return_value(pool_path + ['next-pool']) - config.set(pool_base + [pool_name, 'next-pool'], value=next_pool) - if not gateway: - if config.exists(pool_path + ['gateway-address']): - gateway = config.return_value(pool_path + ['gateway-address']) - - config.delete(namedpools_base) - -if gateway: - config.set(base + ['gateway-address'], value=gateway) -if default_pool: - config.set(base + ['default-pool'], value=default_pool) -# format as tag node -config.set_tag(pool_base) - -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) + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) + config.delete(pool_base + ['subnet']) + + gateway = '' + if config.exists(base + ['gateway-address']): + gateway = config.return_value(base + ['gateway-address']) + + #named pool migration + namedpools_base = pool_base + ['name'] + if config.exists(namedpools_base): + if config.exists(base + ['authentication', 'mode']): + if config.return_value(base + ['authentication', 'mode']) == 'local': + if config.list_nodes(namedpools_base): + default_pool = config.list_nodes(namedpools_base)[0] + + for pool_name in config.list_nodes(namedpools_base): + pool_path = namedpools_base + [pool_name] + if config.exists(pool_path + ['subnet']): + subnet = config.return_value(pool_path + ['subnet']) + config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False) + if config.exists(pool_path + ['next-pool']): + next_pool = config.return_value(pool_path + ['next-pool']) + config.set(pool_base + [pool_name, 'next-pool'], value=next_pool) + if not gateway: + if config.exists(pool_path + ['gateway-address']): + gateway = config.return_value(pool_path + ['gateway-address']) + + config.delete(namedpools_base) + + if gateway: + config.set(base + ['gateway-address'], value=gateway) + if default_pool: + config.set(base + ['default-pool'], value=default_pool) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/pppoe-server/7-to-8 b/src/migration-scripts/pppoe-server/7-to-8 index 0381f0bf9..90e4fa053 100755..100644 --- a/src/migration-scripts/pppoe-server/7-to-8 +++ b/src/migration-scripts/pppoe-server/7-to-8 @@ -1,58 +1,40 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrating to named ipv6 pools -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['service', 'pppoe-server'] +pool_base = base + ['client-ipv6-pool'] -file_name = argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -with open(file_name, 'r') as f: - config_file = f.read() + if not config.exists(pool_base): + return -config = ConfigTree(config_file) -base = ['service', 'pppoe-server'] -pool_base = base + ['client-ipv6-pool'] -if not config.exists(base): - exit(0) - -if not config.exists(pool_base): - exit(0) - -ipv6_pool_name = 'ipv6-pool' -config.copy(pool_base, pool_base + [ipv6_pool_name]) - -if config.exists(pool_base + ['prefix']): - config.delete(pool_base + ['prefix']) - config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) -if config.exists(pool_base + ['delegate']): - config.delete(pool_base + ['delegate']) - -# format as tag node -config.set_tag(pool_base) - -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) + ipv6_pool_name = 'ipv6-pool' + config.copy(pool_base, pool_base + [ipv6_pool_name]) + + if config.exists(pool_base + ['prefix']): + config.delete(pool_base + ['prefix']) + config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) + if config.exists(pool_base + ['delegate']): + config.delete(pool_base + ['delegate']) + + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/pppoe-server/8-to-9 b/src/migration-scripts/pppoe-server/8-to-9 index 4932a766f..e7e0aaa2c 100755..100644 --- a/src/migration-scripts/pppoe-server/8-to-9 +++ b/src/migration-scripts/pppoe-server/8-to-9 @@ -1,66 +1,48 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Change from 'ccp' to 'disable-ccp' in ppp-option section # Migration ipv6 options -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'pppoe-server'] -if not config.exists(base): - exit(0) - -#CCP migration -if config.exists(base + ['ppp-options', 'ccp']): - config.delete(base + ['ppp-options', 'ccp']) -else: - config.set(base + ['ppp-options', 'disable-ccp']) - -#IPV6 options migrations -if config.exists(base + ['ppp-options','ipv6-peer-intf-id']): - intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id']) - if intf_peer_id == 'ipv4': - intf_peer_id = 'ipv4-addr' - config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True) - config.delete(base + ['ppp-options','ipv6-peer-intf-id']) - -if config.exists(base + ['ppp-options','ipv6-intf-id']): - intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id']) - config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True) - config.delete(base + ['ppp-options','ipv6-intf-id']) - -if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']): - config.set(base + ['ppp-options','ipv6-accept-peer-interface-id']) - config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id']) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + #CCP migration + if config.exists(base + ['ppp-options', 'ccp']): + config.delete(base + ['ppp-options', 'ccp']) + else: + config.set(base + ['ppp-options', 'disable-ccp']) + + #IPV6 options migrations + if config.exists(base + ['ppp-options','ipv6-peer-intf-id']): + intf_peer_id = config.return_value(base + ['ppp-options','ipv6-peer-intf-id']) + if intf_peer_id == 'ipv4': + intf_peer_id = 'ipv4-addr' + config.set(base + ['ppp-options','ipv6-peer-interface-id'], value=intf_peer_id, replace=True) + config.delete(base + ['ppp-options','ipv6-peer-intf-id']) + + if config.exists(base + ['ppp-options','ipv6-intf-id']): + intf_id = config.return_value(base + ['ppp-options','ipv6-intf-id']) + config.set(base + ['ppp-options','ipv6-interface-id'], value=intf_id, replace=True) + config.delete(base + ['ppp-options','ipv6-intf-id']) + + if config.exists(base + ['ppp-options','ipv6-accept-peer-intf-id']): + config.set(base + ['ppp-options','ipv6-accept-peer-interface-id']) + config.delete(base + ['ppp-options','ipv6-accept-peer-intf-id']) diff --git a/src/migration-scripts/pppoe-server/9-to-10 b/src/migration-scripts/pppoe-server/9-to-10 index e0c782f04..d3475e8ff 100755..100644 --- a/src/migration-scripts/pppoe-server/9-to-10 +++ b/src/migration-scripts/pppoe-server/9-to-10 @@ -1,56 +1,38 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migration of pado-delay options -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['service', 'pppoe-server', 'pado-delay'] -if not config.exists(base): - exit(0) -pado_delay = {} -for delay in config.list_nodes(base): - sessions = config.return_value(base + [delay, 'sessions']) - pado_delay[delay] = sessions +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -# need to define delay for latest sessions -sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1]))) -last_delay = list(sorted_delays)[-1] + pado_delay = {} + for delay in config.list_nodes(base): + sessions = config.return_value(base + [delay, 'sessions']) + pado_delay[delay] = sessions -# Rename last delay -> disable -tmp = base + [last_delay] -if config.exists(tmp): - config.rename(tmp, 'disable') + # need to define delay for latest sessions + sorted_delays = dict(sorted(pado_delay.items(), key=lambda k_v: int(k_v[1]))) + last_delay = list(sorted_delays)[-1] -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) + # Rename last delay -> disable + tmp = base + [last_delay] + if config.exists(tmp): + config.rename(tmp, 'disable') diff --git a/src/migration-scripts/pptp/0-to-1 b/src/migration-scripts/pptp/0-to-1 index 1b7697c11..dd0b6f57e 100755..100644 --- a/src/migration-scripts/pptp/0-to-1 +++ b/src/migration-scripts/pptp/0-to-1 @@ -1,29 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # Unclutter PPTP VPN configuiration - move radius-server top level tag # nodes to a regular node which now also configures the radius source address # used when querying a radius server -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(cfg_base): + # Nothing to do + return -cfg_base = ['vpn', 'pptp', 'remote-access', 'authentication'] -if not config.exists(cfg_base): - # Nothing to do - sys.exit(0) -else: # Migrate "vpn pptp authentication radius-source-address" to new # "vpn pptp authentication radius source-address" if config.exists(cfg_base + ['radius-source-address']): @@ -50,10 +52,3 @@ else: # delete top level tag node if config.exists(cfg_base + ['radius-server']): config.delete(cfg_base + ['radius-server']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/pptp/1-to-2 b/src/migration-scripts/pptp/1-to-2 index 99624dceb..1e7601193 100755..100644 --- a/src/migration-scripts/pptp/1-to-2 +++ b/src/migration-scripts/pptp/1-to-2 @@ -1,41 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - migrate dns-servers node to common name-servers # - remove radios req-limit node -from sys import argv, exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] +base = ['vpn', 'pptp', 'remote-access'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['vpn', 'pptp', 'remote-access'] -if not config.exists(base): - # Nothing to do - exit(0) -else: # Migrate IPv4 DNS servers dns_base = base + ['dns-servers'] if config.exists(dns_base): @@ -62,10 +51,3 @@ else: for server in config.list_nodes(radius_base + ['server']): if config.exists(radius_base + ['server', server, 'req-limit']): config.delete(radius_base + ['server', server, 'req-limit']) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/pptp/2-to-3 b/src/migration-scripts/pptp/2-to-3 index 42c4dedf4..8b0d6d865 100755..100644 --- a/src/migration-scripts/pptp/2-to-3 +++ b/src/migration-scripts/pptp/2-to-3 @@ -1,73 +1,55 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - move all pool to named pools # 'start-stop' migrate to namedpool 'default-range-pool' # 'default-subnet-pool' is the next pool for 'default-range-pool' -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.base import Warning -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'pptp', 'remote-access'] pool_base = base + ['client-ip-pool'] -if not config.exists(base): - exit(0) - -if not config.exists(pool_base): - exit(0) - -range_pool_name = 'default-range-pool' - -if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): - def is_legalrange(ip1: str, ip2: str, mask: str): - from ipaddress import IPv4Interface - interface1 = IPv4Interface(f'{ip1}/{mask}') - interface2 = IPv4Interface(f'{ip2}/{mask}') - return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip - - start_ip = config.return_value(pool_base + ['start']) - stop_ip = config.return_value(pool_base + ['stop']) - if is_legalrange(start_ip, stop_ip, '24'): - ip_range = f'{start_ip}-{stop_ip}' - config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) - config.set(base + ['default-pool'], value=range_pool_name) - else: - Warning( - f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') - - config.delete(pool_base + ['start']) - config.delete(pool_base + ['stop']) -# format as tag node -config.set_tag(pool_base) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if not config.exists(pool_base): + return + + range_pool_name = 'default-range-pool' + + if config.exists(pool_base + ['start']) and config.exists(pool_base + ['stop']): + def is_legalrange(ip1: str, ip2: str, mask: str): + from ipaddress import IPv4Interface + interface1 = IPv4Interface(f'{ip1}/{mask}') + interface2 = IPv4Interface(f'{ip2}/{mask}') + return interface1.network.network_address == interface2.network.network_address and interface2.ip > interface1.ip + + start_ip = config.return_value(pool_base + ['start']) + stop_ip = config.return_value(pool_base + ['stop']) + if is_legalrange(start_ip, stop_ip, '24'): + ip_range = f'{start_ip}-{stop_ip}' + config.set(pool_base + [range_pool_name, 'range'], value=ip_range, replace=False) + config.set(base + ['default-pool'], value=range_pool_name) + else: + Warning( + f'PPTP client-ip-pool range start-ip:{start_ip} and stop-ip:{stop_ip} can not be migrated.') + + config.delete(pool_base + ['start']) + config.delete(pool_base + ['stop']) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/pptp/3-to-4 b/src/migration-scripts/pptp/3-to-4 index ebd343028..2dabd8475 100755..100644 --- a/src/migration-scripts/pptp/3-to-4 +++ b/src/migration-scripts/pptp/3-to-4 @@ -1,48 +1,29 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - Move 'mppe' from 'authentication' node to 'ppp-options' -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'pptp', 'remote-access'] -if not config.exists(base): - exit(0) - -if config.exists(base + ['authentication','mppe']): - mppe = config.return_value(base + ['authentication','mppe']) - config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True) - config.delete(base + ['authentication','mppe']) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -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) + if config.exists(base + ['authentication','mppe']): + mppe = config.return_value(base + ['authentication','mppe']) + config.set(base + ['ppp-options', 'mppe'], value=mppe, replace=True) + config.delete(base + ['authentication','mppe']) diff --git a/src/migration-scripts/pptp/4-to-5 b/src/migration-scripts/pptp/4-to-5 index 83632b6d8..c906f58c4 100755..100644 --- a/src/migration-scripts/pptp/4-to-5 +++ b/src/migration-scripts/pptp/4-to-5 @@ -1,63 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - Move 'require' from 'protocols' in 'authentication' node # - Migrate to new default values in radius timeout and acct-timeout -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'pptp', 'remote-access'] -if not config.exists(base): - exit(0) - -#migrate require to protocols -require_path = base + ['authentication', 'require'] -if config.exists(require_path): - protocols = list(config.return_values(require_path)) - for protocol in protocols: - config.set(base + ['authentication', 'protocols'], value=protocol, - replace=False) - config.delete(require_path) -else: - config.set(base + ['authentication', 'protocols'], value='mschap-v2') - -radius_path = base + ['authentication', 'radius'] -if config.exists(radius_path): - if not config.exists(radius_path + ['timeout']): - config.set(radius_path + ['timeout'], value=3) - if not config.exists(radius_path + ['acct-timeout']): - config.set(radius_path + ['acct-timeout'], value=3) - - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + #migrate require to protocols + require_path = base + ['authentication', 'require'] + if config.exists(require_path): + protocols = list(config.return_values(require_path)) + for protocol in protocols: + config.set(base + ['authentication', 'protocols'], value=protocol, + replace=False) + config.delete(require_path) + else: + config.set(base + ['authentication', 'protocols'], value='mschap-v2') + + radius_path = base + ['authentication', 'radius'] + if config.exists(radius_path): + if not config.exists(radius_path + ['timeout']): + config.set(radius_path + ['timeout'], value=3) + if not config.exists(radius_path + ['acct-timeout']): + config.set(radius_path + ['acct-timeout'], value=3) diff --git a/src/migration-scripts/qos/1-to-2 b/src/migration-scripts/qos/1-to-2 index 666811e5a..c43d8fa47 100755..100644 --- a/src/migration-scripts/qos/1-to-2 +++ b/src/migration-scripts/qos/1-to-2 @@ -1,20 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -from sys import argv,exit +# 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/>. from vyos.base import Warning from vyos.configtree import ConfigTree @@ -28,18 +25,6 @@ def bandwidth_percent_to_val(interface, percent) -> int: speed = int(speed) *1000000 # convert to MBit/s return speed * int(percent) // 100 # integer division -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 = ['traffic-policy'] -config = ConfigTree(config_file) - def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None): """Delete unexpected traffic-policy on interfaces in cases when @@ -62,133 +47,122 @@ def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None config.delete(if_path + ['traffic-policy']) -if not config.exists(base): - # Delete orphaned nodes on interfaces T5941 - for iftype in config.list_nodes(['interfaces']): - for ifname in config.list_nodes(['interfaces', iftype]): - delete_orphaned_interface_policy(config, iftype, ifname) - - if config.exists(['interfaces', iftype, ifname, 'vif']): - for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): - delete_orphaned_interface_policy(config, iftype, ifname, vif=vif) - - if config.exists(['interfaces', iftype, ifname, 'vif-s']): - for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): - delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs) - - if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): - delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc) - - 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) - - # Nothing to do - exit(0) - -iface_config = {} - -if config.exists(['interfaces']): - def get_qos(config, interface, interface_base): - if config.exists(interface_base): - tmp = { interface : {} } - if config.exists(interface_base + ['in']): - tmp[interface]['ingress'] = config.return_value(interface_base + ['in']) - if config.exists(interface_base + ['out']): - tmp[interface]['egress'] = config.return_value(interface_base + ['out']) - config.delete(interface_base) - return tmp - return None - - # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress" - for type in config.list_nodes(['interfaces']): - for interface in config.list_nodes(['interfaces', type]): - interface_base = ['interfaces', type, interface, 'traffic-policy'] - tmp = get_qos(config, interface, interface_base) - if tmp: iface_config.update(tmp) - - vif_path = ['interfaces', type, interface, 'vif'] - if config.exists(vif_path): - for vif in config.list_nodes(vif_path): - vif_interface_base = vif_path + [vif, 'traffic-policy'] - ifname = f'{interface}.{vif}' - tmp = get_qos(config, ifname, vif_interface_base) - if tmp: iface_config.update(tmp) - - vif_s_path = ['interfaces', type, interface, 'vif-s'] - if config.exists(vif_s_path): - for vif_s in config.list_nodes(vif_s_path): - vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy'] - ifname = f'{interface}.{vif_s}' - tmp = get_qos(config, ifname, vif_s_interface_base) - if tmp: iface_config.update(tmp) - - # vif-c interfaces MUST be migrated before their parent vif-s - # interface as the migrate_*() functions delete the path! - vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] - if config.exists(vif_c_path): - for vif_c in config.list_nodes(vif_c_path): - vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy'] - ifname = f'{interface}.{vif_s}.{vif_c}' - tmp = get_qos(config, ifname, vif_s_interface_base) - if tmp: iface_config.update(tmp) - - -# Now we have the information which interface uses which QoS policy. -# Interface binding will be moved to the qos CLi tree -config.set(['qos']) -config.copy(base, ['qos', 'policy']) -config.delete(base) - -# Now map the interface policy binding to the new CLI syntax -if len(iface_config): - config.set(['qos', 'interface']) - config.set_tag(['qos', 'interface']) - -for interface, interface_config in iface_config.items(): - config.set(['qos', 'interface', interface]) - config.set_tag(['qos', 'interface', interface]) - if 'ingress' in interface_config: - config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress']) - if 'egress' in interface_config: - config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress']) - -# Remove "burst" CLI node from network emulator -netem_base = ['qos', 'policy', 'network-emulator'] -if config.exists(netem_base): - for policy_name in config.list_nodes(netem_base): - if config.exists(netem_base + [policy_name, 'burst']): - config.delete(netem_base + [policy_name, 'burst']) - -# Change bandwidth unit MBit -> mbit as tc only supports mbit -base = ['qos', 'policy'] -if config.exists(base): - for policy_type in config.list_nodes(base): - for policy in config.list_nodes(base + [policy_type]): - policy_base = base + [policy_type, policy] - if config.exists(policy_base + ['bandwidth']): - tmp = config.return_value(policy_base + ['bandwidth']) - config.set(policy_base + ['bandwidth'], value=tmp.lower()) - - if config.exists(policy_base + ['class']): - for cls in config.list_nodes(policy_base + ['class']): - cls_base = policy_base + ['class', cls] - if config.exists(cls_base + ['bandwidth']): - tmp = config.return_value(cls_base + ['bandwidth']) - config.set(cls_base + ['bandwidth'], value=tmp.lower()) - - if config.exists(policy_base + ['default', 'bandwidth']): +def migrate(config: ConfigTree) -> None: + base = ['traffic-policy'] + + if not config.exists(base): + # Delete orphaned nodes on interfaces T5941 + for iftype in config.list_nodes(['interfaces']): + for ifname in config.list_nodes(['interfaces', iftype]): + delete_orphaned_interface_policy(config, iftype, ifname) + + if config.exists(['interfaces', iftype, ifname, 'vif']): + for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']): + delete_orphaned_interface_policy(config, iftype, ifname, vif=vif) + + if config.exists(['interfaces', iftype, ifname, 'vif-s']): + for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']): + delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs) + + if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']): + delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc) + + # Nothing to do + return + + iface_config = {} + + if config.exists(['interfaces']): + def get_qos(config, interface, interface_base): + if config.exists(interface_base): + tmp = { interface : {} } + if config.exists(interface_base + ['in']): + tmp[interface]['ingress'] = config.return_value(interface_base + ['in']) + if config.exists(interface_base + ['out']): + tmp[interface]['egress'] = config.return_value(interface_base + ['out']) + config.delete(interface_base) + return tmp + return None + + # Migrate "interface ethernet eth0 traffic-policy in|out" to "qos interface eth0 ingress|egress" + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + interface_base = ['interfaces', type, interface, 'traffic-policy'] + tmp = get_qos(config, interface, interface_base) + if tmp: iface_config.update(tmp) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_interface_base = vif_path + [vif, 'traffic-policy'] + ifname = f'{interface}.{vif}' + tmp = get_qos(config, ifname, vif_interface_base) + if tmp: iface_config.update(tmp) + + vif_s_path = ['interfaces', type, interface, 'vif-s'] + if config.exists(vif_s_path): + for vif_s in config.list_nodes(vif_s_path): + vif_s_interface_base = vif_s_path + [vif_s, 'traffic-policy'] + ifname = f'{interface}.{vif_s}' + tmp = get_qos(config, ifname, vif_s_interface_base) + if tmp: iface_config.update(tmp) + + # vif-c interfaces MUST be migrated before their parent vif-s + # interface as the migrate_*() functions delete the path! + vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] + if config.exists(vif_c_path): + for vif_c in config.list_nodes(vif_c_path): + vif_c_interface_base = vif_c_path + [vif_c, 'traffic-policy'] + ifname = f'{interface}.{vif_s}.{vif_c}' + tmp = get_qos(config, ifname, vif_s_interface_base) + if tmp: iface_config.update(tmp) + + + # Now we have the information which interface uses which QoS policy. + # Interface binding will be moved to the qos CLi tree + config.set(['qos']) + config.copy(base, ['qos', 'policy']) + config.delete(base) + + # Now map the interface policy binding to the new CLI syntax + if len(iface_config): + config.set(['qos', 'interface']) + config.set_tag(['qos', 'interface']) + + for interface, interface_config in iface_config.items(): + config.set(['qos', 'interface', interface]) + config.set_tag(['qos', 'interface', interface]) + if 'ingress' in interface_config: + config.set(['qos', 'interface', interface, 'ingress'], value=interface_config['ingress']) + if 'egress' in interface_config: + config.set(['qos', 'interface', interface, 'egress'], value=interface_config['egress']) + + # Remove "burst" CLI node from network emulator + netem_base = ['qos', 'policy', 'network-emulator'] + if config.exists(netem_base): + for policy_name in config.list_nodes(netem_base): + if config.exists(netem_base + [policy_name, 'burst']): + config.delete(netem_base + [policy_name, 'burst']) + + # Change bandwidth unit MBit -> mbit as tc only supports mbit + base = ['qos', 'policy'] + if config.exists(base): + for policy_type in config.list_nodes(base): + for policy in config.list_nodes(base + [policy_type]): + policy_base = base + [policy_type, policy] + if config.exists(policy_base + ['bandwidth']): + tmp = config.return_value(policy_base + ['bandwidth']) + config.set(policy_base + ['bandwidth'], value=tmp.lower()) + + if config.exists(policy_base + ['class']): + for cls in config.list_nodes(policy_base + ['class']): + cls_base = policy_base + ['class', cls] + if config.exists(cls_base + ['bandwidth']): + tmp = config.return_value(cls_base + ['bandwidth']) + config.set(cls_base + ['bandwidth'], value=tmp.lower()) + if config.exists(policy_base + ['default', 'bandwidth']): - tmp = config.return_value(policy_base + ['default', 'bandwidth']) - config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower()) - -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) + if config.exists(policy_base + ['default', 'bandwidth']): + tmp = config.return_value(policy_base + ['default', 'bandwidth']) + config.set(policy_base + ['default', 'bandwidth'], value=tmp.lower()) diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11 index 0ed4f5df6..15dbbb193 100755..100644 --- a/src/migration-scripts/quagga/10-to-11 +++ b/src/migration-scripts/quagga/10-to-11 @@ -1,51 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5150: Rework CLI definitions to apply route-maps between routing daemons # and zebra/kernel -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - static_base = ['protocols', 'static'] -# Check if static routes are configured - if so, migrate the CLI node -if config.exists(static_base): - if config.exists(static_base + ['route-map']): - tmp = config.return_value(static_base + ['route-map']) - config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp) - config.set_tag(['system', 'ip', 'protocol']) - config.delete(static_base + ['route-map']) +def migrate(config: ConfigTree) -> None: + # Check if static routes are configured - if so, migrate the CLI node + if config.exists(static_base): + if config.exists(static_base + ['route-map']): + tmp = config.return_value(static_base + ['route-map']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + config.set(['system', 'ip', 'protocol', 'static', 'route-map'], value=tmp) + config.set_tag(['system', 'ip', 'protocol']) + config.delete(static_base + ['route-map']) diff --git a/src/migration-scripts/quagga/2-to-3 b/src/migration-scripts/quagga/2-to-3 index 96b56da70..d62c387ba 100755..100644 --- a/src/migration-scripts/quagga/2-to-3 +++ b/src/migration-scripts/quagga/2-to-3 @@ -1,37 +1,21 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2018 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. -# +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # - -import sys +# 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/>. from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - def migrate_neighbor(config, neighbor_path, neighbor): if config.exists(neighbor_path): neighbors = config.list_nodes(neighbor_path) @@ -117,10 +101,11 @@ def migrate_neighbor(config, neighbor_path, neighbor): config.delete(neighbor_path + [neighbor, 'disable-send-community']) -if not config.exists(['protocols', 'bgp']): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(['protocols', 'bgp']): + # Nothing to do + return + # Just to avoid writing it so many times af_path = ['address-family', 'ipv4-unicast'] @@ -132,7 +117,7 @@ else: bgp_path = ['protocols', 'bgp', asn] else: # There's actually no BGP, just its empty shell - sys.exit(0) + return ## Move global IPv4-specific BGP options to "address-family ipv4-unicast" @@ -194,10 +179,3 @@ else: config.set(bgp_path + af_path + ['redistribute', redistribute, 'route-map'], value=redist_route_map) config.delete(redistribute_path) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/quagga/3-to-4 b/src/migration-scripts/quagga/3-to-4 index 1e8c8e2f2..81cf139f6 100755..100644 --- a/src/migration-scripts/quagga/3-to-4 +++ b/src/migration-scripts/quagga/3-to-4 @@ -1,20 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. -# +# 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/>. # Between 1.2.3 and 1.2.4, FRR added per-neighbor enforce-first-as option. # Unfortunately they also removed the global enforce-first-as option, @@ -23,26 +20,14 @@ # To emulate the effect of the original option, we insert it in every neighbor # if the config used to have the original global option -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(['protocols', 'bgp']): + # Nothing to do + return -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['protocols', 'bgp']): - # Nothing to do - sys.exit(0) -else: # Check if BGP is actually configured and obtain the ASN asn_list = config.list_nodes(['protocols', 'bgp']) if asn_list: @@ -50,7 +35,7 @@ else: asn = asn_list[0] else: # There's actually no BGP, just its empty shell - sys.exit(0) + return # Check if BGP enforce-first-as option is set enforce_first_as_path = ['protocols', 'bgp', asn, 'parameters', 'enforce-first-as'] @@ -64,13 +49,4 @@ else: config.set(['protocols', 'bgp', asn, 'neighbor', p, 'enforce-first-as']) else: # Do nothing - sys.exit(0) - - # Save a new configuration file - 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)) - sys.exit(1) - + return diff --git a/src/migration-scripts/quagga/4-to-5 b/src/migration-scripts/quagga/4-to-5 index fcb496a9c..27b995431 100755..100644 --- a/src/migration-scripts/quagga/4-to-5 +++ b/src/migration-scripts/quagga/4-to-5 @@ -1,41 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2019 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. # -# - -import sys +# 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/>. from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(['protocols', 'bgp']): + # Nothing to do + return -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['protocols', 'bgp']): - # Nothing to do - sys.exit(0) -else: # Check if BGP is actually configured and obtain the ASN asn_list = config.list_nodes(['protocols', 'bgp']) if asn_list: @@ -43,7 +28,7 @@ else: asn = asn_list[0] else: # There's actually no BGP, just its empty shell - sys.exit(0) + return # Check if BGP scan-time parameter exist scan_time_param = ['protocols', 'bgp', asn, 'parameters', 'scan-time'] @@ -52,12 +37,4 @@ else: config.delete(scan_time_param) else: # Do nothing - sys.exit(0) - - # Save a new configuration file - 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)) - sys.exit(1) + return diff --git a/src/migration-scripts/quagga/5-to-6 b/src/migration-scripts/quagga/5-to-6 index f075fc2e7..08fd070de 100755..100644 --- a/src/migration-scripts/quagga/5-to-6 +++ b/src/migration-scripts/quagga/5-to-6 @@ -1,42 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -# * Remove parameter 'disable-network-import-check' which, as implemented, -# had no effect on boot. - -import sys +# 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/>. from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(['protocols', 'bgp']): + # Nothing to do + return -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -if not config.exists(['protocols', 'bgp']): - # Nothing to do - sys.exit(0) -else: # Check if BGP is actually configured and obtain the ASN asn_list = config.list_nodes(['protocols', 'bgp']) if asn_list: @@ -44,7 +28,7 @@ else: asn = asn_list[0] else: # There's actually no BGP, just its empty shell - sys.exit(0) + return # Check if BGP parameter disable-network-import-check exists param = ['protocols', 'bgp', asn, 'parameters', 'disable-network-import-check'] @@ -53,11 +37,4 @@ else: config.delete(param) else: # Do nothing - sys.exit(0) - - 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)) - sys.exit(1) + return diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7 index ed295a95c..095baac03 100755..100644 --- a/src/migration-scripts/quagga/6-to-7 +++ b/src/migration-scripts/quagga/6-to-7 @@ -1,116 +1,97 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in # FRR, there is only a base, per neighbor dynamic capability, migrate config -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.template import is_ipv4 from vyos.template import is_ipv6 -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 = ['protocols', 'bgp'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# Check if BGP is actually configured and obtain the ASN -asn_list = config.list_nodes(base) -if asn_list: - # There's always just one BGP node, if any - bgp_base = base + [asn_list[0]] - - for neighbor_type in ['neighbor', 'peer-group']: - if not config.exists(bgp_base + [neighbor_type]): - continue - for neighbor in config.list_nodes(bgp_base + [neighbor_type]): - # T2844 - add IPv4 AFI disable-send-community support - send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community'] - if config.exists(send_comm_path): - new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast'] - config.set(new_base) - config.copy(send_comm_path, new_base + ['disable-send-community']) - config.delete(send_comm_path) - - cap_dynamic = False - peer_group = None - for afi in ['ipv4-unicast', 'ipv6-unicast']: - afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi] - # Exit loop early if AFI does not exist - if not config.exists(afi_path): - continue - - cap_path = afi_path + ['capability', 'dynamic'] - if config.exists(cap_path): - cap_dynamic = True - config.delete(cap_path) - - # We have now successfully migrated the address-family - # specific dynamic capability to the neighbor/peer-group - # level. If this has been the only option under the - # address-family nodes, we can clean them up by checking if - # no other nodes are left under that tree and if so, delete - # the parent. - # - # We walk from the most inner node to the most outer one. - cleanup = -1 - while len(config.list_nodes(cap_path[:cleanup])) == 0: - config.delete(cap_path[:cleanup]) - cleanup -= 1 - - peer_group_path = afi_path + ['peer-group'] - if config.exists(peer_group_path): - if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or - (is_ipv6(neighbor) and afi == 'ipv6-unicast')): - peer_group = config.return_value(peer_group_path) - - config.delete(peer_group_path) - - # We have now successfully migrated the address-family - # specific peer-group to the neighbor level. If this has - # been the only option under the address-family nodes, we - # can clean them up by checking if no other nodes are left - # under that tree and if so, delete the parent. - # - # We walk from the most inner node to the most outer one. - cleanup = -1 - while len(config.list_nodes(peer_group_path[:cleanup])) == 0: - config.delete(peer_group_path[:cleanup]) - cleanup -= 1 - - if cap_dynamic: - config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic']) - if peer_group: - config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # Check if BGP is actually configured and obtain the ASN + asn_list = config.list_nodes(base) + if asn_list: + # There's always just one BGP node, if any + bgp_base = base + [asn_list[0]] + + for neighbor_type in ['neighbor', 'peer-group']: + if not config.exists(bgp_base + [neighbor_type]): + continue + for neighbor in config.list_nodes(bgp_base + [neighbor_type]): + # T2844 - add IPv4 AFI disable-send-community support + send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community'] + if config.exists(send_comm_path): + new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast'] + config.set(new_base) + config.copy(send_comm_path, new_base + ['disable-send-community']) + config.delete(send_comm_path) + + cap_dynamic = False + peer_group = None + for afi in ['ipv4-unicast', 'ipv6-unicast']: + afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi] + # Exit loop early if AFI does not exist + if not config.exists(afi_path): + continue + + cap_path = afi_path + ['capability', 'dynamic'] + if config.exists(cap_path): + cap_dynamic = True + config.delete(cap_path) + + # We have now successfully migrated the address-family + # specific dynamic capability to the neighbor/peer-group + # level. If this has been the only option under the + # address-family nodes, we can clean them up by checking if + # no other nodes are left under that tree and if so, delete + # the parent. + # + # We walk from the most inner node to the most outer one. + cleanup = -1 + while len(config.list_nodes(cap_path[:cleanup])) == 0: + config.delete(cap_path[:cleanup]) + cleanup -= 1 + + peer_group_path = afi_path + ['peer-group'] + if config.exists(peer_group_path): + if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or + (is_ipv6(neighbor) and afi == 'ipv6-unicast')): + peer_group = config.return_value(peer_group_path) + + config.delete(peer_group_path) + + # We have now successfully migrated the address-family + # specific peer-group to the neighbor level. If this has + # been the only option under the address-family nodes, we + # can clean them up by checking if no other nodes are left + # under that tree and if so, delete the parent. + # + # We walk from the most inner node to the most outer one. + cleanup = -1 + while len(config.list_nodes(peer_group_path[:cleanup])) == 0: + config.delete(peer_group_path[:cleanup]) + cleanup -= 1 + + if cap_dynamic: + config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic']) + if peer_group: + config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group) diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8 index 8f11bf390..d9de26d15 100755..100644 --- a/src/migration-scripts/quagga/7-to-8 +++ b/src/migration-scripts/quagga/7-to-8 @@ -1,61 +1,42 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T3391: Migrate "maximum-paths" setting from "protocols bgp asn maximum-paths" # under the IPv4 address-family tree. Reason is we currently have no way in # configuring this for IPv6 address-family. This mimics the FRR configuration. -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 = ['protocols', 'bgp'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# Check if BGP is actually configured and obtain the ASN -asn_list = config.list_nodes(base) -if asn_list: - # There's always just one BGP node, if any - bgp_base = base + [asn_list[0]] - - maximum_paths = bgp_base + ['maximum-paths'] - if config.exists(maximum_paths): - for bgp_type in ['ebgp', 'ibgp']: - if config.exists(maximum_paths + [bgp_type]): - new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths'] - config.set(new_base) - config.copy(maximum_paths + [bgp_type], new_base + [bgp_type]) - config.delete(maximum_paths) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # Check if BGP is actually configured and obtain the ASN + asn_list = config.list_nodes(base) + if asn_list: + # There's always just one BGP node, if any + bgp_base = base + [asn_list[0]] + + maximum_paths = bgp_base + ['maximum-paths'] + if config.exists(maximum_paths): + for bgp_type in ['ebgp', 'ibgp']: + if config.exists(maximum_paths + [bgp_type]): + new_base = bgp_base + ['address-family', 'ipv4-unicast', 'maximum-paths'] + config.set(new_base) + config.copy(maximum_paths + [bgp_type], new_base + [bgp_type]) + config.delete(maximum_paths) diff --git a/src/migration-scripts/quagga/8-to-9 b/src/migration-scripts/quagga/8-to-9 index 0f683d5a1..eece6c15d 100755..100644 --- a/src/migration-scripts/quagga/8-to-9 +++ b/src/migration-scripts/quagga/8-to-9 @@ -1,24 +1,20 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T2450: drop interface-route and interface-route6 from "protocols static" -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree def migrate_interface_route(config, base, path, route_route6): @@ -84,54 +80,38 @@ def migrate_route(config, base, path, route_route6): config.rename(vrf_path, 'vrf') -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['protocols', 'static'] -file_name = argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -with open(file_name, 'r') as f: - config_file = f.read() + # Migrate interface-route into route + migrate_interface_route(config, base, ['interface-route'], 'route') -base = ['protocols', 'static'] + # Migrate interface-route6 into route6 + migrate_interface_route(config, base, ['interface-route6'], 'route6') -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) + # Cleanup nodes inside route + migrate_route(config, base, ['route'], 'route') -# Migrate interface-route into route -migrate_interface_route(config, base, ['interface-route'], 'route') + # Cleanup nodes inside route6 + migrate_route(config, base, ['route6'], 'route6') -# Migrate interface-route6 into route6 -migrate_interface_route(config, base, ['interface-route6'], 'route6') + # + # PBR table cleanup + table_path = base + ['table'] + if config.exists(table_path): + for table in config.list_nodes(table_path): + # Migrate interface-route into route + migrate_interface_route(config, table_path + [table], ['interface-route'], 'route') -# Cleanup nodes inside route -migrate_route(config, base, ['route'], 'route') + # Migrate interface-route6 into route6 + migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6') -# Cleanup nodes inside route6 -migrate_route(config, base, ['route6'], 'route6') + # Cleanup nodes inside route + migrate_route(config, table_path + [table], ['route'], 'route') -# -# PBR table cleanup -table_path = base + ['table'] -if config.exists(table_path): - for table in config.list_nodes(table_path): - # Migrate interface-route into route - migrate_interface_route(config, table_path + [table], ['interface-route'], 'route') - - # Migrate interface-route6 into route6 - migrate_interface_route(config, table_path + [table], ['interface-route6'], 'route6') - - # Cleanup nodes inside route - migrate_route(config, table_path + [table], ['route'], 'route') - - # Cleanup nodes inside route6 - migrate_route(config, table_path + [table], ['route6'], 'route6') - -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) + # Cleanup nodes inside route6 + migrate_route(config, table_path + [table], ['route6'], 'route6') diff --git a/src/migration-scripts/quagga/9-to-10 b/src/migration-scripts/quagga/9-to-10 index 3731762f7..4ac1f0b7d 100755..100644 --- a/src/migration-scripts/quagga/9-to-10 +++ b/src/migration-scripts/quagga/9-to-10 @@ -1,62 +1,42 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # 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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + 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) diff --git a/src/migration-scripts/reverse-proxy/0-to-1 b/src/migration-scripts/reverse-proxy/0-to-1 index d61493815..b495474a6 100755..100644 --- a/src/migration-scripts/reverse-proxy/0-to-1 +++ b/src/migration-scripts/reverse-proxy/0-to-1 @@ -1,48 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6409: Remove unused 'backend bk-example parameters' node -from sys import argv, exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['load-balancing', 'reverse-proxy', 'backend'] -if not config.exists(base): - # Nothing to do - exit(0) -# we need to run this for every configured network -for backend in config.list_nodes(base): - param_node = base + [backend, 'parameters'] - if config.exists(param_node): - config.delete(param_node) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -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) + # we need to run this for every configured network + for backend in config.list_nodes(base): + param_node = base + [backend, 'parameters'] + if config.exists(param_node): + config.delete(param_node) diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1 index 08a866374..6d41bcf58 100755..100644 --- a/src/migration-scripts/rip/0-to-1 +++ b/src/migration-scripts/rip/0-to-1 @@ -1,51 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T5150: Rework CLI definitions to apply route-maps between routing daemons # and zebra/kernel -from sys import argv -from sys import exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - ripng_base = ['protocols', 'ripng'] -# Check if RIPng is configured - if so, migrate the CLI node -if config.exists(ripng_base): - if config.exists(ripng_base + ['route-map']): - tmp = config.return_value(ripng_base + ['route-map']) - config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp) - config.set_tag(['system', 'ipv6', 'protocol']) - config.delete(ripng_base + ['route-map']) +def migrate(config: ConfigTree) -> None: + # Check if RIPng is configured - if so, migrate the CLI node + if config.exists(ripng_base): + if config.exists(ripng_base + ['route-map']): + tmp = config.return_value(ripng_base + ['route-map']) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + config.set(['system', 'ipv6', 'protocol', 'ripng', 'route-map'], value=tmp) + config.set_tag(['system', 'ipv6', 'protocol']) + config.delete(ripng_base + ['route-map']) diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1 index a7b5d07d5..b6e781fa9 100755..100644 --- a/src/migration-scripts/rpki/0-to-1 +++ b/src/migration-scripts/rpki/0-to-1 @@ -1,63 +1,44 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import exit -from sys import argv 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 = ['protocols', 'rpki'] -config = ConfigTree(config_file) - -# Nothing to do -if not config.exists(base): - exit(0) - -if config.exists(base + ['cache']): - preference = 1 - for cache in config.list_nodes(base + ['cache']): - address_node = base + ['cache', cache, 'address'] - if config.exists(address_node): - address = config.return_value(address_node) - # We do not longer support the address leafNode, RPKI cache server - # IP address is now used from the tagNode - config.delete(address_node) - # VyOS 1.2 had no per instance preference, setting new defaults - config.set(base + ['cache', cache, 'preference'], value=preference) - # Increase preference for the next caching peer - actually VyOS 1.2 - # supported only one but better save then sorry (T3253) - preference += 1 - - # T3293: If the RPKI cache name equals the configured address, - # renaming is not possible, as rename expects the new path to not - # exist. - if not config.exists(base + ['cache', address]): - config.rename(base + ['cache', cache], address) -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) +def migrate(config: ConfigTree) -> None: + # Nothing to do + if not config.exists(base): + return + + if config.exists(base + ['cache']): + preference = 1 + for cache in config.list_nodes(base + ['cache']): + address_node = base + ['cache', cache, 'address'] + if config.exists(address_node): + address = config.return_value(address_node) + # We do not longer support the address leafNode, RPKI cache server + # IP address is now used from the tagNode + config.delete(address_node) + # VyOS 1.2 had no per instance preference, setting new defaults + config.set(base + ['cache', cache, 'preference'], value=preference) + # Increase preference for the next caching peer - actually VyOS 1.2 + # supported only one but better save then sorry (T3253) + preference += 1 + + # T3293: If the RPKI cache name equals the configured address, + # renaming is not possible, as rename expects the new path to not + # exist. + if not config.exists(base + ['cache', address]): + config.rename(base + ['cache', cache], address) diff --git a/src/migration-scripts/rpki/1-to-2 b/src/migration-scripts/rpki/1-to-2 index 50d4a3dfc..855236d6c 100755..100644 --- a/src/migration-scripts/rpki/1-to-2 +++ b/src/migration-scripts/rpki/1-to-2 @@ -1,73 +1,53 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T6011: rpki: known-hosts-file is no longer supported bxy FRR CLI, # remove VyOS CLI node -from sys import exit -from sys import argv - from vyos.configtree import ConfigTree from vyos.pki import OPENSSH_KEY_BEGIN from vyos.pki import OPENSSH_KEY_END from vyos.utils.file import read_file -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - base = ['protocols', 'rpki'] -config = ConfigTree(config_file) - -# Nothing to do -if not config.exists(base): - exit(0) - -if config.exists(base + ['cache']): - for cache in config.list_nodes(base + ['cache']): - ssh_node = base + ['cache', cache, 'ssh'] - if config.exists(ssh_node + ['known-hosts-file']): - config.delete(ssh_node + ['known-hosts-file']) - - if config.exists(base + ['cache', cache, 'ssh']): - private_key_node = base + ['cache', cache, 'ssh', 'private-key-file'] - private_key_file = config.return_value(private_key_node) - private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','') - - public_key_node = base + ['cache', cache, 'ssh', 'public-key-file'] - public_key_file = config.return_value(public_key_node) - public_key = read_file(public_key_file).split() - - config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key) - config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1]) - config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0]) - config.set_tag(['pki', 'openssh']) - config.set(ssh_node + ['key'], value=f'rpki-{cache}') - - config.delete(private_key_node) - config.delete(public_key_node) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) +def migrate(config: ConfigTree) -> None: + # Nothing to do + if not config.exists(base): + return + + if config.exists(base + ['cache']): + for cache in config.list_nodes(base + ['cache']): + ssh_node = base + ['cache', cache, 'ssh'] + if config.exists(ssh_node + ['known-hosts-file']): + config.delete(ssh_node + ['known-hosts-file']) + + if config.exists(base + ['cache', cache, 'ssh']): + private_key_node = base + ['cache', cache, 'ssh', 'private-key-file'] + private_key_file = config.return_value(private_key_node) + private_key = read_file(private_key_file).replace(OPENSSH_KEY_BEGIN, '').replace(OPENSSH_KEY_END, '').replace('\n','') + + public_key_node = base + ['cache', cache, 'ssh', 'public-key-file'] + public_key_file = config.return_value(public_key_node) + public_key = read_file(public_key_file).split() + + config.set(['pki', 'openssh', f'rpki-{cache}', 'private', 'key'], value=private_key) + config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'key'], value=public_key[1]) + config.set(['pki', 'openssh', f'rpki-{cache}', 'public', 'type'], value=public_key[0]) + config.set_tag(['pki', 'openssh']) + config.set(ssh_node + ['key'], value=f'rpki-{cache}') + + config.delete(private_key_node) + config.delete(public_key_node) diff --git a/src/migration-scripts/salt/0-to-1 b/src/migration-scripts/salt/0-to-1 index 481d9de8f..3990a88dc 100755..100644 --- a/src/migration-scripts/salt/0-to-1 +++ b/src/migration-scripts/salt/0-to-1 @@ -1,43 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Delete log_file, log_level and user nodes # rename hash_type to hash # rename mine_interval to interval -from sys import argv,exit - from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['service', 'salt-minion'] -if not config.exists(base): - # Nothing to do - exit(0) -else: + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return # delete nodes which are now populated with sane defaults for node in ['log_file', 'log_level', 'user']: @@ -49,10 +36,3 @@ else: if config.exists(base + ['mine_interval']): config.rename(base + ['mine_interval'], 'interval') - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) diff --git a/src/migration-scripts/snmp/0-to-1 b/src/migration-scripts/snmp/0-to-1 index b1e61b958..03b190cb7 100755..100644 --- a/src/migration-scripts/snmp/0-to-1 +++ b/src/migration-scripts/snmp/0-to-1 @@ -1,38 +1,27 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2019 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) config_base = ['service', 'snmp', 'v3'] -if not config.exists(config_base): - # Nothing to do - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(config_base): + # Nothing to do + return + # we no longer support a per trap target engine ID (https://vyos.dev/T818) if config.exists(config_base + ['v3', 'trap-target']): for target in config.list_nodes(config_base + ['v3', 'trap-target']): @@ -47,10 +36,3 @@ else: # https://vyos.dev/T1769 if config.exists(config_base + ['v3', 'tsm']): config.delete(config_base + ['v3', 'tsm']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/snmp/1-to-2 b/src/migration-scripts/snmp/1-to-2 index e02cd1aa1..0120f8acb 100755..100644 --- a/src/migration-scripts/snmp/1-to-2 +++ b/src/migration-scripts/snmp/1-to-2 @@ -1,22 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv, exit from vyos.configtree import ConfigTree +# We no longer support hashed values prefixed with '0x' to unclutter +# CLI and also calculate the hases in advance instead of retrieving +# them after service startup - which was always a bad idea +prefix = '0x' + def migrate_keys(config, path): # authentication: rename node 'encrypted-key' -> 'encrypted-password' config_path_auth = path + ['auth', 'encrypted-key'] @@ -42,48 +45,26 @@ def migrate_keys(config, path): tmp = tmp.replace(prefix, '') config.set(config_path_priv, value=tmp) -if __name__ == '__main__': - if len(argv) < 2: - print("Must specify file name!") - exit(1) - - file_name = argv[1] - - with open(file_name, 'r') as f: - config_file = f.read() - - config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: config_base = ['service', 'snmp', 'v3'] if not config.exists(config_base): # Nothing to do - exit(0) - else: - # We no longer support hashed values prefixed with '0x' to unclutter - # CLI and also calculate the hases in advance instead of retrieving - # them after service startup - which was always a bad idea - prefix = '0x' - - config_engineid = config_base + ['engineid'] - if config.exists(config_engineid): - tmp = config.return_value(config_engineid) - if tmp.startswith(prefix): - tmp = tmp.replace(prefix, '') - config.set(config_engineid, value=tmp) + return - config_user = config_base + ['user'] - if config.exists(config_user): - for user in config.list_nodes(config_user): - migrate_keys(config, config_user + [user]) + config_engineid = config_base + ['engineid'] + if config.exists(config_engineid): + tmp = config.return_value(config_engineid) + if tmp.startswith(prefix): + tmp = tmp.replace(prefix, '') + config.set(config_engineid, value=tmp) - config_trap = config_base + ['trap-target'] - if config.exists(config_trap): - for trap in config.list_nodes(config_trap): - migrate_keys(config, config_trap + [trap]) + config_user = config_base + ['user'] + if config.exists(config_user): + for user in config.list_nodes(config_user): + migrate_keys(config, config_user + [user]) - 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) + config_trap = config_base + ['trap-target'] + if config.exists(config_trap): + for trap in config.list_nodes(config_trap): + migrate_keys(config, config_trap + [trap]) diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3 index ab9b5dcba..6d828b619 100755..100644 --- a/src/migration-scripts/snmp/2-to-3 +++ b/src/migration-scripts/snmp/2-to-3 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T4857: Implement FRR SNMP recomendations # cli changes from: @@ -20,35 +19,15 @@ # To # set service snmp oid-enable ip-forward -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 = ['service snmp'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['oid-enable']): - config.delete(base + ['oid-enable']) - config.set(base + ['oid-enable'], 'ip-forward') +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -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) + if config.exists(base + ['oid-enable']): + config.delete(base + ['oid-enable']) + config.set(base + ['oid-enable'], 'ip-forward') diff --git a/src/migration-scripts/ssh/0-to-1 b/src/migration-scripts/ssh/0-to-1 index 2595599ac..65b68f509 100755..100644 --- a/src/migration-scripts/ssh/0-to-1 +++ b/src/migration-scripts/ssh/0-to-1 @@ -1,32 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 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/>. # Delete "service ssh allow-root" option -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['service', 'ssh', 'allow-root']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['service', 'ssh', 'allow-root']): - # Nothing to do - sys.exit(0) -else: # Delete node with abandoned command config.delete(['service', 'ssh', 'allow-root']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/ssh/1-to-2 b/src/migration-scripts/ssh/1-to-2 index 79d65d7d4..b601db3b4 100755..100644 --- a/src/migration-scripts/ssh/1-to-2 +++ b/src/migration-scripts/ssh/1-to-2 @@ -1,81 +1,63 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # VyOS 1.2 crux allowed configuring a lower or upper case loglevel. This # is no longer supported as the input data is validated and will lead to # an error. If user specifies an upper case logleve, make it lowercase -from sys import argv,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 = ['service', 'ssh'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -path_loglevel = base + ['loglevel'] -if config.exists(path_loglevel): - # red in configured loglevel and convert it to lower case - tmp = config.return_value(path_loglevel).lower() - # VyOS 1.2 had no proper value validation on the CLI thus the - # user could use any arbitrary values - sanitize them - if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']: - tmp = 'info' - config.set(path_loglevel, value=tmp) - -# T4273: migrate ssh cipher list to multi node -path_ciphers = base + ['ciphers'] -if config.exists(path_ciphers): - tmp = [] - # get curtrent cipher list - comma delimited - for cipher in config.return_values(path_ciphers): - tmp.extend(cipher.split(',')) - # delete old cipher suite representation - config.delete(path_ciphers) - - for cipher in tmp: - config.set(path_ciphers, value=cipher, replace=False) - -# T4273: migrate ssh key-exchange list to multi node -path_kex = base + ['key-exchange'] -if config.exists(path_kex): - tmp = [] - # get curtrent cipher list - comma delimited - for kex in config.return_values(path_kex): - tmp.extend(kex.split(',')) - # delete old cipher suite representation - config.delete(path_kex) - - for kex in tmp: - config.set(path_kex, value=kex, replace=False) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + path_loglevel = base + ['loglevel'] + if config.exists(path_loglevel): + # red in configured loglevel and convert it to lower case + tmp = config.return_value(path_loglevel).lower() + # VyOS 1.2 had no proper value validation on the CLI thus the + # user could use any arbitrary values - sanitize them + if tmp not in ['quiet', 'fatal', 'error', 'info', 'verbose']: + tmp = 'info' + config.set(path_loglevel, value=tmp) + + # T4273: migrate ssh cipher list to multi node + path_ciphers = base + ['ciphers'] + if config.exists(path_ciphers): + tmp = [] + # get curtrent cipher list - comma delimited + for cipher in config.return_values(path_ciphers): + tmp.extend(cipher.split(',')) + # delete old cipher suite representation + config.delete(path_ciphers) + + for cipher in tmp: + config.set(path_ciphers, value=cipher, replace=False) + + # T4273: migrate ssh key-exchange list to multi node + path_kex = base + ['key-exchange'] + if config.exists(path_kex): + tmp = [] + # get curtrent cipher list - comma delimited + for kex in config.return_values(path_kex): + tmp.extend(kex.split(',')) + # delete old cipher suite representation + config.delete(path_kex) + + for kex in tmp: + config.set(path_kex, value=kex, replace=False) diff --git a/src/migration-scripts/sstp/0-to-1 b/src/migration-scripts/sstp/0-to-1 index 150127aaf..1bd7d6c6b 100755..100644 --- a/src/migration-scripts/sstp/0-to-1 +++ b/src/migration-scripts/sstp/0-to-1 @@ -1,19 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - +# 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/>. # - migrate from "service sstp-server" to "vpn sstp" # - remove primary/secondary identifier from nameserver @@ -23,25 +21,15 @@ # - do not migrate radius server req-limit, use default of unlimited # - migrate SSL certificate path -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +old_base = ['service', 'sstp-server'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(old_base): + # Nothing to do + return -config = ConfigTree(config_file) -old_base = ['service', 'sstp-server'] -if not config.exists(old_base): - # Nothing to do - sys.exit(0) -else: # ensure new base path exists if not config.exists(['vpn']): config.set(['vpn']) @@ -119,10 +107,3 @@ else: if config.exists(new_ssl + ['server-key']): config.rename(new_ssl + ['server-key'], 'key-file') - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/sstp/1-to-2 b/src/migration-scripts/sstp/1-to-2 index f7ecbb6d4..2349e3c9f 100755..100644 --- a/src/migration-scripts/sstp/1-to-2 +++ b/src/migration-scripts/sstp/1-to-2 @@ -1,45 +1,35 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - migrate relative path SSL certificate to absolute path, as certs are only # allowed to stored in /config/user-data/sstp/ this is pretty straight # forward move. Delete certificates from source directory import os -import sys from shutil import copy2 from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +base_path = ['vpn', 'sstp', 'ssl'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return -config = ConfigTree(config_file) -base_path = ['vpn', 'sstp', 'ssl'] -if not config.exists(base_path): - # Nothing to do - sys.exit(0) -else: cert_path_old ='/config/user-data/sstp/' cert_path_new ='/config/auth/sstp/' @@ -101,10 +91,3 @@ else: # check if old certificate directory exists but is empty if os.path.isdir(cert_path_old) and not os.listdir(cert_path_old): os.rmdir(cert_path_old) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/sstp/2-to-3 b/src/migration-scripts/sstp/2-to-3 index 245db7ad6..4255a896e 100755..100644 --- a/src/migration-scripts/sstp/2-to-3 +++ b/src/migration-scripts/sstp/2-to-3 @@ -1,41 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - Rename SSTP ppp-settings node to ppp-options to make use of a common # Jinja Template to render Accel-PPP services from vyos.configtree import ConfigTree -from sys import argv -from sys import exit - -if len(argv) < 2: - print("Must specify file name!") - exit(1) -file_name = argv[1] +base_path = ['vpn', 'sstp'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base_path): + # Nothing to do + return -config = ConfigTree(config_file) -base_path = ['vpn', 'sstp'] -if not config.exists(base_path): - # Nothing to do - exit(0) -else: if config.exists(base_path + ['ppp-settings']): config.rename(base_path + ['ppp-settings'], 'ppp-options') @@ -68,11 +57,3 @@ else: config_nw_settings = base_path + ['network-settings'] if config.exists(config_nw_settings): config.delete(config_nw_settings) - - try: - with open(file_name, 'w') as f: - f.write(config.to_string()) - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - exit(1) - diff --git a/src/migration-scripts/sstp/3-to-4 b/src/migration-scripts/sstp/3-to-4 index 5b7757e60..fd10985de 100755..100644 --- a/src/migration-scripts/sstp/3-to-4 +++ b/src/migration-scripts/sstp/3-to-4 @@ -1,25 +1,22 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - Update SSL to use PKI configuration import os -from sys import argv -from sys import exit from vyos.configtree import ConfigTree from vyos.pki import load_certificate from vyos.pki import load_private_key @@ -27,109 +24,93 @@ from vyos.pki import encode_certificate from vyos.pki import encode_private_key from vyos.utils.process import run -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'sstp'] pki_base = ['pki'] -if not config.exists(base): - exit(0) - AUTH_DIR = '/config/auth' def wrapped_pem_to_config_value(pem): return "".join(pem.strip().split("\n")[1:-1]) -if not config.exists(base + ['ssl']): - exit(0) - -x509_base = base + ['ssl'] -pki_name = 'sstp' - -if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - config.set_tag(pki_base + ['ca']) - -if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - config.set_tag(pki_base + ['certificate']) - -if config.exists(x509_base + ['ca-cert-file']): - cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=pki_name) - else: - print(f'Failed to migrate CA certificate on sstp config') - - config.delete(x509_base + ['ca-cert-file']) - -if config.exists(x509_base + ['cert-file']): - cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) - else: - print(f'Failed to migrate certificate on sstp config') - - config.delete(x509_base + ['cert-file']) - -if config.exists(x509_base + ['key-file']): - key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - if key: - key_pem = encode_private_key(key, passphrase=None) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) - else: - print(f'Failed to migrate private key on sstp config') - - config.delete(x509_base + ['key-file']) - -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return + + if not config.exists(base + ['ssl']): + return + + x509_base = base + ['ssl'] + pki_name = 'sstp' + + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + config.set_tag(pki_base + ['ca']) + + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + config.set_tag(pki_base + ['certificate']) + + if config.exists(x509_base + ['ca-cert-file']): + cert_file = config.return_value(x509_base + ['ca-cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=pki_name) + else: + print(f'Failed to migrate CA certificate on sstp config') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['cert-file']): + cert_file = config.return_value(x509_base + ['cert-file']) + cert_path = os.path.join(AUTH_DIR, cert_file) + cert = None + + if os.path.isfile(cert_path): + if not os.access(cert_path, os.R_OK): + run(f'sudo chmod 644 {cert_path}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) + else: + print(f'Failed to migrate certificate on sstp config') + + config.delete(x509_base + ['cert-file']) + + if config.exists(x509_base + ['key-file']): + key_file = config.return_value(x509_base + ['key-file']) + key_path = os.path.join(AUTH_DIR, key_file) + key = None + + if os.path.isfile(key_path): + if not os.access(key_path, os.R_OK): + run(f'sudo chmod 644 {key_path}') + + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) + + if key: + key_pem = encode_private_key(key, passphrase=None) + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + else: + print(f'Failed to migrate private key on sstp config') + + config.delete(x509_base + ['key-file']) diff --git a/src/migration-scripts/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5 index 6907240a0..254e828af 100755..100644 --- a/src/migration-scripts/sstp/4-to-5 +++ b/src/migration-scripts/sstp/4-to-5 @@ -1,59 +1,41 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - move all pool to named pools # 'subnet' migrate to namedpool 'default-subnet-pool' # 'default-subnet-pool' is the next pool for 'default-range-pool' -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base = ['vpn', 'sstp'] pool_base = base + ['client-ip-pool'] -if not config.exists(base): - exit(0) -if not config.exists(pool_base): - exit(0) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -range_pool_name = 'default-range-pool' + if not config.exists(pool_base): + return -if config.exists(pool_base + ['subnet']): - default_pool = range_pool_name - for subnet in config.return_values(pool_base + ['subnet']): - config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) - config.delete(pool_base + ['subnet']) - config.set(base + ['default-pool'], value=default_pool) -# format as tag node -config.set_tag(pool_base) + range_pool_name = 'default-range-pool' -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) + if config.exists(pool_base + ['subnet']): + default_pool = range_pool_name + for subnet in config.return_values(pool_base + ['subnet']): + config.set(pool_base + [range_pool_name, 'range'], value=subnet, replace=False) + config.delete(pool_base + ['subnet']) + config.set(base + ['default-pool'], value=default_pool) + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/sstp/5-to-6 b/src/migration-scripts/sstp/5-to-6 index 43b99044d..fc3cc29b2 100755..100644 --- a/src/migration-scripts/sstp/5-to-6 +++ b/src/migration-scripts/sstp/5-to-6 @@ -1,58 +1,40 @@ -#!/usr/bin/env python3 +# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Migrating to named ipv6 pools -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['vpn', 'sstp'] +pool_base = base + ['client-ipv6-pool'] -file_name = argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -with open(file_name, 'r') as f: - config_file = f.read() + if not config.exists(pool_base): + return -config = ConfigTree(config_file) -base = ['vpn', 'sstp'] -pool_base = base + ['client-ipv6-pool'] -if not config.exists(base): - exit(0) - -if not config.exists(pool_base): - exit(0) - -ipv6_pool_name = 'ipv6-pool' -config.copy(pool_base, pool_base + [ipv6_pool_name]) - -if config.exists(pool_base + ['prefix']): - config.delete(pool_base + ['prefix']) - config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) -if config.exists(pool_base + ['delegate']): - config.delete(pool_base + ['delegate']) - -# format as tag node -config.set_tag(pool_base) - -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) + ipv6_pool_name = 'ipv6-pool' + config.copy(pool_base, pool_base + [ipv6_pool_name]) + + if config.exists(pool_base + ['prefix']): + config.delete(pool_base + ['prefix']) + config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name) + if config.exists(pool_base + ['delegate']): + config.delete(pool_base + ['delegate']) + + # format as tag node + config.set_tag(pool_base) diff --git a/src/migration-scripts/system/10-to-11 b/src/migration-scripts/system/10-to-11 index 5d662af40..76d7f23cb 100755..100644 --- a/src/migration-scripts/system/10-to-11 +++ b/src/migration-scripts/system/10-to-11 @@ -1,36 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Operator accounts have been deprecated due to a security issue. Those accounts # will be converted to regular admin accounts. -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) base_level = ['system', 'login', 'user'] -if not config.exists(base_level): - # Nothing to do, which shouldn't happen anyway - # only if you wipe the config and reboot. - sys.exit(0) -else: +def migrate(config: ConfigTree) -> None: + if not config.exists(base_level): + # Nothing to do, which shouldn't happen anyway + # only if you wipe the config and reboot. + return + for user in config.list_nodes(base_level): if config.exists(base_level + [user, 'level']): if config.return_value(base_level + [user, 'level']) == 'operator': config.set(base_level + [user, 'level'], value="admin", replace=True) - - try: - open(file_name,'w').write(config.to_string()) - - except OSError as e: - print("Failed to save the modified config: {}".format(e)) - sys.exit(1) diff --git a/src/migration-scripts/system/11-to-12 b/src/migration-scripts/system/11-to-12 index 880ab56dc..71c359b7e 100755..100644 --- a/src/migration-scripts/system/11-to-12 +++ b/src/migration-scripts/system/11-to-12 @@ -1,28 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Unclutter RADIUS configuration # # Move radius-server top level tag nodes to a regular node which allows us # to specify additional general features for the RADIUS client. -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +cfg_base = ['system', 'login'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])): + # Nothing to do + return -config = ConfigTree(config_file) -cfg_base = ['system', 'login'] -if not (config.exists(cfg_base + ['radius-server']) or config.exists(cfg_base + ['radius-source-address'])): - # Nothing to do - sys.exit(0) -else: # # Migrate "system login radius-source-address" to "system login radius" # @@ -63,10 +67,3 @@ else: # delete top level tag node if config.exists(cfg_base + ['radius-server']): config.delete(cfg_base + ['radius-server']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/12-to-13 b/src/migration-scripts/system/12-to-13 index e6c4e3802..014edba91 100755..100644 --- a/src/migration-scripts/system/12-to-13 +++ b/src/migration-scripts/system/12-to-13 @@ -1,47 +1,44 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # converts 'set system syslog host <address>:<port>' # to 'set system syslog host <address> port <port>' -import sys import re from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) cbase = ['system', 'syslog', 'host'] -if not config.exists(cbase): - sys.exit(0) - -for host in config.list_nodes(cbase): - if re.search(':[0-9]{1,5}$',host): - h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0) - p = re.sub(':', '', re.search(':[0-9]+$', host).group(0)) - config.set(cbase + [h]) - config.set(cbase + [h, 'port'], value=p) - for fac in config.list_nodes(cbase + [host, 'facility']): - config.set(cbase + [h, 'facility', fac]) - config.set_tag(cbase + [h, 'facility']) - if config.exists(cbase + [host, 'facility', fac, 'protocol']): - proto = config.return_value(cbase + [host, 'facility', fac, 'protocol']) - config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto) - if config.exists(cbase + [host, 'facility', fac, 'level']): - lvl = config.return_value(cbase + [host, 'facility', fac, 'level']) - config.set(cbase + [h, 'facility', fac, 'level'], value=lvl) - config.delete(cbase + [host]) - -try: - open(file_name,'w').write(config.to_string()) -except OSError as e: - print("Failed to save the modified config: {}".format(e)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + if not config.exists(cbase): + return + + for host in config.list_nodes(cbase): + if re.search(':[0-9]{1,5}$',host): + h = re.search('^[a-zA-Z\-0-9\.]+', host).group(0) + p = re.sub(':', '', re.search(':[0-9]+$', host).group(0)) + config.set(cbase + [h]) + config.set(cbase + [h, 'port'], value=p) + for fac in config.list_nodes(cbase + [host, 'facility']): + config.set(cbase + [h, 'facility', fac]) + config.set_tag(cbase + [h, 'facility']) + if config.exists(cbase + [host, 'facility', fac, 'protocol']): + proto = config.return_value(cbase + [host, 'facility', fac, 'protocol']) + config.set(cbase + [h, 'facility', fac, 'protocol'], value=proto) + if config.exists(cbase + [host, 'facility', fac, 'level']): + lvl = config.return_value(cbase + [host, 'facility', fac, 'level']) + config.set(cbase + [h, 'facility', fac, 'level'], value=lvl) + config.delete(cbase + [host]) diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14 index 5b781158b..fbbecbcd3 100755..100644 --- a/src/migration-scripts/system/13-to-14 +++ b/src/migration-scripts/system/13-to-14 @@ -1,4 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Fixup non existent time-zones. Some systems have time-zone set to: Los* # (Los_Angeles), Den* (Denver), New* (New_York) ... but those are no real IANA @@ -9,27 +22,18 @@ # Migrate all configured timezones to real IANA assigned timezones! import re -import sys from vyos.configtree import ConfigTree from vyos.utils.process import cmd -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +tz_base = ['system', 'time-zone'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(tz_base): + # Nothing to do + return -config = ConfigTree(config_file) -tz_base = ['system', 'time-zone'] -if not config.exists(tz_base): - # Nothing to do - sys.exit(0) -else: tz = config.return_value(tz_base) # retrieve all valid timezones @@ -61,10 +65,3 @@ else: # replace timezone data is required config.set(tz_base, value=tz) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15 index feaac37de..281809460 100755..100644 --- a/src/migration-scripts/system/14-to-15 +++ b/src/migration-scripts/system/14-to-15 @@ -1,40 +1,37 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. + # Delete 'system ipv6 blacklist' option as the IPv6 module can no longer be # blacklisted as it is required by e.g. WireGuard and thus will always be # loaded. import os -import sys ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf' from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +ip_base = ['system', 'ipv6'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(ip_base): + # Nothing to do + return -config = ConfigTree(config_file) -ip_base = ['system', 'ipv6'] -if not config.exists(ip_base): - # Nothing to do - sys.exit(0) -else: # delete 'system ipv6 blacklist' node if config.exists(ip_base + ['blacklist']): config.delete(ip_base + ['blacklist']) if os.path.isfile(ipv6_blacklist_file): os.unlink(ipv6_blacklist_file) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16 index 2944cdb1e..7db042930 100755..100644 --- a/src/migration-scripts/system/15-to-16 +++ b/src/migration-scripts/system/15-to-16 @@ -1,36 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Make 'system options reboot-on-panic' valueless +# 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/>. -import sys +# Make 'system options reboot-on-panic' valueless from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +base = ['system', 'options'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['system', 'options'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: if config.exists(base + ['reboot-on-panic']): reboot = config.return_value(base + ['reboot-on-panic']) config.delete(base + ['reboot-on-panic']) # create new valueless node if action was true if reboot == "true": config.set(base + ['reboot-on-panic']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17 index afa171a9b..9fb86af88 100755..100644 --- a/src/migration-scripts/system/16-to-17 +++ b/src/migration-scripts/system/16-to-17 @@ -1,18 +1,17 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # * remove "system login user <user> group" node, Why should be add a user to a # 3rd party group when the system is fully managed by CLI? @@ -20,35 +19,18 @@ # This is the only privilege level left and also the default, what is the # sense in keeping this orphaned node? -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +base = ['system', 'login', 'user'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['system', 'login', 'user'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: for user in config.list_nodes(base): if config.exists(base + [user, 'group']): config.delete(base + [user, 'group']) if config.exists(base + [user, 'level']): config.delete(base + [user, 'level']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18 index f6adebb06..323ef4e65 100755..100644 --- a/src/migration-scripts/system/17-to-18 +++ b/src/migration-scripts/system/17-to-18 @@ -1,42 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # remove "system console netconsole" # remove "system console device <device> modem" import os -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] +base = ['system', 'console'] -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config = ConfigTree(config_file) -base = ['system', 'console'] -if not config.exists(base): - # Nothing to do - sys.exit(0) -else: # remove "system console netconsole" (T2561) if config.exists(base + ['netconsole']): config.delete(base + ['netconsole']) @@ -67,10 +57,3 @@ else: config.copy(dev_path, base + ['device', usb_device]) # Delete old USB node from config config.delete(dev_path) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19 index fad1d17a4..5d9788d70 100755..100644 --- a/src/migration-scripts/system/18-to-19 +++ b/src/migration-scripts/system/18-to-19 @@ -1,102 +1,81 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. # migrate disable-dhcp-nameservers (boolean) to name-servers-dhcp <interface> # if disable-dhcp-nameservers is set, just remove it # else retrieve all interface names that have configured dhcp(v6) address and # add them to the new name-servers-dhcp node -from sys import argv, exit from vyos.ifconfig import Interface from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) - -file_name = argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - base = ['system'] -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['disable-dhcp-nameservers']): - config.delete(base + ['disable-dhcp-nameservers']) -else: - dhcp_interfaces = [] - - # go through all interfaces searching for 'address dhcp(v6)?' - for sect in Interface.sections(): - sect_base = ['interfaces', sect] - - if not config.exists(sect_base): - continue - for intf in config.list_nodes(sect_base): - intf_base = sect_base + [intf] - - # try without vlans - if config.exists(intf_base + ['address']): - for addr in config.return_values(intf_base + ['address']): - if addr in ['dhcp', 'dhcpv6']: - dhcp_interfaces.append(intf) - - # try vif - if config.exists(intf_base + ['vif']): - for vif in config.list_nodes(intf_base + ['vif']): - vif_base = intf_base + ['vif', vif] - if config.exists(vif_base + ['address']): - for addr in config.return_values(vif_base + ['address']): - if addr in ['dhcp', 'dhcpv6']: - dhcp_interfaces.append(f'{intf}.{vif}') - - # try vif-s - if config.exists(intf_base + ['vif-s']): - for vif_s in config.list_nodes(intf_base + ['vif-s']): - vif_s_base = intf_base + ['vif-s', vif_s] - if config.exists(vif_s_base + ['address']): - for addr in config.return_values(vif_s_base + ['address']): - if addr in ['dhcp', 'dhcpv6']: - dhcp_interfaces.append(f'{intf}.{vif_s}') - - # try vif-c - if config.exists(intf_base + ['vif-c']): - for vif_c in config.list_nodes(vif_s_base + ['vif-c']): - vif_c_base = vif_s_base + ['vif-c', vif_c] - if config.exists(vif_c_base + ['address']): - for addr in config.return_values(vif_c_base + ['address']): +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['disable-dhcp-nameservers']): + config.delete(base + ['disable-dhcp-nameservers']) + else: + dhcp_interfaces = [] + + # go through all interfaces searching for 'address dhcp(v6)?' + for sect in Interface.sections(): + sect_base = ['interfaces', sect] + + if not config.exists(sect_base): + continue + + for intf in config.list_nodes(sect_base): + intf_base = sect_base + [intf] + + # try without vlans + if config.exists(intf_base + ['address']): + for addr in config.return_values(intf_base + ['address']): + if addr in ['dhcp', 'dhcpv6']: + dhcp_interfaces.append(intf) + + # try vif + if config.exists(intf_base + ['vif']): + for vif in config.list_nodes(intf_base + ['vif']): + vif_base = intf_base + ['vif', vif] + if config.exists(vif_base + ['address']): + for addr in config.return_values(vif_base + ['address']): if addr in ['dhcp', 'dhcpv6']: - dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}') - - # set new config nodes - for intf in dhcp_interfaces: - config.set(base + ['name-servers-dhcp'], value=intf, replace=False) - -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) - -exit(0) + dhcp_interfaces.append(f'{intf}.{vif}') + + # try vif-s + if config.exists(intf_base + ['vif-s']): + for vif_s in config.list_nodes(intf_base + ['vif-s']): + vif_s_base = intf_base + ['vif-s', vif_s] + if config.exists(vif_s_base + ['address']): + for addr in config.return_values(vif_s_base + ['address']): + if addr in ['dhcp', 'dhcpv6']: + dhcp_interfaces.append(f'{intf}.{vif_s}') + + # try vif-c + if config.exists(intf_base + ['vif-c']): + for vif_c in config.list_nodes(vif_s_base + ['vif-c']): + vif_c_base = vif_s_base + ['vif-c', vif_c] + if config.exists(vif_c_base + ['address']): + for addr in config.return_values(vif_c_base + ['address']): + if addr in ['dhcp', 'dhcpv6']: + dhcp_interfaces.append(f'{intf}.{vif_s}.{vif_c}') + + # set new config nodes + for intf in dhcp_interfaces: + config.set(base + ['name-servers-dhcp'], value=intf, replace=False) diff --git a/src/migration-scripts/system/19-to-20 b/src/migration-scripts/system/19-to-20 index 177173c50..cb84e11fc 100755..100644 --- a/src/migration-scripts/system/19-to-20 +++ b/src/migration-scripts/system/19-to-20 @@ -1,62 +1,44 @@ -#!/usr/bin/env python3 +# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3048: remove smp-affinity node from ethernet and use tuned instead -from sys import exit, argv 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 = ['system', 'options'] base_new = ['system', 'option'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base_new): - for node in config.list_nodes(base): - config.copy(base + [node], base_new + [node]) -else: - config.copy(base, base_new) -config.delete(base) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -# Rename "system option beep-if-fully-booted" -> "system option startup-beep" -base_beep = base_new + ['beep-if-fully-booted'] -if config.exists(base_beep): - config.rename(base_beep, 'startup-beep') + if config.exists(base_new): + for node in config.list_nodes(base): + config.copy(base + [node], base_new + [node]) + else: + config.copy(base, base_new) -# Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete" -base_ctrl_alt_del = base_new + ['ctrl-alt-del-action'] -if config.exists(base_ctrl_alt_del): - config.rename(base_ctrl_alt_del, 'ctrl-alt-delete') + config.delete(base) + # Rename "system option beep-if-fully-booted" -> "system option startup-beep" + base_beep = base_new + ['beep-if-fully-booted'] + if config.exists(base_beep): + config.rename(base_beep, 'startup-beep') -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) + # Rename "system option ctrl-alt-del-action" -> "system option ctrl-alt-delete" + base_ctrl_alt_del = base_new + ['ctrl-alt-del-action'] + if config.exists(base_ctrl_alt_del): + config.rename(base_ctrl_alt_del, 'ctrl-alt-delete') diff --git a/src/migration-scripts/system/20-to-21 b/src/migration-scripts/system/20-to-21 index 24e042ce2..71c283da6 100755..100644 --- a/src/migration-scripts/system/20-to-21 +++ b/src/migration-scripts/system/20-to-21 @@ -1,46 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3795: merge "system name-servers-dhcp" into "system name-server" -from sys import argv 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 = ['system', 'name-servers-dhcp'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) -for interface in config.return_values(base): - config.set(['system', 'name-server'], value=interface, replace=False) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -config.delete(base) + for interface in config.return_values(base): + config.set(['system', 'name-server'], value=interface, replace=False) -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) + config.delete(base) diff --git a/src/migration-scripts/system/21-to-22 b/src/migration-scripts/system/21-to-22 index 2a1b603c6..0e68a6856 100755..100644 --- a/src/migration-scripts/system/21-to-22 +++ b/src/migration-scripts/system/21-to-22 @@ -1,55 +1,38 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import exit, argv 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 = ['system', 'sysctl'] -config = ConfigTree(config_file) -if not config.exists(base): - # Nothing to do - exit(0) - -for all_custom in ['all', 'custom']: - if config.exists(base + [all_custom]): - for key in config.list_nodes(base + [all_custom]): - tmp = config.return_value(base + [all_custom, key, 'value']) - config.set(base + ['parameter', key, 'value'], value=tmp) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for all_custom in ['all', 'custom']: + if config.exists(base + [all_custom]): + for key in config.list_nodes(base + [all_custom]): + tmp = config.return_value(base + [all_custom, key, 'value']) + config.set(base + ['parameter', key, 'value'], value=tmp) + config.set_tag(base + ['parameter']) + config.delete(base + [all_custom]) + + for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']: + if config.exists(base + [ipv4_param]): + tmp = config.return_value(base + [ipv4_param]) + config.set(base + ['parameter', ipv4_param, 'value'], value=tmp) config.set_tag(base + ['parameter']) - config.delete(base + [all_custom]) - -for ipv4_param in ['net.ipv4.igmp_max_memberships', 'net.ipv4.ipfrag_time']: - if config.exists(base + [ipv4_param]): - tmp = config.return_value(base + [ipv4_param]) - config.set(base + ['parameter', ipv4_param, 'value'], value=tmp) - config.set_tag(base + ['parameter']) - config.delete(base + [ipv4_param]) - -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) + config.delete(base + [ipv4_param]) diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23 index f83279b88..e49094e4a 100755..100644 --- a/src/migration-scripts/system/22-to-23 +++ b/src/migration-scripts/system/22-to-23 @@ -1,48 +1,31 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import exit, argv 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 = ['system', 'ipv6'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) -# T4346: drop support to disbale IPv6 address family within the OS Kernel -if config.exists(base + ['disable']): - config.delete(base + ['disable']) - # IPv6 address family disable was the only CLI option set - we can cleanup - # the entire tree - if len(config.list_nodes(base)) == 0: - config.delete(base) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # T4346: drop support to disbale IPv6 address family within the OS Kernel + if config.exists(base + ['disable']): + config.delete(base + ['disable']) + # IPv6 address family disable was the only CLI option set - we can cleanup + # the entire tree + if len(config.list_nodes(base)) == 0: + config.delete(base) diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24 index 1fd61d83b..feb62bc32 100755..100644 --- a/src/migration-scripts/system/23-to-24 +++ b/src/migration-scripts/system/23-to-24 @@ -1,38 +1,28 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. from ipaddress import ip_interface from ipaddress import ip_address -from sys import exit, argv + from vyos.configtree import ConfigTree from vyos.template import is_ipv4 -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 = ['protocols', 'static', 'arp'] tmp_base = ['protocols', 'static', 'arp-tmp'] -config = ConfigTree(config_file) -def fixup_cli(config, path, interface): +def fixup_cli(config, path, interface, host): if config.exists(path + ['address']): for address in config.return_values(path + ['address']): tmp = ip_interface(address) @@ -47,41 +37,35 @@ def fixup_cli(config, path, interface): config.set_tag(iface_path + [interface, 'address']) continue -if not config.exists(base): - # Nothing to do - exit(0) - -# We need a temporary copy of the config tree as the original one needs to be -# deleted first due to a change iun thge tagNode structure. -config.copy(base, tmp_base) -config.delete(base) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -for host in config.list_nodes(tmp_base): - for type in config.list_nodes(['interfaces']): - for interface in config.list_nodes(['interfaces', type]): - if_base = ['interfaces', type, interface] - fixup_cli(config, if_base, interface) + # We need a temporary copy of the config tree as the original one needs to be + # deleted first due to a change iun thge tagNode structure. + config.copy(base, tmp_base) + config.delete(base) - if config.exists(if_base + ['vif']): - for vif in config.list_nodes(if_base + ['vif']): - vif_base = ['interfaces', type, interface, 'vif', vif] - fixup_cli(config, vif_base, f'{interface}.{vif}') + for host in config.list_nodes(tmp_base): + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + if_base = ['interfaces', type, interface] + fixup_cli(config, if_base, interface, host) - if config.exists(if_base + ['vif-s']): - for vif_s in config.list_nodes(if_base + ['vif-s']): - vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s] - fixup_cli(config, vif_s_base, f'{interface}.{vif_s}') + if config.exists(if_base + ['vif']): + for vif in config.list_nodes(if_base + ['vif']): + vif_base = ['interfaces', type, interface, 'vif', vif] + fixup_cli(config, vif_base, f'{interface}.{vif}', host) - if config.exists(if_base + ['vif-s', vif_s, 'vif-c']): - for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']): - vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c] - fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}') + if config.exists(if_base + ['vif-s']): + for vif_s in config.list_nodes(if_base + ['vif-s']): + vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s] + fixup_cli(config, vif_s_base, f'{interface}.{vif_s}', host) -config.delete(tmp_base) + if config.exists(if_base + ['vif-s', vif_s, 'vif-c']): + for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']): + vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c] + fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}', host) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + config.delete(tmp_base) diff --git a/src/migration-scripts/system/24-to-25 b/src/migration-scripts/system/24-to-25 index 1c81a76e7..bdb89902e 100755..100644 --- a/src/migration-scripts/system/24-to-25 +++ b/src/migration-scripts/system/24-to-25 @@ -1,52 +1,35 @@ -#!/usr/bin/env python3 +# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2022 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. + # Migrate system syslog global archive to system logs logrotate messages -from sys import exit, argv 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 = ['system', 'syslog', 'global', 'archive'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) -if config.exists(base + ['file']): - tmp = config.return_value(base + ['file']) - config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -if config.exists(base + ['size']): - tmp = config.return_value(base + ['size']) - tmp = max(round(int(tmp) / 1024), 1) # kb -> mb - config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp) + if config.exists(base + ['file']): + tmp = config.return_value(base + ['file']) + config.set(['system', 'logs', 'logrotate', 'messages', 'rotate'], value=tmp) -config.delete(base) + if config.exists(base + ['size']): + tmp = config.return_value(base + ['size']) + tmp = max(round(int(tmp) / 1024), 1) # kb -> mb + config.set(['system', 'logs', 'logrotate', 'messages', 'max-size'], value=tmp) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + config.delete(base) diff --git a/src/migration-scripts/system/25-to-26 b/src/migration-scripts/system/25-to-26 index 7bdf3be98..8832f48e5 100755..100644 --- a/src/migration-scripts/system/25-to-26 +++ b/src/migration-scripts/system/25-to-26 @@ -1,39 +1,25 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. + # syslog: migrate deprecated CLI options # - protocols -> local7 # - security -> auth -from sys import exit, argv 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 = ['system', 'syslog'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) def rename_facilities(config, base_tree, facility, facility_new) -> None: if config.exists(base + [base_tree, 'facility', facility]): @@ -44,39 +30,36 @@ def rename_facilities(config, base_tree, facility, facility_new) -> None: # delete old duplicate facility config config.delete(base + [base_tree, 'facility', facility]) -# -# Rename protocols and securityy facility to common ones -# -replace = { - 'protocols' : 'local7', - 'security' : 'auth' -} -for facility, facility_new in replace.items(): - rename_facilities(config, 'console', facility, facility_new) - rename_facilities(config, 'global', facility, facility_new) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return - if config.exists(base + ['host']): - for host in config.list_nodes(base + ['host']): - rename_facilities(config, f'host {host}', facility, facility_new) + # + # Rename protocols and securityy facility to common ones + # + replace = { + 'protocols' : 'local7', + 'security' : 'auth' + } + for facility, facility_new in replace.items(): + rename_facilities(config, 'console', facility, facility_new) + rename_facilities(config, 'global', facility, facility_new) -# -# It makes no sense to configure udp/tcp transport per individual facility -# -if config.exists(base + ['host']): - for host in config.list_nodes(base + ['host']): - protocol = None - for facility in config.list_nodes(base + ['host', host, 'facility']): - tmp_path = base + ['host', host, 'facility', facility, 'protocol'] - if config.exists(tmp_path): - # We can only change the first one - if protocol == None: - protocol = config.return_value(tmp_path) - config.set(base + ['host', host, 'protocol'], value=protocol) - config.delete(tmp_path) + if config.exists(base + ['host']): + for host in config.list_nodes(base + ['host']): + rename_facilities(config, f'host {host}', facility, facility_new) -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # + # It makes no sense to configure udp/tcp transport per individual facility + # + if config.exists(base + ['host']): + for host in config.list_nodes(base + ['host']): + protocol = None + for facility in config.list_nodes(base + ['host', host, 'facility']): + tmp_path = base + ['host', host, 'facility', facility, 'protocol'] + if config.exists(tmp_path): + # We can only change the first one + if protocol == None: + protocol = config.return_value(tmp_path) + config.set(base + ['host', host, 'protocol'], value=protocol) + config.delete(tmp_path) diff --git a/src/migration-scripts/system/26-to-27 b/src/migration-scripts/system/26-to-27 index 80bb82cbd..499e16e08 100755..100644 --- a/src/migration-scripts/system/26-to-27 +++ b/src/migration-scripts/system/26-to-27 @@ -1,47 +1,30 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. + # T5877: migrate 'system domain-search domain' to 'system domain-search' -from sys import exit, argv 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 = ['system', 'domain-search'] -config = ConfigTree(config_file) - -if not config.exists(base): - exit(0) -if config.exists(base + ['domain']): - entries = config.return_values(base + ['domain']) - config.delete(base + ['domain']) - for entry in entries: - config.set(base, value=entry, replace=False) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + return -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + if config.exists(base + ['domain']): + entries = config.return_values(base + ['domain']) + config.delete(base + ['domain']) + for entry in entries: + config.set(base, value=entry, replace=False) diff --git a/src/migration-scripts/system/6-to-7 b/src/migration-scripts/system/6-to-7 index d24521134..e91ccc4e9 100755..100644 --- a/src/migration-scripts/system/6-to-7 +++ b/src/migration-scripts/system/6-to-7 @@ -1,48 +1,36 @@ -#!/usr/bin/env python3 +# Copyright 2019-2024 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/>. # Change smp_affinity to smp-affinity -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - -update_required = False - -intf_types = config.list_nodes(["interfaces"]) - -for intf_type in intf_types: - intf_type_path = ["interfaces", intf_type] - intfs = config.list_nodes(intf_type_path) - - for intf in intfs: - intf_path = intf_type_path + [intf] - if not config.exists(intf_path + ["smp_affinity"]): - # Nothing to do. - continue - else: - # Rename the node. - old_smp_affinity_path = intf_path + ["smp_affinity"] - config.rename(old_smp_affinity_path, "smp-affinity") - update_required = True - -if update_required: - 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)) - sys.exit(1) - - - +def migrate(config: ConfigTree) -> None: + intf_types = config.list_nodes(["interfaces"]) + + for intf_type in intf_types: + intf_type_path = ["interfaces", intf_type] + intfs = config.list_nodes(intf_type_path) + + for intf in intfs: + intf_path = intf_type_path + [intf] + if not config.exists(intf_path + ["smp_affinity"]): + # Nothing to do. + continue + else: + # Rename the node. + old_smp_affinity_path = intf_path + ["smp_affinity"] + config.rename(old_smp_affinity_path, "smp-affinity") + update_required = True diff --git a/src/migration-scripts/system/7-to-8 b/src/migration-scripts/system/7-to-8 index 5d084d2bf..64dd4dc93 100755..100644 --- a/src/migration-scripts/system/7-to-8 +++ b/src/migration-scripts/system/7-to-8 @@ -1,26 +1,27 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # Converts "system gateway-address" option to "protocols static route 0.0.0.0/0 next-hop $gw" -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['system', 'gateway-address']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['system', 'gateway-address']): - # Nothing to do - sys.exit(0) -else: # Save the address gw = config.return_value(['system', 'gateway-address']) @@ -36,10 +37,3 @@ else: # They must be formatted as such to load correctly. config.set_tag(['protocols', 'static', 'route']) config.set_tag(['protocols', 'static', 'route', '0.0.0.0/0', 'next-hop']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/system/8-to-9 b/src/migration-scripts/system/8-to-9 index e3bb2bca8..ea5f7af81 100755..100644 --- a/src/migration-scripts/system/8-to-9 +++ b/src/migration-scripts/system/8-to-9 @@ -1,32 +1,26 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # Deletes "system package" option as it is deprecated -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +def migrate(config: ConfigTree) -> None: + if not config.exists(['system', 'package']): + # Nothing to do + return -config = ConfigTree(config_file) - -if not config.exists(['system', 'package']): - # Nothing to do - sys.exit(0) -else: # Delete the node with the old syntax config.delete(['system', 'package']) - - 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)) - sys.exit(1) diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1 index 8187138d9..70abae2a8 100755..100644 --- a/src/migration-scripts/vrf/0-to-1 +++ b/src/migration-scripts/vrf/0-to-1 @@ -1,132 +1,113 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T2450: drop interface-route and interface-route6 from "protocols vrf" -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 = ['protocols', 'vrf'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -for vrf in config.list_nodes(base): - static_base = base + [vrf, 'static'] - if not config.exists(static_base): - continue - - # - # Migrate interface-route into route - # - interface_route_path = static_base + ['interface-route'] - if config.exists(interface_route_path): - for route in config.list_nodes(interface_route_path): - interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) - - tmp = interface_route_path + [route, 'next-hop-interface'] - for interface in config.list_nodes(tmp): - new_base = static_base + ['route', route, 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(tmp + [interface], new_base + [interface]) - - config.delete(interface_route_path) - - # - # Migrate interface-route6 into route6 - # - interface_route_path = static_base + ['interface-route6'] - if config.exists(interface_route_path): - for route in config.list_nodes(interface_route_path): - interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) - - tmp = interface_route_path + [route, 'next-hop-interface'] - for interface in config.list_nodes(tmp): - new_base = static_base + ['route6', route, 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(tmp + [interface], new_base + [interface]) - - config.delete(interface_route_path) - - # - # Cleanup nodes inside route - # - route_path = static_base + ['route'] - if config.exists(route_path): - for route in config.list_nodes(route_path): - next_hop = route_path + [route, 'next-hop'] - if config.exists(next_hop): - for gateway in config.list_nodes(next_hop): - interface_path = next_hop + [gateway, 'next-hop-interface'] - if config.exists(interface_path): - config.rename(interface_path, 'interface') - vrf_path = next_hop + [gateway, 'next-hop-vrf'] - if config.exists(vrf_path): - config.rename(vrf_path, 'vrf') - - next_hop = route_path + [route, 'interface'] - if config.exists(next_hop): - for interface in config.list_nodes(next_hop): - interface_path = next_hop + [interface, 'next-hop-interface'] - if config.exists(interface_path): - config.rename(interface_path, 'interface') - vrf_path = next_hop + [interface, 'next-hop-vrf'] - if config.exists(vrf_path): - config.rename(vrf_path, 'vrf') - - # - # Cleanup nodes inside route6 - # - route_path = static_base + ['route6'] - if config.exists(route_path): - for route in config.list_nodes(route_path): - next_hop = route_path + [route, 'next-hop'] - if config.exists(next_hop): - for gateway in config.list_nodes(next_hop): - vrf_path = next_hop + [gateway, 'next-hop-vrf'] - if config.exists(vrf_path): - config.rename(vrf_path, 'vrf') - - next_hop = route_path + [route, 'interface'] - if config.exists(next_hop): - for interface in config.list_nodes(next_hop): - interface_path = next_hop + [interface, 'next-hop-interface'] - if config.exists(interface_path): - config.rename(interface_path, 'interface') - vrf_path = next_hop + [interface, 'next-hop-vrf'] - if config.exists(vrf_path): - config.rename(vrf_path, 'vrf') -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + for vrf in config.list_nodes(base): + static_base = base + [vrf, 'static'] + if not config.exists(static_base): + continue + + # + # Migrate interface-route into route + # + interface_route_path = static_base + ['interface-route'] + if config.exists(interface_route_path): + for route in config.list_nodes(interface_route_path): + interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) + + tmp = interface_route_path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = static_base + ['route', route, 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(interface_route_path) + + # + # Migrate interface-route6 into route6 + # + interface_route_path = static_base + ['interface-route6'] + if config.exists(interface_route_path): + for route in config.list_nodes(interface_route_path): + interface = config.list_nodes(interface_route_path + [route, 'next-hop-interface']) + + tmp = interface_route_path + [route, 'next-hop-interface'] + for interface in config.list_nodes(tmp): + new_base = static_base + ['route6', route, 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(tmp + [interface], new_base + [interface]) + + config.delete(interface_route_path) + + # + # Cleanup nodes inside route + # + route_path = static_base + ['route'] + if config.exists(route_path): + for route in config.list_nodes(route_path): + next_hop = route_path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + interface_path = next_hop + [gateway, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + next_hop = route_path + [route, 'interface'] + if config.exists(next_hop): + for interface in config.list_nodes(next_hop): + interface_path = next_hop + [interface, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + vrf_path = next_hop + [interface, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + # + # Cleanup nodes inside route6 + # + route_path = static_base + ['route6'] + if config.exists(route_path): + for route in config.list_nodes(route_path): + next_hop = route_path + [route, 'next-hop'] + if config.exists(next_hop): + for gateway in config.list_nodes(next_hop): + vrf_path = next_hop + [gateway, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') + + next_hop = route_path + [route, 'interface'] + if config.exists(next_hop): + for interface in config.list_nodes(next_hop): + interface_path = next_hop + [interface, 'next-hop-interface'] + if config.exists(interface_path): + config.rename(interface_path, 'interface') + vrf_path = next_hop + [interface, 'next-hop-vrf'] + if config.exists(vrf_path): + config.rename(vrf_path, 'vrf') diff --git a/src/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2 index 52d4c2c7b..557a9ec58 100755..100644 --- a/src/migration-scripts/vrf/1-to-2 +++ b/src/migration-scripts/vrf/1-to-2 @@ -1,62 +1,43 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # - T3344: migrate routing options from "protocols vrf" to "vrf <name> protocols" -from sys import argv -from sys import exit from vyos.configtree import ConfigTree -if len(argv) < 2: - print("Must specify file name!") - exit(1) +base = ['protocols', 'vrf'] -file_name = argv[1] +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return -with open(file_name, 'r') as f: - config_file = f.read() + vrf_base = ['vrf', 'name'] + config.set(vrf_base) + config.set_tag(vrf_base) -base = ['protocols', 'vrf'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -vrf_base = ['vrf', 'name'] -config.set(vrf_base) -config.set_tag(vrf_base) - -# Copy all existing static routes to the new base node under "vrf name <name> protocols static" -for vrf in config.list_nodes(base): - static_base = base + [vrf, 'static'] - if not config.exists(static_base): - continue - - new_static_base = vrf_base + [vrf, 'protocols'] - config.set(new_static_base) - config.copy(static_base, new_static_base + ['static']) - config.set_tag(new_static_base + ['static', 'route']) - -# Now delete the old configuration -config.delete(base) - -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) + # Copy all existing static routes to the new base node under "vrf name <name> protocols static" + for vrf in config.list_nodes(base): + static_base = base + [vrf, 'static'] + if not config.exists(static_base): + continue + + new_static_base = vrf_base + [vrf, 'protocols'] + config.set(new_static_base) + config.copy(static_base, new_static_base + ['static']) + config.set_tag(new_static_base + ['static', 'route']) + + # Now delete the old configuration + config.delete(base) diff --git a/src/migration-scripts/vrf/2-to-3 b/src/migration-scripts/vrf/2-to-3 index d45b185ee..acacffb41 100755..100644 --- a/src/migration-scripts/vrf/2-to-3 +++ b/src/migration-scripts/vrf/2-to-3 @@ -1,26 +1,23 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # Since connection tracking zones are int16, VRFs tables maximum value must # be limited to 65535 # Also, interface names in nftables cannot start from numbers, # so VRF name should not start from a number -from sys import argv -from sys import exit from random import randrange from random import choice from string import ascii_lowercase @@ -69,76 +66,60 @@ def _search_tables(config_commands, table_num): return table_items -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 = ['vrf', 'name'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -# Get a list of all currently used VRFs and tables -vrfs_current = {} -for vrf in config.list_nodes(base): - vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table'])) - -# Check VRF names and table numbers -name_regex = re.compile(r'^\d.*$') -for vrf_name, vrf_table in vrfs_current.items(): - # Check table number - if vrf_table > 65535: - # Find new unused table number - vrfs_current[vrf_name] = None - while not vrfs_current[vrf_name]: - table_random = randrange(100, 65535) - if table_random not in vrfs_current.values(): - vrfs_current[vrf_name] = table_random - # Update number to a new one - config.set(['vrf', 'name', vrf_name, 'table'], - vrfs_current[vrf_name], - replace=True) - # Check config items with old table number and replace to new one - config_commands = config.to_commands().split('\n') - table_config_lines = _search_tables(config_commands, vrf_table) - # Rename table nodes - if table_config_lines.get('table_tags'): - for table_config_path in table_config_lines.get('table_tags'): - config.rename(table_config_path, f'{vrfs_current[vrf_name]}') - # Replace table values - if table_config_lines.get('table_values'): - for table_config_path in table_config_lines.get('table_values'): - config.set(table_config_path, - f'{vrfs_current[vrf_name]}', - replace=True) - - # Check VRF name - if name_regex.match(vrf_name): - vrf_name_new = None - while not vrf_name_new: - vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15] - if vrf_name_rand not in vrfs_current: - vrf_name_new = vrf_name_rand - # Update VRF name to a new one - config.rename(['vrf', 'name', vrf_name], vrf_name_new) - # Check config items with old VRF name and replace to new one - config_commands = config.to_commands().split('\n') - vrf_config_lines = _search_vrfs(config_commands, vrf_name) - # Rename VRF to a new name - if vrf_config_lines: - for vrf_value_path in vrf_config_lines: - config.set(vrf_value_path, vrf_name_new, replace=True) -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) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + # Get a list of all currently used VRFs and tables + vrfs_current = {} + for vrf in config.list_nodes(base): + vrfs_current[vrf] = int(config.return_value(base + [vrf, 'table'])) + + # Check VRF names and table numbers + name_regex = re.compile(r'^\d.*$') + for vrf_name, vrf_table in vrfs_current.items(): + # Check table number + if vrf_table > 65535: + # Find new unused table number + vrfs_current[vrf_name] = None + while not vrfs_current[vrf_name]: + table_random = randrange(100, 65535) + if table_random not in vrfs_current.values(): + vrfs_current[vrf_name] = table_random + # Update number to a new one + config.set(['vrf', 'name', vrf_name, 'table'], + vrfs_current[vrf_name], + replace=True) + # Check config items with old table number and replace to new one + config_commands = config.to_commands().split('\n') + table_config_lines = _search_tables(config_commands, vrf_table) + # Rename table nodes + if table_config_lines.get('table_tags'): + for table_config_path in table_config_lines.get('table_tags'): + config.rename(table_config_path, f'{vrfs_current[vrf_name]}') + # Replace table values + if table_config_lines.get('table_values'): + for table_config_path in table_config_lines.get('table_values'): + config.set(table_config_path, + f'{vrfs_current[vrf_name]}', + replace=True) + + # Check VRF name + if name_regex.match(vrf_name): + vrf_name_new = None + while not vrf_name_new: + vrf_name_rand = f'{choice(ascii_lowercase)}{vrf_name}'[:15] + if vrf_name_rand not in vrfs_current: + vrf_name_new = vrf_name_rand + # Update VRF name to a new one + config.rename(['vrf', 'name', vrf_name], vrf_name_new) + # Check config items with old VRF name and replace to new one + config_commands = config.to_commands().split('\n') + vrf_config_lines = _search_vrfs(config_commands, vrf_name) + # Rename VRF to a new name + if vrf_config_lines: + for vrf_value_path in vrf_config_lines: + config.set(vrf_value_path, vrf_name_new, replace=True) diff --git a/src/migration-scripts/vrrp/1-to-2 b/src/migration-scripts/vrrp/1-to-2 index dba5af81c..8639a7553 100755..100644 --- a/src/migration-scripts/vrrp/1-to-2 +++ b/src/migration-scripts/vrrp/1-to-2 @@ -1,37 +1,23 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2018 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 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/>. +# 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/>. import re -import sys from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() - -config = ConfigTree(config_file) - # Convert the old VRRP syntax to the new syntax # The old approach was to put VRRP groups inside interfaces, @@ -109,162 +95,156 @@ def get_vrrp_group(path): # Only if no data is collected from any interface we can conclude that VRRP is not configured # and exit. -groups = [] -base_paths = [] - -if config.exists(["interfaces", "ethernet"]): - base_paths.append("ethernet") -if config.exists(["interfaces", "bonding"]): - base_paths.append("bonding") - -for bp in base_paths: - parent_path = ["interfaces", bp] - - parent_intfs = config.list_nodes(parent_path) - - for pi in parent_intfs: - # Extract VRRP groups from the parent interface - vg_path =[pi, "vrrp", "vrrp-group"] - if config.exists(parent_path + vg_path): - pgroups = config.list_nodes(parent_path + vg_path) - for pg in pgroups: - g = get_vrrp_group(parent_path + vg_path + [pg]) - g["interface"] = pi - g["vrid"] = pg - groups.append(g) - - # Delete the VRRP subtree - # If left in place, configs will not load correctly - config.delete(parent_path + [pi, "vrrp"]) - - # Extract VRRP groups from 802.1q VLAN interfaces - if config.exists(parent_path + [pi, "vif"]): - vifs = config.list_nodes(parent_path + [pi, "vif"]) - for vif in vifs: - vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"] - if config.exists(parent_path + vif_vg_path): - vifgroups = config.list_nodes(parent_path + vif_vg_path) - for vif_group in vifgroups: - g = get_vrrp_group(parent_path + vif_vg_path + [vif_group]) - g["interface"] = "{0}.{1}".format(pi, vif) - g["vrid"] = vif_group - groups.append(g) - - config.delete(parent_path + [pi, "vif", vif, "vrrp"]) - - # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces - if config.exists(parent_path + [pi, "vif-s"]): - vif_ss = config.list_nodes(parent_path + [pi, "vif-s"]) - for vif_s in vif_ss: - vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"] - if config.exists(parent_path + vifs_vg_path): - vifsgroups = config.list_nodes(parent_path + vifs_vg_path) - for vifs_group in vifsgroups: - g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group]) - g["interface"] = "{0}.{1}".format(pi, vif_s) - g["vrid"] = vifs_group - groups.append(g) - - config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"]) - - # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s - if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]): - vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"]) - for vif_c in vif_cs: - vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"] - vifcgroups = config.list_nodes(parent_path + vifc_vg_path) - for vifc_group in vifcgroups: - g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group]) - g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c) - g["vrid"] = vifc_group - groups.append(g) - - config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"]) - -# If nothing was collected before this point, it means the config has no VRRP setup -if not groups: - sys.exit(0) - -# Otherwise, there is VRRP to convert - -# Now convert the collected groups to the new syntax -base_group_path = ["high-availability", "vrrp", "group"] -sync_path = ["high-availability", "vrrp", "sync-group"] - -for g in groups: - group_name = "{0}-{1}".format(g["interface"], g["vrid"]) - group_path = base_group_path + [group_name] - - config.set(group_path + ["interface"], value=g["interface"]) - config.set(group_path + ["vrid"], value=g["vrid"]) - - if "advertise_interval" in g: - config.set(group_path + ["advertise-interval"], value=g["advertise_interval"]) - - if "priority" in g: - config.set(group_path + ["priority"], value=g["priority"]) - - if not g["preempt"]: - config.set(group_path + ["no-preempt"], value=None) - - if "preempt_delay" in g: - config.set(group_path + ["preempt-delay"], value=g["preempt_delay"]) - - if g["rfc_compatibility"]: - config.set(group_path + ["rfc3768-compatibility"], value=None) - - if g["disable"]: - config.set(group_path + ["disable"], value=None) - - if "hello_source" in g: - config.set(group_path + ["hello-source-address"], value=g["hello_source"]) - - if "peer_address" in g: - config.set(group_path + ["peer-address"], value=g["peer_address"]) - - if "auth_password" in g: - config.set(group_path + ["authentication", "password"], value=g["auth_password"]) - if "auth_type" in g: - config.set(group_path + ["authentication", "type"], value=g["auth_type"]) - - if "master_script" in g: - config.set(group_path + ["transition-script", "master"], value=g["master_script"]) - if "backup_script" in g: - config.set(group_path + ["transition-script", "backup"], value=g["backup_script"]) - if "fault_script" in g: - config.set(group_path + ["transition-script", "fault"], value=g["fault_script"]) - - if "health_check_interval" in g: - config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"]) - if "health_check_count" in g: - config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"]) - if "health_check_script" in g: - config.set(group_path + ["health-check", "script"], value=g["health_check_script"]) - - # Not that it should ever be absent... - if "virtual_addresses" in g: - # The new CLI disallows addresses without prefix length - # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway - for va in g["virtual_addresses"]: - if not re.search(r'/', va): - if re.search(r':', va): - va = "{0}/128".format(va) - else: - va = "{0}/32".format(va) - config.set(group_path + ["virtual-address"], value=va, replace=False) - - # Sync group - if "sync_group" in g: - config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False) - -# Set the tag flag -config.set_tag(base_group_path) -if config.exists(sync_path): - config.set_tag(sync_path) - -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)) - sys.exit(1) +def migrate(config: ConfigTree) -> None: + groups = [] + base_paths = [] + + if config.exists(["interfaces", "ethernet"]): + base_paths.append("ethernet") + if config.exists(["interfaces", "bonding"]): + base_paths.append("bonding") + + for bp in base_paths: + parent_path = ["interfaces", bp] + + parent_intfs = config.list_nodes(parent_path) + + for pi in parent_intfs: + # Extract VRRP groups from the parent interface + vg_path =[pi, "vrrp", "vrrp-group"] + if config.exists(parent_path + vg_path): + pgroups = config.list_nodes(parent_path + vg_path) + for pg in pgroups: + g = get_vrrp_group(parent_path + vg_path + [pg]) + g["interface"] = pi + g["vrid"] = pg + groups.append(g) + + # Delete the VRRP subtree + # If left in place, configs will not load correctly + config.delete(parent_path + [pi, "vrrp"]) + + # Extract VRRP groups from 802.1q VLAN interfaces + if config.exists(parent_path + [pi, "vif"]): + vifs = config.list_nodes(parent_path + [pi, "vif"]) + for vif in vifs: + vif_vg_path = [pi, "vif", vif, "vrrp", "vrrp-group"] + if config.exists(parent_path + vif_vg_path): + vifgroups = config.list_nodes(parent_path + vif_vg_path) + for vif_group in vifgroups: + g = get_vrrp_group(parent_path + vif_vg_path + [vif_group]) + g["interface"] = "{0}.{1}".format(pi, vif) + g["vrid"] = vif_group + groups.append(g) + + config.delete(parent_path + [pi, "vif", vif, "vrrp"]) + + # Extract VRRP groups from 802.3ad QinQ service VLAN interfaces + if config.exists(parent_path + [pi, "vif-s"]): + vif_ss = config.list_nodes(parent_path + [pi, "vif-s"]) + for vif_s in vif_ss: + vifs_vg_path = [pi, "vif-s", vif_s, "vrrp", "vrrp-group"] + if config.exists(parent_path + vifs_vg_path): + vifsgroups = config.list_nodes(parent_path + vifs_vg_path) + for vifs_group in vifsgroups: + g = get_vrrp_group(parent_path + vifs_vg_path + [vifs_group]) + g["interface"] = "{0}.{1}".format(pi, vif_s) + g["vrid"] = vifs_group + groups.append(g) + + config.delete(parent_path + [pi, "vif-s", vif_s, "vrrp"]) + + # Extract VRRP groups from QinQ client VLAN interfaces nested in the vif-s + if config.exists(parent_path + [pi, "vif-s", vif_s, "vif-c"]): + vif_cs = config.list_nodes(parent_path + [pi, "vif-s", vif_s, "vif-c"]) + for vif_c in vif_cs: + vifc_vg_path = [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp", "vrrp-group"] + vifcgroups = config.list_nodes(parent_path + vifc_vg_path) + for vifc_group in vifcgroups: + g = get_vrrp_group(parent_path + vifc_vg_path + [vifc_group]) + g["interface"] = "{0}.{1}.{2}".format(pi, vif_s, vif_c) + g["vrid"] = vifc_group + groups.append(g) + + config.delete(parent_path + [pi, "vif-s", vif_s, "vif-c", vif_c, "vrrp"]) + + # If nothing was collected before this point, it means the config has no VRRP setup + if not groups: + return + + # Otherwise, there is VRRP to convert + + # Now convert the collected groups to the new syntax + base_group_path = ["high-availability", "vrrp", "group"] + sync_path = ["high-availability", "vrrp", "sync-group"] + + for g in groups: + group_name = "{0}-{1}".format(g["interface"], g["vrid"]) + group_path = base_group_path + [group_name] + + config.set(group_path + ["interface"], value=g["interface"]) + config.set(group_path + ["vrid"], value=g["vrid"]) + + if "advertise_interval" in g: + config.set(group_path + ["advertise-interval"], value=g["advertise_interval"]) + + if "priority" in g: + config.set(group_path + ["priority"], value=g["priority"]) + + if not g["preempt"]: + config.set(group_path + ["no-preempt"], value=None) + + if "preempt_delay" in g: + config.set(group_path + ["preempt-delay"], value=g["preempt_delay"]) + + if g["rfc_compatibility"]: + config.set(group_path + ["rfc3768-compatibility"], value=None) + + if g["disable"]: + config.set(group_path + ["disable"], value=None) + + if "hello_source" in g: + config.set(group_path + ["hello-source-address"], value=g["hello_source"]) + + if "peer_address" in g: + config.set(group_path + ["peer-address"], value=g["peer_address"]) + + if "auth_password" in g: + config.set(group_path + ["authentication", "password"], value=g["auth_password"]) + if "auth_type" in g: + config.set(group_path + ["authentication", "type"], value=g["auth_type"]) + + if "master_script" in g: + config.set(group_path + ["transition-script", "master"], value=g["master_script"]) + if "backup_script" in g: + config.set(group_path + ["transition-script", "backup"], value=g["backup_script"]) + if "fault_script" in g: + config.set(group_path + ["transition-script", "fault"], value=g["fault_script"]) + + if "health_check_interval" in g: + config.set(group_path + ["health-check", "interval"], value=g["health_check_interval"]) + if "health_check_count" in g: + config.set(group_path + ["health-check", "failure-count"], value=g["health_check_count"]) + if "health_check_script" in g: + config.set(group_path + ["health-check", "script"], value=g["health_check_script"]) + + # Not that it should ever be absent... + if "virtual_addresses" in g: + # The new CLI disallows addresses without prefix length + # Pre-rewrite configs didn't support IPv6 VRRP, but handle it anyway + for va in g["virtual_addresses"]: + if not re.search(r'/', va): + if re.search(r':', va): + va = "{0}/128".format(va) + else: + va = "{0}/32".format(va) + config.set(group_path + ["virtual-address"], value=va, replace=False) + + # Sync group + if "sync_group" in g: + config.set(sync_path + [g["sync_group"], "member"], value=group_name, replace=False) + + # Set the tag flag + config.set_tag(base_group_path) + if config.exists(sync_path): + config.set_tag(sync_path) diff --git a/src/migration-scripts/vrrp/2-to-3 b/src/migration-scripts/vrrp/2-to-3 index ed583b489..468918f91 100755..100644 --- a/src/migration-scripts/vrrp/2-to-3 +++ b/src/migration-scripts/vrrp/2-to-3 @@ -1,62 +1,44 @@ -#!/usr/bin/env python3 +# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2021 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. # T3847: vrrp config cleanup -from sys import argv 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 = ['high-availability', 'vrrp'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base + ['group']): - for group in config.list_nodes(base + ['group']): - group_base = base + ['group', group] - - # Deprecated option - tmp = group_base + ['transition-script', 'mode-force'] - if config.exists(tmp): - config.delete(tmp) - - # Rename virtual-address -> address - tmp = group_base + ['virtual-address'] - if config.exists(tmp): - config.rename(tmp, 'address') - - # Rename virtual-address-excluded -> excluded-address - tmp = group_base + ['virtual-address-excluded'] - if config.exists(tmp): - config.rename(tmp, 'excluded-address') - -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + if config.exists(base + ['group']): + for group in config.list_nodes(base + ['group']): + group_base = base + ['group', group] + + # Deprecated option + tmp = group_base + ['transition-script', 'mode-force'] + if config.exists(tmp): + config.delete(tmp) + + # Rename virtual-address -> address + tmp = group_base + ['virtual-address'] + if config.exists(tmp): + config.rename(tmp, 'address') + + # Rename virtual-address-excluded -> excluded-address + tmp = group_base + ['virtual-address-excluded'] + if config.exists(tmp): + config.rename(tmp, 'excluded-address') diff --git a/src/migration-scripts/vrrp/3-to-4 b/src/migration-scripts/vrrp/3-to-4 index e5d93578c..9f05cf7a1 100755..100644 --- a/src/migration-scripts/vrrp/3-to-4 +++ b/src/migration-scripts/vrrp/3-to-4 @@ -1,51 +1,32 @@ -#!/usr/bin/env python3 +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # -# Copyright (C) 2023 VyOS maintainers and contributors +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. # -# This 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, +# 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 General Public License for more details. +# 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 General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# 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/>. -from sys import argv 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 = ['high-availability', 'virtual-server'] -config = ConfigTree(config_file) - -if not config.exists(base): - # Nothing to do - exit(0) - -if config.exists(base): - for vs in config.list_nodes(base): - vs_base = base + [vs] - # If the fwmark is used, the address is not required - if not config.exists(vs_base + ['fwmark']): - # add option: 'virtual-server <tag> address x.x.x.x' - config.set(vs_base + ['address'], value=vs) +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + if config.exists(base): + for vs in config.list_nodes(base): + vs_base = base + [vs] -try: - with open(file_name, 'w') as f: - f.write(config.to_string()) -except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + # If the fwmark is used, the address is not required + if not config.exists(vs_base + ['fwmark']): + # add option: 'virtual-server <tag> address x.x.x.x' + config.set(vs_base + ['address'], value=vs) diff --git a/src/migration-scripts/webproxy/1-to-2 b/src/migration-scripts/webproxy/1-to-2 index 03f357878..5a4847474 100755..100644 --- a/src/migration-scripts/webproxy/1-to-2 +++ b/src/migration-scripts/webproxy/1-to-2 @@ -1,39 +1,33 @@ -#!/usr/bin/env python3 +# Copyright 2018-2024 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/>. # migrate old style `webproxy proxy-bypass 1.2.3.4/24` # to new style `webproxy whitelist destination-address 1.2.3.4/24` -import sys - from vyos.configtree import ConfigTree -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) - -file_name = sys.argv[1] - -with open(file_name, 'r') as f: - config_file = f.read() +cfg_webproxy_base = ['service', 'webproxy'] -config = ConfigTree(config_file) +def migrate(config: ConfigTree) -> None: + if not config.exists(cfg_webproxy_base + ['proxy-bypass']): + # Nothing to do + return -cfg_webproxy_base = ['service', 'webproxy'] -if not config.exists(cfg_webproxy_base + ['proxy-bypass']): - # Nothing to do - sys.exit(0) -else: bypass_addresses = config.return_values(cfg_webproxy_base + ['proxy-bypass']) # delete old configuration node config.delete(cfg_webproxy_base + ['proxy-bypass']) for bypass_address in bypass_addresses: # add data to new configuration node config.set(cfg_webproxy_base + ['whitelist', 'destination-address'], value=bypass_address, replace=False) - - # save updated configuration - 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)) - sys.exit(1) diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py index 15fbb65a2..c197ca434 100755 --- a/src/op_mode/firewall.py +++ b/src/op_mode/firewall.py @@ -63,10 +63,10 @@ def get_nftables_details(family, hook, priority): aux='' if hook == 'name' or hook == 'ipv6-name': - command = f'sudo nft list chain {suffix} vyos_filter {name_prefix}{priority}' + command = f'nft list chain {suffix} vyos_filter {name_prefix}{priority}' else: up_hook = hook.upper() - command = f'sudo nft list chain {suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}' + command = f'nft list chain {suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}' try: results = cmd(command) @@ -90,12 +90,42 @@ def get_nftables_details(family, hook, priority): out[rule_id] = rule return out +def get_nftables_state_details(family): + if family == 'ipv6': + suffix = 'ip6' + name_suffix = 'POLICY6' + elif family == 'ipv4': + suffix = 'ip' + name_suffix = 'POLICY' + else: + # no state policy for bridge + return {} + + command = f'nft list chain {suffix} vyos_filter VYOS_STATE_{name_suffix}' + try: + results = cmd(command) + except: + return {} + + out = {} + for line in results.split('\n'): + rule = {} + for state in ['established', 'related', 'invalid']: + if state in line: + counter_search = re.search(r'counter packets (\d+) bytes (\d+)', line) + if counter_search: + rule['packets'] = counter_search[1] + rule['bytes'] = counter_search[2] + rule['conditions'] = re.sub(r'(\b(counter packets \d+ bytes \d+|drop|reject|return|log)\b|comment "[\w\-]+")', '', line).strip() + out[state] = rule + return out + def get_nftables_group_members(family, table, name): prefix = 'ip6' if family == 'ipv6' else 'ip' out = [] try: - results_str = cmd(f'sudo nft -j list set {prefix} {table} {name}') + results_str = cmd(f'nft -j list set {prefix} {table} {name}') results = json.loads(results_str) except: return out @@ -172,6 +202,34 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N rows[rows.index(i)].pop(1) print(tabulate.tabulate(rows, header) + '\n') +def output_firewall_state_policy(family): + if family == 'bridge': + return {} + print(f'\n---------------------------------\n{family} State Policy\n') + + details = get_nftables_state_details(family) + rows = [] + + for state, state_conf in details.items(): + row = [state, state_conf['conditions']] + row.append(state_conf.get('packets', 0)) + row.append(state_conf.get('bytes', 0)) + row.append(state_conf.get('conditions')) + rows.append(row) + + if rows: + if args.rule: + rows.pop() + + if args.detail: + header = ['State', 'Conditions', 'Packets', 'Bytes'] + output_firewall_vertical(rows, header) + else: + header = ['State', 'Packets', 'Bytes', 'Conditions'] + for i in rows: + rows[rows.index(i)].pop(1) + print(tabulate.tabulate(rows, header) + '\n') + def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule_id=None): print(f'\n---------------------------------\n{family} Firewall "{hook} {prior}"\n') @@ -305,6 +363,10 @@ def show_firewall(): return for family in ['ipv4', 'ipv6', 'bridge']: + if 'global_options' in firewall: + if 'state_policy' in firewall['global_options']: + output_firewall_state_policy(family) + if family in firewall: for hook, hook_conf in firewall[family].items(): for prior, prior_conf in firewall[family][hook].items(): @@ -316,12 +378,17 @@ def show_firewall_family(family): conf = Config() firewall = get_config_node(conf) - if not firewall or family not in firewall: + if not firewall: return - for hook, hook_conf in firewall[family].items(): - for prior, prior_conf in firewall[family][hook].items(): - output_firewall_name(family, hook, prior, prior_conf) + if 'global_options' in firewall: + if 'state_policy' in firewall['global_options']: + output_firewall_state_policy(family) + + if family in firewall: + for hook, hook_conf in firewall[family].items(): + for prior, prior_conf in firewall[family][hook].items(): + output_firewall_name(family, hook, prior, prior_conf) def show_firewall_name(family, hook, priority): print('Ruleset Information') @@ -622,6 +689,10 @@ def show_statistics(): return for family in ['ipv4', 'ipv6', 'bridge']: + if 'global_options' in firewall: + if 'state_policy' in firewall['global_options']: + output_firewall_state_policy(family) + if family in firewall: for hook, hook_conf in firewall[family].items(): for prior, prior_conf in firewall[family][hook].items(): diff --git a/src/op_mode/generate_firewall_rule-resequence.py b/src/op_mode/generate_service_rule-resequence.py index 21441f689..9333d6353 100755 --- a/src/op_mode/generate_firewall_rule-resequence.py +++ b/src/op_mode/generate_service_rule-resequence.py @@ -77,7 +77,7 @@ def change_rule_numbers(config_dict, start, step): change_rule_numbers(config_dict[key], start, step) -def convert_rule_keys_to_int(config_dict): +def convert_rule_keys_to_int(config_dict, prev_key=None): """ Converts rule keys in the configuration dictionary to integers. @@ -91,11 +91,11 @@ def convert_rule_keys_to_int(config_dict): new_dict = {} for key, value in config_dict.items(): # Convert key to integer if possible - new_key = int(key) if key.isdigit() else key + new_key = int(key) if key.isdigit() and prev_key == 'rule' else key # Recur for nested dictionaries if isinstance(value, dict): - new_value = convert_rule_keys_to_int(value) + new_value = convert_rule_keys_to_int(value, key) else: new_value = value @@ -111,27 +111,24 @@ def convert_rule_keys_to_int(config_dict): if __name__ == "__main__": # Parse command-line arguments parser = argparse.ArgumentParser(description='Convert dictionary to set commands with rule number modifications.') - parser.add_argument('--start', type=int, default=100, help='Start rule number') + parser.add_argument('--service', type=str, help='Name of service') + parser.add_argument('--start', type=int, default=100, help='Start rule number (default: 100)') parser.add_argument('--step', type=int, default=10, help='Step for rule numbers (default: 10)') args = parser.parse_args() config = ConfigTreeQuery() - if not config.exists('firewall'): - print('Firewall is not configured') + if not config.exists(args.service): + print(f'{args.service} is not configured') exit(1) - config_dict = config.get_config_dict('firewall') + config_dict = config.get_config_dict(args.service) - # Remove global-options, group and flowtable as they don't need sequencing - if 'global-options' in config_dict['firewall']: - del config_dict['firewall']['global-options'] + if 'firewall' in config_dict: + # Remove global-options, group and flowtable as they don't need sequencing + for item in ['global-options', 'group', 'flowtable']: + if item in config_dict['firewall']: + del config_dict['firewall'][item] - if 'group' in config_dict['firewall']: - del config_dict['firewall']['group'] - - if 'flowtable' in config_dict['firewall']: - del config_dict['firewall']['flowtable'] - # Convert rule keys to integers, rule "10" -> rule 10 # This is necessary for sorting the rules config_dict = convert_rule_keys_to_int(config_dict) diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py index 230fb252d..32cf67778 100644 --- a/src/op_mode/show_techsupport_report.py +++ b/src/op_mode/show_techsupport_report.py @@ -14,10 +14,12 @@ # 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 from typing import List -from vyos.utils.process import rc_cmd from vyos.ifconfig import Section from vyos.ifconfig import Interface +from vyos.utils.process import rc_cmd def print_header(command: str) -> None: @@ -50,7 +52,15 @@ def execute_command(command: str, header_text: str) -> None: print_header(header_text) try: rc, output = rc_cmd(command) - print(output) + # Enable unbuffered print param to improve responsiveness of printed + # output to end user + print(output, flush=True) + # Exit gracefully when user interrupts program output + # Flush standard streams; redirect remaining output to devnull + # Resolves T5633: Bug #1 and 3 + except (BrokenPipeError, KeyboardInterrupt): + os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno()) + sys.exit(1) except Exception as e: print(f"Error executing command: {command}") print(f"Error message: {e}") @@ -155,13 +165,13 @@ def show_route() -> None: "show ip route supernets-only", "show ip route table all", "show ip route vrf all", - "show ipv6 route bgp | head 108", + "show ipv6 route bgp | head -108", "show ipv6 route cache", "show ipv6 route connected", "show ipv6 route forward", "show ipv6 route isis", "show ipv6 route kernel", - "show ipv6 route ospf", + "show ipv6 route ospfv3", "show ipv6 route rip", "show ipv6 route static", "show ipv6 route summary", @@ -179,8 +189,9 @@ def show_firewall() -> None: def show_system() -> None: """Prints system parameters.""" - execute_command(op('show system image version'), 'Show System Image Version') - execute_command(op('show system image storage'), 'Show System Image Storage') + execute_command(op('show version'), 'Show System Version') + execute_command(op('show system storage'), 'Show System Storage') + execute_command(op('show system image details'), 'Show System Image Details') def show_date() -> None: diff --git a/src/tests/helper.py b/src/tests/helper.py index f7033148a..cc0710494 100644 --- a/src/tests/helper.py +++ b/src/tests/helper.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018 VyOS maintainers and contributors +# Copyright (C) 2018-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_config_diff.py b/src/tests/test_config_diff.py index 61a2f3487..39e17613a 100644 --- a/src/tests/test_config_diff.py +++ b/src/tests/test_config_diff.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright (C) 2023-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify diff --git a/src/tests/test_config_parser.py b/src/tests/test_config_parser.py index c69732daa..9a4f02859 100644 --- a/src/tests/test_config_parser.py +++ b/src/tests/test_config_parser.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright (C) 2018-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify diff --git a/smoketest/scripts/cli/test_configd_inspect.py b/src/tests/test_configd_inspect.py index af46c6148..98552c8f3 100755..100644 --- a/smoketest/scripts/cli/test_configd_inspect.py +++ b/src/tests/test_configd_inspect.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -17,16 +15,16 @@ import os import re import json -import unittest + import warnings import importlib.util -from inspect import signature, getsource +from inspect import signature +from inspect import getsource from functools import wraps +from unittest import TestCase -from vyos.defaults import directories - -INC_FILE = '/usr/share/vyos/configd-include.json' -CONF_DIR = directories['conf_mode'] +INC_FILE = 'data/configd-include.json' +CONF_DIR = 'src/conf_mode' f_list = ['get_config', 'verify', 'generate', 'apply'] @@ -47,7 +45,7 @@ def ignore_deprecation_warning(f): f(*args, **kwargs) return decorated_function -class TestConfigdInclude(unittest.TestCase): +class TestConfigdInspect(TestCase): def setUp(self): with open(INC_FILE) as f: self.inc_list = json.load(f) @@ -105,6 +103,3 @@ class TestConfigdInclude(unittest.TestCase): str_m = getsource(m) n = str_m.count('my_set') self.assertEqual(n, 0, f"'{s}' modifies config") - -if __name__ == '__main__': - unittest.main(verbosity=2) diff --git a/src/tests/test_configverify.py b/src/tests/test_configverify.py index 15ccdf13d..f1ec65cd2 100644 --- a/src/tests/test_configverify.py +++ b/src/tests/test_configverify.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_dependency_graph.py b/src/tests/test_dependency_graph.py index f682e87bb..f3f1db376 100644 --- a/src/tests/test_dependency_graph.py +++ b/src/tests/test_dependency_graph.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright (C) 2023-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_dict_search.py b/src/tests/test_dict_search.py index 2435d89c7..6b4bc933a 100644 --- a/src/tests/test_dict_search.py +++ b/src/tests/test_dict_search.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_find_device_file.py b/src/tests/test_find_device_file.py index f18043d65..5b90f2034 100755..100644 --- a/src/tests/test_find_device_file.py +++ b/src/tests/test_find_device_file.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -28,8 +26,5 @@ class TestDeviceFile(TestCase): def test_zero(self): self.assertEqual(find_device_file('zero'), '/dev/zero') - def test_input_event(self): - self.assertEqual(find_device_file('event0'), '/dev/input/event0') - def test_non_existing(self): self.assertFalse(find_device_file('vyos')) diff --git a/src/tests/test_initial_setup.py b/src/tests/test_initial_setup.py index f85bf1265..4cd5fb169 100644 --- a/src/tests/test_initial_setup.py +++ b/src/tests/test_initial_setup.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright (C) 2018-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify diff --git a/src/tests/test_op_mode.py b/src/tests/test_op_mode.py index 90963b3c5..23f709653 100644 --- a/src/tests/test_op_mode.py +++ b/src/tests/test_op_mode.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2022 VyOS maintainers and contributors +# Copyright (C) 2022-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -62,4 +60,3 @@ class TestVyOSOpMode(TestCase): data = [1, False, "foo"] self.assertEqual(_normalize_field_names(data), [1, False, "foo"]) - diff --git a/src/tests/test_task_scheduler.py b/src/tests/test_task_scheduler.py index 130f825e6..795ffeb9d 100644 --- a/src/tests/test_task_scheduler.py +++ b/src/tests/test_task_scheduler.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2018-2023 VyOS maintainers and contributors +# Copyright (C) 2018-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_template.py b/src/tests/test_template.py index dbb86b40b..6377f6da5 100644 --- a/src/tests/test_template.py +++ b/src/tests/test_template.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify diff --git a/src/tests/test_utils.py b/src/tests/test_utils.py index 9ae329ced..7bfd2618e 100644 --- a/src/tests/test_utils.py +++ b/src/tests/test_utils.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_utils_network.py b/src/tests/test_utils_network.py index 5a6dc2586..d68dec16f 100644 --- a/src/tests/test_utils_network.py +++ b/src/tests/test_utils_network.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# Copyright (C) 2020-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -45,6 +43,3 @@ class TestVyOSUtilsNetwork(TestCase): self.assertFalse(vyos.utils.network.is_loopback_addr('::2')) self.assertFalse(vyos.utils.network.is_loopback_addr('192.0.2.1')) - - - |