From 584cfe42c4ae6a74f3cd05837e095d31565c5b0c Mon Sep 17 00:00:00 2001 From: Jonathan Chun Date: Sun, 15 Jan 2017 10:41:12 -0500 Subject: [PATCH] compare IPv6 addresses correctly with normalization (#1052) --- management/ssl_certificates.py | 4 ++-- management/status_checks.py | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) mode change 100755 => 100644 management/status_checks.py diff --git a/management/ssl_certificates.py b/management/ssl_certificates.py index d7317ae..b0355cf 100755 --- a/management/ssl_certificates.py +++ b/management/ssl_certificates.py @@ -4,7 +4,6 @@ import os, os.path, re, shutil from utils import shell, safe_domain_name, sort_domains - import idna # SELECTING SSL CERTIFICATES FOR USE IN WEB @@ -214,6 +213,7 @@ def get_certificates_to_provision(env, show_extended_problems=True, force_domain # Filter out domains that we can't provision a certificate for. def can_provision_for_domain(domain): + from status_checks import normalize_ip # Let's Encrypt doesn't yet support IDNA domains. # We store domains in IDNA (ASCII). To see if this domain is IDNA, # we'll see if its IDNA-decoded form is different. @@ -252,7 +252,7 @@ def get_certificates_to_provision(env, show_extended_problems=True, force_domain return s # END HOTFIX - if len(response) != 1 or rdata__str__(response[0]) != value: + if len(response) != 1 or normalize_ip(rdata__str__(response[0])) != normalize_ip(value): problems[domain] = "Domain control validation cannot be performed for this domain because DNS points the domain to another machine (%s %s)." % (rtype, ", ".join(rdata__str__(r) for r in response)) return False diff --git a/management/status_checks.py b/management/status_checks.py old mode 100755 new mode 100644 index 3027ea7..30b9a28 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -393,7 +393,7 @@ def check_primary_hostname_dns(domain, env, output, dns_domains, dns_zonefiles): # Check that PRIMARY_HOSTNAME resolves to PUBLIC_IP[V6] in public DNS. ipv6 = query_dns(domain, "AAAA") if env.get("PUBLIC_IPV6") else None - if ip == env['PUBLIC_IP'] and ipv6 in (None, env['PUBLIC_IPV6']): + if ip == env['PUBLIC_IP'] and normalize_ip(ipv6) in (None, normalize_ip(env['PUBLIC_IPV6'])): output.print_ok("Domain resolves to box's IP address. [%s ↦ %s]" % (env['PRIMARY_HOSTNAME'], my_ips)) else: output.print_error("""This domain must resolve to your box's IP address (%s) in public DNS but it currently resolves @@ -700,10 +700,11 @@ def query_dns(qname, rtype, nxdomain='[Not Set]', at=None): # BEGIN HOTFIX response_new = [] for r in response: - if isinstance(r.to_text(), bytes): - response_new.append(r.to_text().decode('utf-8')) - else: - response_new.append(r) + s = r.to_text() + if isinstance(s, bytes): + s = s.decode('utf-8') + response_new.append(s) + response = response_new # END HOTFIX @@ -890,6 +891,11 @@ def run_and_output_changes(env, pool): with open(cache_fn, "w") as f: json.dump(cur.buf, f, indent=True) +def normalize_ip(ip): + # Use ipaddress module to normalize the IPv6 notation and ensure we are matching IPv6 addresses written in different representations according to rfc5952. + import ipaddress + return str(ipaddress.ip_address(ip)) + class FileOutput: def __init__(self, buf, width): self.buf = buf