• DcRouter v32.6.0
    Release / build-and-release (push) Successful in 26m16s
    Stable

    jkunz released this 2026-09-26 17:03:29 +00:00 | 14 commits to main since this release

    2026-09-26 - 32.6.0

    Features

    • Report stored routes that cannot be served. Route warnings (IRouteWarning) gain the type route-ingress-disabled: a stored route whose only ingress paths are off (SmartVPN or the RemoteIngress hub not running) is left out of the applied routes and listed with this warning, instead of stopping every other route.

    Fixes

    • Hold one local mirror row per provider DNS record. Releases before 19.1.0 ran provider-zone syncs, gateway route DNS reconciles and mail DNS reconciles concurrently, so two writers could each mirror the same new provider record; syncDomain() then refuses the zone with Local mirror has duplicate provider record id …, and every automated DNS write for that zone fails as zone-unavailable until the row is removed. DnsRecordDoc now stores providerRecordKey (<domainId>:<providerRecordId>), derived in one place (ts/dns/provider-record-key.ts) by createSavableObject() and by the ACME and testing mirror writers, and cleared with the provider id when a zone migrates to dcrouter. The sparse unique index provider_record_key_unique makes a racing second mirror insert fail instead of persisting. The new migration step reconcile-provider-record-mirror-duplicates (32.0.1 to 32.6.0) keeps the row that carries managedBy ownership and deletes its unowned synced copies, keeps the oldest row where none is owned, trims stored ids, backfills the key and then creates the index. It deletes local mirror rows only and never calls the provider. When rows with different owners share one provider record, it refuses by name and changes nothing. The error lists the domain, the provider id, the row ids and the owners.
    • Start dcrouter when neither SmartVPN nor a RemoteIngress hub runs. Since 17.9.0 every route without an explicit ingress policy, including the generated dns-over-https-dns-query route and email routes, was authorized for SmartVPN, and a remoteIngress route for the edge tunnel, whether or not that runtime was on. The listener therefore got inboundProxyProtocol optional or required while SmartProxy had no trusted proxy, and SmartProxy refused the route set: Route 'dns-over-https-dns-query': inboundProxyProtocol mode optional/required needs trustedProxyIPs or global trustedProxyIPs, a critical startup failure. Ingress origins are now authorized only for the paths whose runtime is on: smartVpn when vpnConfig.enabled, trustedProxy when the RemoteIngress hub is enabled. A listener that only direct traffic reaches gets reject. A route created through the API whose only declared paths are off, for example a VPN-only route on a hub without SmartVPN, is now left out of the applied route set on its own. Every other route is still applied, at startup and on every route application. The route is logged at warn when it is first refused and listed among the route warnings of getMergedRoutes and the Ops UI routes view as route-ingress-disabled. A route from dcrouter's own configuration whose only paths are off still fails startup with Route '<name>' has no enabled ingress path, because it restates the operator's options.
    Downloads