mirror of
https://github.com/timothymiller/cloudflare-ddns.git
synced 2026-03-21 22:48:57 -03:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
560a3b7b28 | ||
|
|
1b3928865b |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -103,7 +103,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloudflare-ddns"
|
name = "cloudflare-ddns"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"idna",
|
"idna",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloudflare-ddns"
|
name = "cloudflare-ddns"
|
||||||
version = "2.0.1"
|
version = "2.0.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Access your home network remotely via a custom domain name without a static IP"
|
description = "Access your home network remotely via a custom domain name without a static IP"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
|
|||||||
@@ -145,12 +145,15 @@ impl ProviderType {
|
|||||||
|
|
||||||
// --- Cloudflare Trace ---
|
// --- Cloudflare Trace ---
|
||||||
|
|
||||||
/// Primary trace URL uses a hostname so DNS resolves normally, avoiding the
|
/// Primary trace URLs use literal IPs to guarantee the correct address family.
|
||||||
/// problem where WARP/Zero Trust intercepts requests to literal 1.1.1.1.
|
/// api.cloudflare.com is dual-stack, so on dual-stack hosts (e.g. Docker
|
||||||
const CF_TRACE_PRIMARY: &str = "https://api.cloudflare.com/cdn-cgi/trace";
|
/// --net=host with IPv6) the connection may go via IPv6 even when detecting
|
||||||
/// Fallback URLs use literal IPs for when api.cloudflare.com is unreachable.
|
/// IPv4, causing the trace endpoint to return the wrong address family.
|
||||||
const CF_TRACE_V4_FALLBACK: &str = "https://1.0.0.1/cdn-cgi/trace";
|
const CF_TRACE_V4_PRIMARY: &str = "https://1.0.0.1/cdn-cgi/trace";
|
||||||
const CF_TRACE_V6_FALLBACK: &str = "https://[2606:4700:4700::1001]/cdn-cgi/trace";
|
const CF_TRACE_V6_PRIMARY: &str = "https://[2606:4700:4700::1001]/cdn-cgi/trace";
|
||||||
|
/// Fallback uses a hostname, which works when literal IPs are intercepted
|
||||||
|
/// (e.g. Cloudflare WARP/Zero Trust).
|
||||||
|
const CF_TRACE_FALLBACK: &str = "https://api.cloudflare.com/cdn-cgi/trace";
|
||||||
|
|
||||||
pub fn parse_trace_ip(body: &str) -> Option<String> {
|
pub fn parse_trace_ip(body: &str) -> Option<String> {
|
||||||
for line in body.lines() {
|
for line in body.lines() {
|
||||||
@@ -211,13 +214,13 @@ async fn detect_cloudflare_trace(
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let fallback = match ip_type {
|
let primary = match ip_type {
|
||||||
IpType::V4 => CF_TRACE_V4_FALLBACK,
|
IpType::V4 => CF_TRACE_V4_PRIMARY,
|
||||||
IpType::V6 => CF_TRACE_V6_FALLBACK,
|
IpType::V6 => CF_TRACE_V6_PRIMARY,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try primary (api.cloudflare.com — resolves via DNS, avoids literal-IP interception)
|
// Try primary (literal IP — guarantees correct address family)
|
||||||
if let Some(ip) = fetch_trace_ip(&client, CF_TRACE_PRIMARY, timeout).await {
|
if let Some(ip) = fetch_trace_ip(&client, primary, timeout).await {
|
||||||
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||||
return vec![ip];
|
return vec![ip];
|
||||||
}
|
}
|
||||||
@@ -227,8 +230,8 @@ async fn detect_cloudflare_trace(
|
|||||||
&format!("{} not detected via primary, trying fallback", ip_type.describe()),
|
&format!("{} not detected via primary, trying fallback", ip_type.describe()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Try fallback (literal IP — useful when DNS is broken)
|
// Try fallback (hostname-based — works when literal IPs are intercepted by WARP/Zero Trust)
|
||||||
if let Some(ip) = fetch_trace_ip(&client, fallback, timeout).await {
|
if let Some(ip) = fetch_trace_ip(&client, CF_TRACE_FALLBACK, timeout).await {
|
||||||
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||||
return vec![ip];
|
return vec![ip];
|
||||||
}
|
}
|
||||||
@@ -918,14 +921,13 @@ mod tests {
|
|||||||
// ---- trace URL constants ----
|
// ---- trace URL constants ----
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_trace_primary_uses_hostname_not_ip() {
|
fn test_trace_urls() {
|
||||||
// Primary must use a hostname (api.cloudflare.com) so DNS resolves normally
|
// Primary URLs use literal IPs to guarantee correct address family.
|
||||||
// and WARP/Zero Trust doesn't intercept the request.
|
assert!(CF_TRACE_V4_PRIMARY.contains("1.0.0.1"));
|
||||||
assert_eq!(CF_TRACE_PRIMARY, "https://api.cloudflare.com/cdn-cgi/trace");
|
assert!(CF_TRACE_V6_PRIMARY.contains("2606:4700:4700::1001"));
|
||||||
assert!(CF_TRACE_PRIMARY.contains("api.cloudflare.com"));
|
// Fallback uses a hostname for when literal IPs are intercepted (WARP/Zero Trust).
|
||||||
// Fallbacks use literal IPs for when DNS is broken.
|
assert_eq!(CF_TRACE_FALLBACK, "https://api.cloudflare.com/cdn-cgi/trace");
|
||||||
assert!(CF_TRACE_V4_FALLBACK.contains("1.0.0.1"));
|
assert!(CF_TRACE_FALLBACK.contains("api.cloudflare.com"));
|
||||||
assert!(CF_TRACE_V6_FALLBACK.contains("2606:4700:4700::1001"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- build_split_client ----
|
// ---- build_split_client ----
|
||||||
|
|||||||
Reference in New Issue
Block a user