diff --git a/README.md b/README.md index 6e39ecf..0353383 100644 --- a/README.md +++ b/README.md @@ -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 the initial DNS record from the request IP; scripts may also pass `myip` or `myipv6` on the registration URL. 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; otherwise the first router update publishes the record. Pending hostnames that are never registered are cleaned up automatically. Use the dashboard secret to rotate the update URL: diff --git a/karldns/routers/management.py b/karldns/routers/management.py index 6daa4da..3f6d361 100644 --- a/karldns/routers/management.py +++ b/karldns/routers/management.py @@ -84,7 +84,7 @@ async def activate_dashboard( management_slug, account, dashboard_csrf_token(management_slug, account), - "Registration needs a public source IP. Try again from your home connection or use the API with myip.", + "The supplied IP address is invalid. Leave IP fields empty and let the router send the first update.", client_ip(request, settings), ), status_code=400, diff --git a/karldns/services/ddns.py b/karldns/services/ddns.py index 8a1a6e8..10ecf06 100644 --- a/karldns/services/ddns.py +++ b/karldns/services/ddns.py @@ -72,21 +72,21 @@ class DdnsService: ipaddr: str | None, myipv6: str | None, ip6addr: str | None, - ) -> None: + ) -> bool: if not dns_backend_configured(self.settings): - return + return False source_ip = client_ip(request, self.settings) source_fallback = source_ip if _is_global_ip(source_ip) else "" - try: - ipv4, ipv6, update_ipv4, update_ipv6 = parse_update_ips( - source_fallback, - myip, - ipaddr, - myipv6, - ip6addr, - ) - except BadIpError as exc: - raise BadIpError("registration needs a public source IP or myip/myipv6 parameter") from exc + 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, + ) lock = self._lock_for(hostname) with lock: planned = self.store.preview_update(hostname, ipv4, ipv6, update_ipv4=update_ipv4, update_ipv6=update_ipv6) @@ -115,6 +115,7 @@ class DdnsService: raise result = self.store.commit_update_result(planned) self.store.log_update_event(hostname, result.ipv4, result.ipv6, UPDATED, "initial dns registered", source_ip) + return True def apply_update( self, diff --git a/karldns/web/templates_public.py b/karldns/web/templates_public.py index 1f3a0a0..fd45fa5 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, for the initial DNS record.myip/myipv6 value is available; otherwise the first router update publishes it.myip, ipaddr, myipv6, and ip6addr.