From 1490dc820f8b65e598526125040425c91ae8076d Mon Sep 17 00:00:00 2001 From: Rob van Oostenrijk Date: Sun, 18 Aug 2024 10:14:28 +0200 Subject: [PATCH] Refactored IP matching, ignore results of hostname. Added cloudflare direct IPv4 & IPv6 (#4181) --- .../mvc/app/models/OPNsense/DynDNS/DynDNS.xml | 4 +++- .../opnsense/scripts/ddclient/lib/address.py | 23 +++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml index 577b6651a..0888c87ac 100644 --- a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml +++ b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml @@ -139,7 +139,9 @@ web_dyndns An IP service type is required. - cloudflare + cloudflare + cloudflare-ipv4 + cloudflare-ipv6 dyndns freedns he diff --git a/dns/ddclient/src/opnsense/scripts/ddclient/lib/address.py b/dns/ddclient/src/opnsense/scripts/ddclient/lib/address.py index e79fa8c5f..42842e8c1 100755 --- a/dns/ddclient/src/opnsense/scripts/ddclient/lib/address.py +++ b/dns/ddclient/src/opnsense/scripts/ddclient/lib/address.py @@ -26,10 +26,12 @@ import subprocess import re import ipaddress - +from urllib.parse import urlparse checkip_service_list = { 'cloudflare': '%s://one.one.one.one/cdn-cgi/trace', + 'cloudflare-ipv4': '%s://1.1.1.1/cdn-cgi/trace', + 'cloudflare-ipv6': '%s://[2606:4700:4700::1111]/cdn-cgi/trace', 'dyndns': '%s://checkip.dyndns.org/', 'freedns': '%s://freedns.afraid.org/dynamic/check.php', 'he': '%s://checkip.dns.he.net/', @@ -48,17 +50,18 @@ checkip_service_list = { } -def extract_address(txt): +def extract_address(host, txt): """ Extract first IPv4 or IPv6 address from provided string :param txt: text blob :return: str """ - for regexp in [r'[^a-fA-F0-9\:]', r'[^F0-9\.]']: - for line in re.sub(regexp, ' ', txt).split(): - if line.count('.') == 3 or line.count(':') >= 2: + for regexp in [r'(?:\d{1,3}\.){3}\d{1,3}', r'([a-f0-9:]+:+)+[a-f0-9]+']: + matches = re.finditer(regexp, txt) + for match in matches: + if match.group() != host: try: - ipaddress.ip_address(line) - return line + ipaddress.ip_address(match.group()) + return match.group() except ValueError: pass return "" @@ -79,8 +82,10 @@ def checkip(service, proto='https', timeout='10', interface=None): if interface is not None: params.append("--interface") params.append(interface) - params.append(checkip_service_list[service] % proto) - return extract_address(subprocess.run(params, capture_output=True, text=True).stdout) + url = checkip_service_list[service] % proto + params.append(url) + return extract_address(urlparse(url).hostname, + subprocess.run(params, capture_output=True, text=True).stdout) elif service in ['if', 'if6'] and interface is not None: # return first non private IPv[4|6] interface address ifcfg = subprocess.run(['/sbin/ifconfig', interface], capture_output=True, text=True).stdout