Commit 584cfe42 authored by Jonathan Chun's avatar Jonathan Chun Committed by Joshua Tauberer

compare IPv6 addresses correctly with normalization (#1052)

parent 41601a59
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import os, os.path, re, shutil import os, os.path, re, shutil
from utils import shell, safe_domain_name, sort_domains from utils import shell, safe_domain_name, sort_domains
import idna import idna
# SELECTING SSL CERTIFICATES FOR USE IN WEB # SELECTING SSL CERTIFICATES FOR USE IN WEB
...@@ -214,6 +213,7 @@ def get_certificates_to_provision(env, show_extended_problems=True, force_domain ...@@ -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. # Filter out domains that we can't provision a certificate for.
def can_provision_for_domain(domain): def can_provision_for_domain(domain):
from status_checks import normalize_ip
# Let's Encrypt doesn't yet support IDNA domains. # Let's Encrypt doesn't yet support IDNA domains.
# We store domains in IDNA (ASCII). To see if this domain is IDNA, # We store domains in IDNA (ASCII). To see if this domain is IDNA,
# we'll see if its IDNA-decoded form is different. # 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 ...@@ -252,7 +252,7 @@ def get_certificates_to_provision(env, show_extended_problems=True, force_domain
return s return s
# END HOTFIX # 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)) 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 return False
......
...@@ -393,7 +393,7 @@ def check_primary_hostname_dns(domain, env, output, dns_domains, dns_zonefiles): ...@@ -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. # Check that PRIMARY_HOSTNAME resolves to PUBLIC_IP[V6] in public DNS.
ipv6 = query_dns(domain, "AAAA") if env.get("PUBLIC_IPV6") else None 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)) output.print_ok("Domain resolves to box's IP address. [%s ↦ %s]" % (env['PRIMARY_HOSTNAME'], my_ips))
else: else:
output.print_error("""This domain must resolve to your box's IP address (%s) in public DNS but it currently resolves 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): ...@@ -700,10 +700,11 @@ def query_dns(qname, rtype, nxdomain='[Not Set]', at=None):
# BEGIN HOTFIX # BEGIN HOTFIX
response_new = [] response_new = []
for r in response: for r in response:
if isinstance(r.to_text(), bytes): s = r.to_text()
response_new.append(r.to_text().decode('utf-8')) if isinstance(s, bytes):
else: s = s.decode('utf-8')
response_new.append(r) response_new.append(s)
response = response_new response = response_new
# END HOTFIX # END HOTFIX
...@@ -890,6 +891,11 @@ def run_and_output_changes(env, pool): ...@@ -890,6 +891,11 @@ def run_and_output_changes(env, pool):
with open(cache_fn, "w") as f: with open(cache_fn, "w") as f:
json.dump(cur.buf, f, indent=True) 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: class FileOutput:
def __init__(self, buf, width): def __init__(self, buf, width):
self.buf = buf self.buf = buf
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment