From 8dfd89fe1fd41576790cc62097fbf4ddd8ffa613 Mon Sep 17 00:00:00 2001 From: mhorky Date: Mon, 16 Oct 2023 15:43:05 +0200 Subject: [PATCH] CCT-10: Ensure IPv6-based URLs are properly formatted * Card ID: CCT-10 Recent changes (e83e637) fixed parsing information from IPv6 URLs. This patch fixes writing these addresses back as strings, mainly into configuration files. Previously, passing in IPv6 URL in e.g. `--baseurl` during registration resulted in broken address in the config file: $ subscription-manager register --baseurl https://[::1]:8443/prefix $ cat /etc/rhsm/rhsm.conf | grep baseurl baseurl=https://::1:8443/prefix After this patch, the square brackets are written when port is specified: $ cat /etc/rhsm/rhsm.conf | grep baseurl baseurl=https://[::1]:8443/prefix Due to the state of the code, it is likely that this problem also exists in other parts. If that is true, it is most likely in less sensitive parts, such as during logging. Looking back, using `ipaddress` stdlib would have been the right way to do this, but it is too late to do that. --- src/subscription_manager/utils.py | 5 +++++ test/test_utils.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/subscription_manager/utils.py b/src/subscription_manager/utils.py index 724f1a3aad..283916f1ba 100644 --- a/src/subscription_manager/utils.py +++ b/src/subscription_manager/utils.py @@ -122,6 +122,11 @@ def format_baseurl(hostname: str, port: str, prefix: str) -> str: if port == DEFAULT_CDN_PORT: return "https://%s%s" % (hostname, prefix) + # Handle raw IPv6 addresses. + # RFC 1035 only allows characters `a-zA-Z0-9.`, we can do this. + if ":" in hostname: + hostname = f"[{hostname}]" + return "https://%s:%s%s" % (hostname, port, prefix) diff --git a/test/test_utils.py b/test/test_utils.py index f4afa7bd99..02ed354bd7 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -290,6 +290,22 @@ def test_format_not_fqdn_with_port(self): self.assertEqual(prefix, DEFAULT_CDN_PREFIX) self.assertEqual("https://foo-bar:8088", format_baseurl(hostname, port, prefix)) + def test_ipv4(self): + result = format_baseurl(hostname="127.0.0.1", port="8080", prefix="/foo") + self.assertEqual("https://127.0.0.1:8080/foo", result) + + def test_ipv6(self): + result = format_baseurl(hostname="::1", port="8080", prefix="/foo") + self.assertEqual("https://[::1]:8080/foo", result) + + def test_ipv6_default_port(self): + result = format_baseurl(hostname="::1", port="443", prefix="/foo") + self.assertEqual("https://::1/foo", result) + + def test_ipv6_no_prefix(self): + result = format_baseurl(hostname="::1", port="8080", prefix="/") + self.assertEqual("https://[::1]:8080", result) + class TestUrlBaseJoinEmptyBase(fixture.SubManFixture): def test_blank_base_blank_url(self):