From e7772c0fe0e319a59ad69392833d04b328e3969e Mon Sep 17 00:00:00 2001 From: Timothy Miller Date: Tue, 10 Mar 2026 05:37:09 -0400 Subject: [PATCH] Change default IPv4 provider to ipify Update README and tests to reflect new defaults Bump actions/checkout to v6, replace linux/arm/v7 with linux/ppc64le in the Docker build, and normalize tag quoting in the GitHub workflow --- .github/workflows/image.yml | 4 ++-- README.md | 4 ++-- scripts/docker-publish.sh | 2 +- src/config.rs | 6 +++--- src/updater.rs | 20 +++++++++++++++++--- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/image.yml b/.github/workflows/image.yml index 38065c0..fc8e9d3 100644 --- a/.github/workflows/image.yml +++ b/.github/workflows/image.yml @@ -4,7 +4,7 @@ on: push: branches: master tags: - - 'v*' + - "v*" pull_request: jobs: @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/README.md b/README.md index 70287e9..ee5c6fc 100755 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ At least one of `DOMAINS`, `IP4_DOMAINS`, `IP6_DOMAINS`, or `WAF_LISTS` must be | Variable | Default | Description | |----------|---------|-------------| -| `IP4_PROVIDER` | `cloudflare.trace` | IPv4 detection method | +| `IP4_PROVIDER` | `ipify` | IPv4 detection method | | `IP6_PROVIDER` | `cloudflare.trace` | IPv6 detection method | Available providers: @@ -195,7 +195,7 @@ Heartbeats are sent after each update cycle. On failure, a fail signal is sent. | `DOMAINS` | — | 🌐 Domains for both IPv4 and IPv6 | | `IP4_DOMAINS` | — | 4️⃣ IPv4-only domains | | `IP6_DOMAINS` | — | 6️⃣ IPv6-only domains | -| `IP4_PROVIDER` | `cloudflare.trace` | 🔍 IPv4 detection provider | +| `IP4_PROVIDER` | `ipify` | 🔍 IPv4 detection provider | | `IP6_PROVIDER` | `cloudflare.trace` | 🔍 IPv6 detection provider | | `UPDATE_CRON` | `@every 5m` | ⏱️ Update schedule | | `UPDATE_ON_START` | `true` | 🚀 Update on startup | diff --git a/scripts/docker-publish.sh b/scripts/docker-publish.sh index 654b7c6..32c6032 100755 --- a/scripts/docker-publish.sh +++ b/scripts/docker-publish.sh @@ -2,7 +2,7 @@ BASH_DIR=$(dirname $(realpath "${BASH_SOURCE}")) VERSION=$(grep '^version' ${BASH_DIR}/../Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') docker buildx build \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ + --platform linux/amd64,linux/arm64,linux/ppc64le \ --tag timothyjmiller/cloudflare-ddns:latest \ --tag timothyjmiller/cloudflare-ddns:${VERSION} \ --push ${BASH_DIR}/../ diff --git a/src/config.rs b/src/config.rs index 2518843..ae512fe 100644 --- a/src/config.rs +++ b/src/config.rs @@ -243,7 +243,7 @@ fn read_providers_from_env(ppfmt: &PP) -> Result, let ip4_provider = match ip4_str { Some(s) => ProviderType::parse(&s) .map_err(|e| format!("Invalid IP4_PROVIDER: {e}"))?, - None => ProviderType::CloudflareTrace { url: None }, + None => ProviderType::Ipify, }; let ip6_provider = match ip6_str { @@ -1429,12 +1429,12 @@ mod tests { let pp = PP::new(false, true); let providers = read_providers_from_env(&pp).unwrap(); drop(g); - // Both default to CloudflareTrace, so both V4 and V6 are present. + // V4 defaults to Ipify, V6 defaults to CloudflareTrace. assert!(providers.contains_key(&IpType::V4)); assert!(providers.contains_key(&IpType::V6)); assert!(matches!( providers[&IpType::V4], - ProviderType::CloudflareTrace { url: None } + ProviderType::Ipify )); assert!(matches!( providers[&IpType::V6], diff --git a/src/updater.rs b/src/updater.rs index b3ee7e1..0f763c2 100644 --- a/src/updater.rs +++ b/src/updater.rs @@ -314,6 +314,7 @@ impl LegacyDdnsClient { &mut warnings.shown_ipv4, &mut warnings.shown_ipv4_secondary, "IPv4", + true, ) .await; if a.is_none() && purge_unknown_records { @@ -337,6 +338,7 @@ impl LegacyDdnsClient { &mut warnings.shown_ipv6, &mut warnings.shown_ipv6_secondary, "IPv6", + false, ) .await; if aaaa.is_none() && purge_unknown_records { @@ -362,6 +364,7 @@ impl LegacyDdnsClient { shown_primary: &mut bool, shown_secondary: &mut bool, label: &str, + expect_v4: bool, ) -> Option { for (i, url) in urls.iter().enumerate() { match self.client.get(url).send().await { @@ -369,6 +372,17 @@ impl LegacyDdnsClient { if let Some(ip) = crate::provider::parse_trace_ip(&resp.text().await.unwrap_or_default()) { + // Validate the IP matches the expected address family + if let Ok(addr) = ip.parse::() { + if expect_v4 && !addr.is_ipv4() { + eprintln!("{label} trace returned IPv6 address, skipping"); + continue; + } + if !expect_v4 && !addr.is_ipv6() { + eprintln!("{label} trace returned IPv4 address, skipping"); + continue; + } + } return Some(ip); } } @@ -1655,7 +1669,7 @@ mod tests { let mut shown_primary = false; let mut shown_secondary = false; let result = ddns - .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4") + .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4", true) .await; assert_eq!(result, Some("198.51.100.1".to_string())); } @@ -1685,7 +1699,7 @@ mod tests { let mut shown_primary = false; let mut shown_secondary = false; let result = ddns - .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4") + .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4", true) .await; assert_eq!(result, Some("198.51.100.2".to_string())); assert!(shown_primary); @@ -1706,7 +1720,7 @@ mod tests { let mut shown_primary = false; let mut shown_secondary = false; let result = ddns - .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4") + .try_trace_urls(&ddns.ipv4_urls, &mut shown_primary, &mut shown_secondary, "IPv4", true) .await; assert!(result.is_none()); assert!(shown_primary);