From 98b74e29ba364dbd3be8dd6c7f2c148fe693ce9b Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 11:32:14 +0800 Subject: [PATCH 1/6] Add getIP helper function Reduces code repetition and ensures failures get raised --- cloudflare-ddns.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 64dc6e9..8d8caa7 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -53,6 +53,19 @@ def deleteEntries(type): print("🗑️ Deleted stale record " + identifier) +def getIP(endpoint, **kwargs): + # Helper function for getting IPv4 or IPv6 address + # from a specified endpoint. Raises an error + # in the case of a response or return value failure. + timeout = kwargs.get("timeout", 10) + response = requests.get(endpoint, timeout=timeout) + # raise any error status + response.raise_for_status() + # create list out of response + l = [line for line in response.text.split("\n") if line.strip()] + return dict(i.split("=") for i in l)["ip"] + + def getIPs(): a = None aaaa = None From cbb5ead02f97479538228de85ea042eb357cabcc Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 11:33:56 +0800 Subject: [PATCH 2/6] Use helper function to obtain IP --- cloudflare-ddns.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 8d8caa7..1795050 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -74,10 +74,7 @@ def getIPs(): global purgeUnknownRecords if ipv4_enabled: try: - a = requests.get( - "https://1.1.1.1/cdn-cgi/trace").text.split("\n") - a.pop() - a = dict(s.split("=") for s in a)["ip"] + a = getIP("https://1.1.1.1/cdn-cgi/trace") except Exception: global shown_ipv4_warning if not shown_ipv4_warning: @@ -85,10 +82,7 @@ def getIPs(): print("🧩 IPv4 not detected via 1.1.1.1, trying 1.0.0.1") # Try secondary IP check try: - a = requests.get( - "https://1.0.0.1/cdn-cgi/trace").text.split("\n") - a.pop() - a = dict(s.split("=") for s in a)["ip"] + a = getIP("https://1.0.0.1/cdn-cgi/trace") except Exception: global shown_ipv4_warning_secondary if not shown_ipv4_warning_secondary: @@ -98,20 +92,15 @@ def getIPs(): deleteEntries("A") if ipv6_enabled: try: - aaaa = requests.get( - "https://[2606:4700:4700::1111]/cdn-cgi/trace").text.split("\n") - aaaa.pop() - aaaa = dict(s.split("=") for s in aaaa)["ip"] + aaaa = getIP("https://[2606:4700:4700::1111]/cdn-cgi/trace") except Exception: global shown_ipv6_warning if not shown_ipv6_warning: shown_ipv6_warning = True print("🧩 IPv6 not detected via 1.1.1.1, trying 1.0.0.1") + # Try secondary IP check try: - aaaa = requests.get( - "https://[2606:4700:4700::1001]/cdn-cgi/trace").text.split("\n") - aaaa.pop() - aaaa = dict(s.split("=") for s in aaaa)["ip"] + aaaa = getIP("https://[2606:4700:4700::1001]/cdn-cgi/trace") except Exception: global shown_ipv6_warning_secondary if not shown_ipv6_warning_secondary: From dcd28e9353cdabfb7febc3ab58b0b63a48000a85 Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 16:31:27 +0800 Subject: [PATCH 3/6] Support both key-value and single value endpoint types Allows acquiring IPv4/6 address from key-value (i.e. https://1.1.1.1/cdn-cgi/trace) and single-value (i.e. https://ipv4.icanhazip.com) --- cloudflare-ddns.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 1795050..4191de6 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -63,7 +63,8 @@ def getIP(endpoint, **kwargs): response.raise_for_status() # create list out of response l = [line for line in response.text.split("\n") if line.strip()] - return dict(i.split("=") for i in l)["ip"] + # support both key-value and single value endpoint types + return dict(i.split("=") for i in l)["ip"] if len(l) > 1 else l[0] def getIPs(): From e969a99e40902f6c6132dda416cf88c8b0f2adc1 Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 16:36:40 +0800 Subject: [PATCH 4/6] Set and use ipv4_endpoints and ipv6_endpoints global vars These vars could potentially be added as new config options to set the primary and fallback endpoints --- cloudflare-ddns.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 4191de6..196742d 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -72,10 +72,12 @@ def getIPs(): aaaa = None global ipv4_enabled global ipv6_enabled + global ipv4_endpoints + global ipv6_endpoints global purgeUnknownRecords if ipv4_enabled: try: - a = getIP("https://1.1.1.1/cdn-cgi/trace") + a = getIP(ipv4_endpoints[0]) except Exception: global shown_ipv4_warning if not shown_ipv4_warning: @@ -83,7 +85,7 @@ def getIPs(): print("🧩 IPv4 not detected via 1.1.1.1, trying 1.0.0.1") # Try secondary IP check try: - a = getIP("https://1.0.0.1/cdn-cgi/trace") + a = getIP(ipv4_endpoints[-1]) except Exception: global shown_ipv4_warning_secondary if not shown_ipv4_warning_secondary: @@ -93,7 +95,7 @@ def getIPs(): deleteEntries("A") if ipv6_enabled: try: - aaaa = getIP("https://[2606:4700:4700::1111]/cdn-cgi/trace") + aaaa = getIP(ipv6_endpoints[0]) except Exception: global shown_ipv6_warning if not shown_ipv6_warning: @@ -101,7 +103,7 @@ def getIPs(): print("🧩 IPv6 not detected via 1.1.1.1, trying 1.0.0.1") # Try secondary IP check try: - aaaa = getIP("https://[2606:4700:4700::1001]/cdn-cgi/trace") + aaaa = getIP(ipv6_endpoints[-1]) except Exception: global shown_ipv6_warning_secondary if not shown_ipv6_warning_secondary: @@ -258,6 +260,8 @@ def updateIPs(ips): shown_ipv6_warning_secondary = False ipv4_enabled = True ipv6_enabled = True + ipv4_endpoints = ("https://1.1.1.1/cdn-cgi/trace", "https://1.0.0.1/cdn-cgi/trace") + ipv6_endpoints = ("https://[2606:4700:4700::1111]/cdn-cgi/trace", "https://[2606:4700:4700::1001]/cdn-cgi/trace") purgeUnknownRecords = False if sys.version_info < (3, 5): From 44015e05b27a7f85fcc39a4289b7f65d5a844a71 Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 16:39:25 +0800 Subject: [PATCH 5/6] Accurately report IP endpoint that was used --- cloudflare-ddns.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 196742d..8b78f71 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -9,6 +9,7 @@ __version__ = "1.0.2" from string import Template +from urllib.parse import urlparse import json import os @@ -82,7 +83,7 @@ def getIPs(): global shown_ipv4_warning if not shown_ipv4_warning: shown_ipv4_warning = True - print("🧩 IPv4 not detected via 1.1.1.1, trying 1.0.0.1") + print("🧩 IPv4 not detected via %s, trying %s" % (urlparse(ipv4_endpoints[0]).netloc, urlparse(ipv4_endpoints[-1]).netloc)) # Try secondary IP check try: a = getIP(ipv4_endpoints[-1]) @@ -90,7 +91,7 @@ def getIPs(): global shown_ipv4_warning_secondary if not shown_ipv4_warning_secondary: shown_ipv4_warning_secondary = True - print("🧩 IPv4 not detected via 1.0.0.1. Verify your ISP or DNS provider isn't blocking Cloudflare's IPs.") + print("🧩 IPv4 not detected via %s. Verify your ISP or DNS provider isn't blocking Cloudflare's IPs." % urlparse(ipv4_endpoints[-1]).netloc) if purgeUnknownRecords: deleteEntries("A") if ipv6_enabled: @@ -100,7 +101,7 @@ def getIPs(): global shown_ipv6_warning if not shown_ipv6_warning: shown_ipv6_warning = True - print("🧩 IPv6 not detected via 1.1.1.1, trying 1.0.0.1") + print("🧩 IPv6 not detected via %s, trying %s" % (urlparse(ipv6_endpoints[0]).netloc, urlparse(ipv6_endpoints[-1]).netloc)) # Try secondary IP check try: aaaa = getIP(ipv6_endpoints[-1]) @@ -108,7 +109,7 @@ def getIPs(): global shown_ipv6_warning_secondary if not shown_ipv6_warning_secondary: shown_ipv6_warning_secondary = True - print("🧩 IPv6 not detected via 1.0.0.1. Verify your ISP or DNS provider isn't blocking Cloudflare's IPs.") + print("🧩 IPv6 not detected via %s. Verify your ISP or DNS provider isn't blocking Cloudflare's IPs." % urlparse(ipv6_endpoints[-1]).netloc) if purgeUnknownRecords: deleteEntries("AAAA") ips = {} From ba37a97d5008d457e625e511b6c7c763ec20d2e2 Mon Sep 17 00:00:00 2001 From: Irfan Hakim Date: Tue, 26 Nov 2024 16:45:42 +0800 Subject: [PATCH 6/6] Replace 1.0.0.1 with icanhazip.com as fallback IPv4/6 endpoints Sensible fallback endpoint in case Cloudflare's are unavailable --- cloudflare-ddns.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudflare-ddns.py b/cloudflare-ddns.py index 8b78f71..24cf3f9 100755 --- a/cloudflare-ddns.py +++ b/cloudflare-ddns.py @@ -261,8 +261,8 @@ def updateIPs(ips): shown_ipv6_warning_secondary = False ipv4_enabled = True ipv6_enabled = True - ipv4_endpoints = ("https://1.1.1.1/cdn-cgi/trace", "https://1.0.0.1/cdn-cgi/trace") - ipv6_endpoints = ("https://[2606:4700:4700::1111]/cdn-cgi/trace", "https://[2606:4700:4700::1001]/cdn-cgi/trace") + ipv4_endpoints = ("https://1.1.1.1/cdn-cgi/trace", "https://ipv4.icanhazip.com") + ipv6_endpoints = ("https://[2606:4700:4700::1111]/cdn-cgi/trace", "https://ipv6.icanhazip.com") purgeUnknownRecords = False if sys.version_info < (3, 5):