From b91b52b9afc74ae87132a9121db715af42c1f29a Mon Sep 17 00:00:00 2001 From: Nils Stein <31704359+mietzen@users.noreply.github.com> Date: Sun, 3 Mar 2024 15:28:04 +0100 Subject: [PATCH] try multiple ipv4 and ipv6 providers --- porkbun_ddns/porkbun_ddns.py | 34 +++++++++++++++----------- porkbun_ddns/test/test_porkbun_ddns.py | 19 +++++++++++++- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/porkbun_ddns/porkbun_ddns.py b/porkbun_ddns/porkbun_ddns.py index 2306554..2713dc2 100644 --- a/porkbun_ddns/porkbun_ddns.py +++ b/porkbun_ddns/porkbun_ddns.py @@ -84,33 +84,39 @@ def get_public_ips(self) -> list: get_ips_from_fritzbox(self.fritzbox_ip)) else: if self.ipv4: + urls = ['https://v4.ident.me', + 'https://api.ipify.org', + 'https://ipv4.icanhazip.com'] try: - response = urllib.request.urlopen('https://v4.ident.me') - if response.getcode() == 200: - public_ips.append(response.read().decode('utf-8')) - else: - logger.warning("Failed to retrieve IPv4 Address! HTTP status code: {}".format(response.code())) - alternative_response = urllib.request.urlopen('https://api.ipify.org/') - if alternative_response.getcode() == 200: - public_ips.append(alternative_response.read().decode('utf-8')) - else: - logger.warning("Failed to retrieve IPv4 Address! HTTP status code: {}".format(response.code())) + for url in urls: + with urllib.request.urlopen(url) as response: + if response.getcode() == 200: + public_ips.append(response.read().decode('utf-8')) + break + logger.warning("Failed to retrieve IPv4 Address from %s! HTTP status code: %s", url, str(response.code())) except URLError: logger.warning("Can't reach IPv4 Address! Check IPv4 connectivity!") if self.ipv6: + urls = ['https://v6.ident.me', + 'https://api6.ipify.org', + 'https://ipv6.icanhazip.com'] try: - public_ips.append(urllib.request.urlopen( - 'https://v6.ident.me').read().decode('utf8')) + for url in urls: + with urllib.request.urlopen(url) as response: + if response.getcode() == 200: + public_ips.append(response.read().decode('utf-8')) + break + logger.warning("Failed to retrieve IPv6 Address from %s! HTTP status code: %s", url, str(response.code())) except URLError: logger.warning("Can't reach IPv6 Address! Check IPv6 connectivity!") - + public_ips = set(public_ips) if not public_ips: raise PorkbunDDNS_Error('Failed to obtain IP Addresses!') return [ipaddress.ip_address(x) for x in public_ips if not ipaddress.ip_address(x).is_unspecified] - + def _api(self, target: str, data: dict = None) -> dict: """Send an API request to a specified target. """ diff --git a/porkbun_ddns/test/test_porkbun_ddns.py b/porkbun_ddns/test/test_porkbun_ddns.py index 76ab52f..5b0ffdf 100644 --- a/porkbun_ddns/test/test_porkbun_ddns.py +++ b/porkbun_ddns/test/test_porkbun_ddns.py @@ -160,7 +160,7 @@ def test_record_overwrite_alias_and_cname(self, mocker=None): '0000:0000:0000:0000:0000:0000:0000:0001, Status: SUCCESS']) @patch('urllib.request.urlopen') - def test_urlopen_returns_500(self, mock_urlopen): + def test_urlopen_returns_500_ipv4(self, mock_urlopen): # Set up the mock to return a response with status code 500 mock_response = MagicMock() mock_response.getcode.return_value = 500 @@ -176,6 +176,23 @@ def test_urlopen_returns_500(self, mock_urlopen): # Verify that the exception has the expected error message self.assertEqual(str(context.exception), 'Failed to obtain IP Addresses!') + @patch('urllib.request.urlopen') + def test_urlopen_returns_500_ipv6(self, mock_urlopen): + # Set up the mock to return a response with status code 500 + mock_response = MagicMock() + mock_response.getcode.return_value = 500 + mock_urlopen.return_value = mock_response + + # Instantiate your class or call the method that uses urllib.request.urlopen() + porkbun_ddns = PorkbunDDNS(valid_config, domain='example.com', ipv4=False, ipv6=True) + + # Now when you call the method that uses urllib.request.urlopen(), it will get the mocked response + with self.assertRaises(PorkbunDDNS_Error) as context: + porkbun_ddns.get_public_ips() + + # Verify that the exception has the expected error message + self.assertEqual(str(context.exception), 'Failed to obtain IP Addresses!') + if __name__ == '__main__': unittest.main()