diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | python/vyos/ifconfig/macsec.py | 2 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_macsec.py | 8 | ||||
-rwxr-xr-x | src/conf_mode/interfaces_macsec.py | 10 | ||||
-rwxr-xr-x | src/conf_mode/nat_cgnat.py | 51 |
5 files changed, 68 insertions, 11 deletions
@@ -78,7 +78,7 @@ vyshim: $(MAKE) -C $(SHIM_DIR) .PHONY: all -all: clean interface_definitions op_mode_definitions check test j2lint vyshim +all: clean interface_definitions op_mode_definitions check test j2lint vyshim check_migration_scripts_executable .PHONY: check .ONESHELL: @@ -103,6 +103,12 @@ test: 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 +.PHONY: check_migration_scripts_executable +.ONESHELL: +check_migration_scripts_executable: + @echo "Checking if migration scripts have executable bit set..." + find src/migration-scripts -type f -not -executable -print -exec false {} + || sh -c 'echo "Found files that are not executable! Add permissions." && exit 1' + .PHONY: j2lint j2lint: ifndef J2LINT diff --git a/python/vyos/ifconfig/macsec.py b/python/vyos/ifconfig/macsec.py index bde1d9aec..383905814 100644 --- a/python/vyos/ifconfig/macsec.py +++ b/python/vyos/ifconfig/macsec.py @@ -66,7 +66,7 @@ class MACsecIf(Interface): cmd = 'ip macsec add {ifname} rx port 1 address'.format(**self.config) cmd += f' {peer_config["mac"]}' self._cmd(cmd) - # Add the rx-key to the address + # Add the encryption key to the address cmd += f' sa 0 pn 1 on key 01 {peer_config["key"]}' self._cmd(cmd) diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py index a4e6840ca..d73895b7f 100755 --- a/smoketest/scripts/cli/test_interfaces_macsec.py +++ b/smoketest/scripts/cli/test_interfaces_macsec.py @@ -225,11 +225,11 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase): self.cli_commit() self.cli_delete(self._base_path + [interface, 'security', 'mka']) - # check validate() - tx-key required + # check validate() - key required with self.assertRaises(ConfigSessionError): self.cli_commit() - # check validate() - tx-key length must match cipher + # check validate() - key length must match cipher self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2]) with self.assertRaises(ConfigSessionError): self.cli_commit() @@ -239,7 +239,7 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase): with self.assertRaises(ConfigSessionError): self.cli_commit() - # check validate() - enabled peer must have both rx-key and MAC defined + # check validate() - enabled peer must have both key and MAC defined self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER']) with self.assertRaises(ConfigSessionError): self.cli_commit() @@ -252,7 +252,7 @@ class MACsecInterfaceTest(BasicInterfaceTest.TestCase): self.cli_commit() self.cli_set(self._base_path + [interface, 'security', 'static', 'peer', 'TESTPEER', 'mac', peer_mac]) - # check validate() - peer rx-key length must match cipher + # check validate() - peer key length must match cipher self.cli_set(self._base_path + [interface, 'security', 'cipher', cipher2]) self.cli_set(self._base_path + [interface, 'security', 'static', 'key', tx_key_2]) with self.assertRaises(ConfigSessionError): diff --git a/src/conf_mode/interfaces_macsec.py b/src/conf_mode/interfaces_macsec.py index eb0ca9a8b..3ede4377a 100755 --- a/src/conf_mode/interfaces_macsec.py +++ b/src/conf_mode/interfaces_macsec.py @@ -103,9 +103,9 @@ def verify(macsec): # Logic to check static configuration if dict_search('security.static', macsec) != None: - # tx-key must be defined + # key must be defined if dict_search('security.static.key', macsec) == None: - raise ConfigError('Static MACsec tx-key must be defined.') + raise ConfigError('Static MACsec key must be defined.') tx_len = len(dict_search('security.static.key', macsec)) @@ -119,12 +119,12 @@ def verify(macsec): if 'peer' not in macsec['security']['static']: raise ConfigError('Must have at least one peer defined for static MACsec') - # For every enabled peer, make sure a MAC and rx-key is defined + # For every enabled peer, make sure a MAC and key is defined for peer, peer_config in macsec['security']['static']['peer'].items(): if 'disable' not in peer_config and ('mac' not in peer_config or 'key' not in peer_config): - raise ConfigError('Every enabled MACsec static peer must have a MAC address and rx-key defined.') + raise ConfigError('Every enabled MACsec static peer must have a MAC address and key defined!') - # check rx-key length against cipher suite + # check key length against cipher suite rx_len = len(peer_config['key']) if dict_search('security.cipher', macsec) == 'gcm-aes-128' and rx_len != GCM_AES_128_LEN: diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py index cb336a35c..34ec64fce 100755 --- a/src/conf_mode/nat_cgnat.py +++ b/src/conf_mode/nat_cgnat.py @@ -23,6 +23,7 @@ from sys import exit from logging.handlers import SysLogHandler from vyos.config import Config +from vyos.configdict import is_node_changed from vyos.template import render from vyos.utils.process import cmd from vyos.utils.process import run @@ -118,6 +119,41 @@ class IPOperations: + [self.ip_network.broadcast_address] ] + def get_prefix_by_ip_range(self): + """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 + """ + 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) + + return f"{network_address}/{prefix_length}" + return self.ip_prefix + + +def _delete_conntrack_entries(source_prefixes: list) -> None: + """Delete all conntrack entries for the list of prefixes""" + for source_prefix in source_prefixes: + run(f'conntrack -D -s {source_prefix}') + def generate_port_rules( external_hosts: list, @@ -188,6 +224,9 @@ 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': {}}) + return config @@ -386,6 +425,18 @@ def apply(config): # 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: |