diff options
| -rwxr-xr-x | smoketest/scripts/cli/test_nat64.py | 31 | ||||
| -rwxr-xr-x | src/conf_mode/nat64.py | 32 |
2 files changed, 47 insertions, 16 deletions
diff --git a/smoketest/scripts/cli/test_nat64.py b/smoketest/scripts/cli/test_nat64.py index 077648118..c578da214 100755 --- a/smoketest/scripts/cli/test_nat64.py +++ b/smoketest/scripts/cli/test_nat64.py @@ -20,6 +20,9 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError +from vyos.utils.system import sysctl_read + base_path = ['nat64'] src_path = base_path + ['source'] @@ -48,15 +51,25 @@ class TestNAT64(VyOSUnitTestSHIM.TestCase): pool = '192.0.2.10' pool_port = '1-65535' - self.cli_set(src_path + ['rule', rule, 'source', 'prefix', prefix_v6]) - self.cli_set( - src_path - + ['rule', rule, 'translation', 'pool', translation_rule, 'address', pool] - ) - self.cli_set( - src_path - + ['rule', rule, 'translation', 'pool', translation_rule, 'port', pool_port] - ) + rule_path = src_path + ['rule', rule] + self.cli_set(rule_path + ['source', 'prefix', prefix_v6]) + self.cli_set(rule_path + ['translation', 'pool', translation_rule, + 'address', pool]) + self.cli_set(rule_path + ['translation', 'pool', translation_rule, + 'port', pool_port]) + + # pool_port overlaps with the Linux Kernel ephemeral port range + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + # https://nicmx.github.io/Jool/en/usr-flags-pool4.html#port-range + # Jool is incapable of ensuring pool4 does not intersect with other defined + # port ranges; this validation is the operator’s responsibility. + tmp = sysctl_read('net.ipv4.ip_local_port_range') + _, ephemeral_port_max = map(int, tmp.split()) + pool_port = f'{ephemeral_port_max +1}-{ephemeral_port_max +1000}' + self.cli_set(rule_path + ['translation', 'pool', translation_rule, + 'port', pool_port]) self.cli_commit() # Load the JSON file diff --git a/src/conf_mode/nat64.py b/src/conf_mode/nat64.py index c31806b43..175e9eb1e 100755 --- a/src/conf_mode/nat64.py +++ b/src/conf_mode/nat64.py @@ -34,6 +34,7 @@ from vyos.utils.kernel import check_kmod from vyos.utils.kernel import unload_kmod from vyos.utils.process import cmd from vyos.utils.process import run +from vyos.utils.system import sysctl_read airbag.enable() @@ -92,6 +93,12 @@ def verify(nat64) -> None: # nothing left to do return + # https://nicmx.github.io/Jool/en/usr-flags-pool4.html#port-range + # Jool is incapable of ensuring pool4 does not intersect with other defined + # port ranges; this validation is the operator’s responsibility. + tmp = sysctl_read('net.ipv4.ip_local_port_range') + ephemeral_port_min, ephemeral_port_max = map(int, tmp.split()) + if dict_search('source.rule', nat64): # Ensure only 1 netfilter instance per namespace nf_rules = filter( @@ -123,18 +130,29 @@ def verify(nat64) -> None: pools = dict_search('translation.pool', instance) if pools: for num, pool in pools.items(): + error_msg = f'Source NAT64 rule {rule} translation pool {num}' if 'address' not in pool: - raise ConfigError( - f'Source NAT64 rule {rule} translation pool ' - f'{num} missing address/prefix' - ) + raise ConfigError(f'{error_msg} missing address/prefix') if 'port' not in pool: + raise ConfigError(f'{error_msg} missing port(-range)') + # Split the provided ports, it's either a single port or start-end + tmp = pool['port'].split('-') + if len(tmp) == 1: # single port + pool_min = pool_max = int(tmp[0]) + elif len(tmp) == 2: # port range with start-stop + pool_min, pool_max = map(int, tmp) + else: + raise ConfigError('Invalid port range, this should not happen!') + + # Inclusive overlap check between nat64 translation ports and + # the Linux Kernel ephemeral port range + # overlap if pool_min <= ephemeral_port_max and ephemeral_port_min <= pool_max + if pool_min <= ephemeral_port_max and ephemeral_port_min <= pool_max: raise ConfigError( - f'Source NAT64 rule {rule} translation pool ' - f'{num} missing port(-range)' + f'{error_msg} port range {pool_min}-{pool_max} overlaps with ' + f'local ephemeral range {ephemeral_port_min}-{ephemeral_port_max}' ) - def generate(nat64) -> None: if not nat64: return |
