From 98c4dcdc08a350597eea22215fecc3a9d8a4e01d Mon Sep 17 00:00:00 2001 From: Corentin Forler Date: Fri, 27 Sep 2024 17:58:25 +0200 Subject: [PATCH] feat(IPv6): Allow custom domains with AAAA domains --- press/api/site.py | 42 ++++++++++++++++++- .../press/doctype/site_domain/site_domain.py | 5 ++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/press/api/site.py b/press/api/site.py index aaa9478b29..8da67223c9 100644 --- a/press/api/site.py +++ b/press/api/site.py @@ -1652,6 +1652,37 @@ def check_dns_a(name, domain): return result +def check_dns_aaaa(name, domain): + result = {"type": "AAAA", "matched": False, "answer": ""} + try: + resolver = Resolver(configure=False) + resolver.nameservers = NAMESERVERS + answer = resolver.query(domain, "AAAA") + domain_ip = answer[0].to_text() + site_ip = resolver.query(name, "AAAA")[0].to_text() + result["answer"] = answer.rrset.to_text() + if domain_ip == site_ip: + result["matched"] = True + elif site_ip: + # We can issue certificates even if the domain points to the secondary proxies + server = frappe.db.get_value("Site", name, "server") + proxy = frappe.db.get_value("Server", server, "proxy_server") + secondary_ips = frappe.get_all( + "Proxy Server", + {"status": "Active", "primary": proxy, "is_replication_setup": True}, + pluck="ip6", + ) + if domain_ip in secondary_ips: + result["matched"] = True + except dns.exception.DNSException as e: + result["answer"] = str(e) + except Exception as e: + result["answer"] = str(e) + log_error("DNS Query Exception - AAAA", site=name, domain=domain, exception=e) + finally: + return result + + def ensure_dns_aaaa_record_doesnt_exist(domain: str): """ Ensure that the domain doesn't have an AAAA record @@ -1676,7 +1707,7 @@ def ensure_dns_aaaa_record_doesnt_exist(domain: str): def check_dns_cname_a(name, domain): check_domain_allows_letsencrypt_certs(domain) - ensure_dns_aaaa_record_doesnt_exist(domain) + # ensure_dns_aaaa_record_doesnt_exist(domain) cname = check_dns_cname(name, domain) result = {"CNAME": cname} result.update(cname) @@ -1688,6 +1719,15 @@ def check_dns_cname_a(name, domain): result.update({"A": a}) result.update(a) + # Check that both A and AAAA records match a proxy + aaaa = check_dns_aaaa(name, domain) + result.update({"AAAA": aaaa}) + a_found = a["answer"] and "does not contain an answer" not in a["answer"] + aaaa_found = aaaa["answer"] and "does not contain an answer" not in aaaa["answer"] + if a_found and aaaa_found and a["matched"] != aaaa["matched"]: + # There is both records but one does not match. + result["matched"] = False + return result diff --git a/press/press/doctype/site_domain/site_domain.py b/press/press/doctype/site_domain/site_domain.py index 71f38ca31c..9eff6efaf6 100644 --- a/press/press/doctype/site_domain/site_domain.py +++ b/press/press/doctype/site_domain/site_domain.py @@ -204,9 +204,10 @@ def update_dns_type(): return try: response = check_dns(domain.site, domain.domain) - if response["matched"] and response["type"] != domain.dns_type: + dns_type = "A" if response["type"] == "AAAA" else response["type"] + if response["matched"] and dns_type != domain.dns_type: frappe.db.set_value( - "Site Domain", domain.name, "dns_type", response["type"], update_modified=False + "Site Domain", domain.name, "dns_type", dns_type, update_modified=False ) pretty_response = json.dumps(response, indent=4, default=str) frappe.db.set_value(