diff --git a/README.md b/README.md index 0353383..00a999f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ KarlDNS lets you host your own managed DynDNS service: 3. KarlDNS shows the exact router settings and private values. 4. The user confirms they saved the values, which registers the hostname. 5. The router periodically calls the update URL with its current public IPv4/IPv6 address. -6. KarlDNS publishes the matching DNS records through your configured DNS backend. +6. KarlDNS publishes the matching DNS records through your configured DNS backend. If no public IP is visible during registration, it publishes a temporary `192.0.2.1` A record until the router sends its first real update. 7. If the user wants their own DNS name, they can create a CNAME to the generated hostname. That means users always have a current hostname for VPN, remote access, self-hosted apps, home servers, NAS devices, and lab networks. @@ -335,7 +335,7 @@ Example: curl -sS -X POST https://karldns.de/api/v1/hostnames ``` -The create response includes `registration_url`, `update_url`, and `dashboard_url`. Save the returned secrets, then `POST` the registration URL before using the update URL. Registration publishes an initial DNS record when a public request IP or explicit `myip`/`myipv6` value is available; otherwise the first router update publishes the record. Pending hostnames that are never registered are cleaned up automatically. +The create response includes `registration_url`, `update_url`, and `dashboard_url`. Save the returned secrets, then `POST` the registration URL before using the update URL. Registration publishes an initial DNS record when a public request IP or explicit `myip`/`myipv6` value is available. If no public IP is visible, KarlDNS publishes a temporary `192.0.2.1` A record and replaces it on the first router update. Pending hostnames that are never registered are cleaned up automatically. Use the dashboard secret to rotate the update URL: diff --git a/karldns/services/ddns.py b/karldns/services/ddns.py index 10ecf06..8d36141 100644 --- a/karldns/services/ddns.py +++ b/karldns/services/ddns.py @@ -20,6 +20,7 @@ from ..settings import DdnsSettings from ..store import DdnsStore LOGGER = logging.getLogger(__name__) +INITIAL_PLACEHOLDER_IPV4 = "192.0.2.1" @dataclass(slots=True) @@ -79,14 +80,20 @@ class DdnsService: source_fallback = source_ip if _is_global_ip(source_ip) else "" supplied_ip = any(value and value.strip() for value in (myip, ipaddr, myipv6, ip6addr)) if not supplied_ip and not source_fallback: - return False - ipv4, ipv6, update_ipv4, update_ipv6 = parse_update_ips( - source_fallback, - myip, - ipaddr, - myipv6, - ip6addr, - ) + ipv4 = INITIAL_PLACEHOLDER_IPV4 + ipv6 = None + update_ipv4 = True + update_ipv6 = False + detail = "initial placeholder dns registered" + else: + ipv4, ipv6, update_ipv4, update_ipv6 = parse_update_ips( + source_fallback, + myip, + ipaddr, + myipv6, + ip6addr, + ) + detail = "initial dns registered" lock = self._lock_for(hostname) with lock: planned = self.store.preview_update(hostname, ipv4, ipv6, update_ipv4=update_ipv4, update_ipv6=update_ipv6) @@ -114,7 +121,7 @@ class DdnsService: self.store.log_update_event(hostname, ipv4, ipv6, DNS_FAILED, f"{type(exc).__name__}: {exc}", source_ip) raise result = self.store.commit_update_result(planned) - self.store.log_update_event(hostname, result.ipv4, result.ipv6, UPDATED, "initial dns registered", source_ip) + self.store.log_update_event(hostname, result.ipv4, result.ipv6, UPDATED, detail, source_ip) return True def apply_update( diff --git a/karldns/web/templates_public.py b/karldns/web/templates_public.py index fd45fa5..d431ce0 100644 --- a/karldns/web/templates_public.py +++ b/karldns/web/templates_public.py @@ -183,7 +183,7 @@ def _render_api_docs_page(settings: DdnsSettings, request_ip: str | None = None)
registration_url.myip/myipv6 value is available; otherwise the first router update publishes it.myip/myipv6 value. If no public IP is visible, publishes a temporary 192.0.2.1 A record until the first router update.myip, ipaddr, myipv6, and ip6addr.