From ba43108f552fc3f6e7ef9ba8741c7612d948fb2c Mon Sep 17 00:00:00 2001 From: Michael Pardatscher Date: Fri, 25 Sep 2026 17:45:56 +0000 Subject: haproxy: T8977: allow a listen-address that is not assigned to an interface A listen-address had to be present on an interface at commit time, which refused a perfectly valid configuration: such an address is commonly supplied by a failover mechanism only after the commit, and the kernel permits binding it as soon as the non-local bind sysctl is set. That is accepted now. Co-authored-by: Christian Breunig --- .../scripts/cli/test_load-balancing_haproxy.py | 58 ++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'smoketest/scripts/cli/test_load-balancing_haproxy.py') diff --git a/smoketest/scripts/cli/test_load-balancing_haproxy.py b/smoketest/scripts/cli/test_load-balancing_haproxy.py index 118d42773..66aa16c8f 100755 --- a/smoketest/scripts/cli/test_load-balancing_haproxy.py +++ b/smoketest/scripts/cli/test_load-balancing_haproxy.py @@ -32,6 +32,10 @@ HAPROXY_CONF = '/run/haproxy/haproxy.cfg' base_path = ['load-balancing', 'haproxy'] proxy_interface = 'eth1' +haproxy_service_name = 'https_front' +haproxy_service_port = '4433' +haproxy_backend_name = 'bk-01' + valid_ca_cert = """ MIIDnTCCAoWgAwIBAgIUewSDtLiZbhg1YEslMnqRl1shoPcwDQYJKoZIhvcNAQEL BQAwVzELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcM @@ -136,8 +140,6 @@ ZXLrtgVJR9W020qTurO2f91qfU8646n11hR9ObBB1IYbagOU0Pw1Nrq/FRp/u2tx 7i7xFz2WEiQeSCPaKYOiqM3t """ -haproxy_service_name = 'https_front' -haproxy_backend_name = 'bk-01' def parse_haproxy_config() -> dict: config_str = read_file(HAPROXY_CONF) @@ -173,7 +175,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): def base_config(self): self.cli_set(base_path + ['service', haproxy_service_name, 'mode', 'http']) - self.cli_set(base_path + ['service', haproxy_service_name, 'port', '4433']) + self.cli_set(base_path + ['service', haproxy_service_name, 'port', haproxy_service_port]) self.cli_set(base_path + ['service', haproxy_service_name, 'backend', haproxy_backend_name]) self.cli_set(base_path + ['backend', haproxy_backend_name, 'mode', 'http']) @@ -761,6 +763,56 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): self.assertNotIn(f'bind {addr_busy}:{shared_port}', config) self.assertIn(f'bind [{addr_listen}]:{shared_port}', config) + def test_reverse_proxy_listen_address_lifecycle(self): + """T8977: adding then removing a listen-address must revert haproxy to wildcard.""" + from vyos.utils.network import check_port_availability + + # Use loopback so no real NIC is required + addr_v4 = '127.0.0.1' + addr_v6 = '::1' + svc_laddr_base = base_path + ['service', haproxy_service_name, 'listen-address'] + + # Pre-test before service binds + # Check port availability without address (default to 'any'), must yield true + self.assertTrue(check_port_availability(port=int(haproxy_service_port), protocol='tcp')) + + # Start without a specific listen-address (listen on 'any') + self.base_config() + self.cli_commit() + + # Check port availability without address (default to 'any'), must yield false + self.assertFalse(check_port_availability(port=int(haproxy_service_port), protocol='tcp')) + + # Set a addr_v4 listen-address + self.cli_set(svc_laddr_base + [addr_v4]) + self.cli_commit() + + # Check port availability without address (default to 'any'), must yield false + self.assertFalse(check_port_availability(port=int(haproxy_service_port), protocol='tcp')) + # Check port availability on addr_v4, must yield false + self.assertFalse(check_port_availability(address=addr_v4, port=int(haproxy_service_port), protocol='tcp')) + # Check port availability on addr_v6, must yield true + self.assertTrue(check_port_availability(address=addr_v6, port=int(haproxy_service_port), protocol='tcp')) + + # Set a addr_v6 listen-address + self.cli_delete(svc_laddr_base) + self.cli_set(svc_laddr_base + [addr_v6]) + self.cli_commit() + + # Check port availability without address (default to 'any'), must yield false + self.assertFalse(check_port_availability(port=int(haproxy_service_port), protocol='tcp')) + # Check port availability on addr_v4, must yield true + self.assertTrue(check_port_availability(address=addr_v4, port=int(haproxy_service_port), protocol='tcp')) + # Check port availability on addr_v6, must yield false + self.assertFalse(check_port_availability(address=addr_v6, port=int(haproxy_service_port), protocol='tcp')) + + # Remove the specific listen-address + self.cli_delete(svc_laddr_base) + self.cli_commit() + + # Check port availability without address (default to 'any'), must yield false + self.assertFalse(check_port_availability(port=int(haproxy_service_port), protocol='tcp')) + if __name__ == '__main__': unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on()) -- cgit v1.2.3