Highlights
-
Cloudflare IP filtering is now on by default —
REJECT_CLOUDFLARE_IPSdefaults totrue, preventing Cloudflare anycast addresses from being written to DNS
records. If the published IP ranges can't be fetched, updates are skipped entirely to avoid incorrect writes. -
Cached Cloudflare IP ranges — A new
CachedCloudflareFilterfetches Cloudflare's IP ranges once and reuses them for 24 hours. If a refresh fails, the
previously cached ranges are retained with a warning, avoiding unnecessary network calls every update cycle. -
Concurrent range fetching — IPv4 and IPv6 Cloudflare ranges are now fetched in parallel via
tokio::join!, cutting the setup time roughly in half. -
ip4_provider/ip6_providerfor legacy mode — New config options let you override the IP detection provider per address family in legacy mode (e.g.,
"ip4_provider": "ipify","ip6_provider": "cloudflare.doh"). -
Cloudflare IP filtering in legacy mode — The
REJECT_CLOUDFLARE_IPSfilter now applies to legacy mode as well, not just the modern provider path.
Improvements
- Noop deduplication — "Record is up to date" messages are now logged once per domain and suppressed on subsequent cycles until the record actually changes,
keeping logs clean during steady-state operation. - Reuse HTTP client — A single
reqwest::Clientis reused for IP detection across all providers instead of being rebuilt each cycle. - Always ping heartbeat — Heartbeat monitors (Healthchecks, Uptime Kuma) are now pinged every cycle so uptime services know the updater is alive, even when no DNS
changes occurred. - Removed
ipnetdependency — Replaced with a lightweight inlineCidrRangeimplementation, reducing the dependency footprint.
Fixes
- Pushover notification parsing — Fixed the shoutrrr URL parser for Pushover so
pushover://token@usercorrectly mapstokenanduserto the Pushover API
parameters.