From 9e002d13071e9ef97e3727ff28abf8b2307a12c9 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..31c6cbfab1 100644 --- a/src/subscription_manager/utils.py +++ b/src/subscription_manager/utils.py @@ -117,6 +117,11 @@ def format_baseurl(hostname: str, port: str, prefix: str) -> str: if prefix == DEFAULT_CDN_PREFIX: prefix = prefix[:-1] + # Handle raw IPv6 addresses. + # RFC 1035 only allows characters `a-zA-Z0-9.`, we can do this. + if ":" in hostname: + hostname = f"[{hostname}]" + # just so we match how we format this by # default if port == DEFAULT_CDN_PORT: diff --git a/test/test_utils.py b/test/test_utils.py index f4afa7bd99..3110a03709 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):