mirror of
https://github.com/timothymiller/cloudflare-ddns.git
synced 2026-03-22 06:58:57 -03:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ca4a5eae | ||
|
|
94ce10fccc | ||
|
|
7e96816740 | ||
|
|
8a4b57c163 | ||
|
|
3c7072f4b6 | ||
|
|
3d796d470c | ||
|
|
36bdbea568 | ||
|
|
6085ba0cc2 |
10
.github/workflows/image.yml
vendored
10
.github/workflows/image.yml
vendored
@@ -15,14 +15,14 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: timothyjmiller/cloudflare-ddns
|
||||
tags: |
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
type=raw,enable=${{ github.ref == 'refs/heads/master' }},value=${{ steps.version.outputs.version }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloudflare-ddns"
|
||||
version = "2.0.2"
|
||||
version = "2.0.3"
|
||||
edition = "2021"
|
||||
description = "Access your home network remotely via a custom domain name without a static IP"
|
||||
license = "GPL-3.0"
|
||||
|
||||
@@ -164,13 +164,17 @@ pub fn parse_trace_ip(body: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn fetch_trace_ip(client: &Client, url: &str, timeout: Duration) -> Option<IpAddr> {
|
||||
let resp = client
|
||||
.get(url)
|
||||
.timeout(timeout)
|
||||
.send()
|
||||
.await
|
||||
.ok()?;
|
||||
async fn fetch_trace_ip(
|
||||
client: &Client,
|
||||
url: &str,
|
||||
timeout: Duration,
|
||||
host_override: Option<&str>,
|
||||
) -> Option<IpAddr> {
|
||||
let mut req = client.get(url).timeout(timeout);
|
||||
if let Some(host) = host_override {
|
||||
req = req.header("Host", host);
|
||||
}
|
||||
let resp = req.send().await.ok()?;
|
||||
let body = resp.text().await.ok()?;
|
||||
let ip_str = parse_trace_ip(&body)?;
|
||||
ip_str.parse::<IpAddr>().ok()
|
||||
@@ -202,7 +206,7 @@ async fn detect_cloudflare_trace(
|
||||
let client = build_split_client(ip_type, timeout);
|
||||
|
||||
if let Some(url) = custom_url {
|
||||
if let Some(ip) = fetch_trace_ip(&client, url, timeout).await {
|
||||
if let Some(ip) = fetch_trace_ip(&client, url, timeout, None).await {
|
||||
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||
return vec![ip];
|
||||
}
|
||||
@@ -220,7 +224,7 @@ async fn detect_cloudflare_trace(
|
||||
};
|
||||
|
||||
// Try primary (literal IP — guarantees correct address family)
|
||||
if let Some(ip) = fetch_trace_ip(&client, primary, timeout).await {
|
||||
if let Some(ip) = fetch_trace_ip(&client, primary, timeout, Some("one.one.one.one")).await {
|
||||
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||
return vec![ip];
|
||||
}
|
||||
@@ -231,7 +235,7 @@ async fn detect_cloudflare_trace(
|
||||
);
|
||||
|
||||
// Try fallback (hostname-based — works when literal IPs are intercepted by WARP/Zero Trust)
|
||||
if let Some(ip) = fetch_trace_ip(&client, CF_TRACE_FALLBACK, timeout).await {
|
||||
if let Some(ip) = fetch_trace_ip(&client, CF_TRACE_FALLBACK, timeout, None).await {
|
||||
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||
return vec![ip];
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ pub async fn update_once(
|
||||
|
||||
let mut all_ok = true;
|
||||
let mut messages = Vec::new();
|
||||
let mut notify = false; // NEW: track meaningful events
|
||||
|
||||
if config.legacy_mode {
|
||||
all_ok = update_legacy(config, ppfmt).await;
|
||||
@@ -108,6 +109,7 @@ pub async fn update_once(
|
||||
|
||||
match result {
|
||||
SetResult::Updated => {
|
||||
notify = true; // NEW
|
||||
let ip_strs: Vec<String> = ips.iter().map(|ip| ip.to_string()).collect();
|
||||
messages.push(Message::new_ok(&format!(
|
||||
"Updated {domain_str} -> {}",
|
||||
@@ -115,6 +117,7 @@ pub async fn update_once(
|
||||
)));
|
||||
}
|
||||
SetResult::Failed => {
|
||||
notify = true; // NEW
|
||||
all_ok = false;
|
||||
messages.push(Message::new_fail(&format!(
|
||||
"Failed to update {domain_str}"
|
||||
@@ -147,12 +150,14 @@ pub async fn update_once(
|
||||
|
||||
match result {
|
||||
SetResult::Updated => {
|
||||
notify = true; // NEW
|
||||
messages.push(Message::new_ok(&format!(
|
||||
"Updated WAF list {}",
|
||||
waf_list.describe()
|
||||
)));
|
||||
}
|
||||
SetResult::Failed => {
|
||||
notify = true; // NEW
|
||||
all_ok = false;
|
||||
messages.push(Message::new_fail(&format!(
|
||||
"Failed to update WAF list {}",
|
||||
@@ -164,13 +169,17 @@ pub async fn update_once(
|
||||
}
|
||||
}
|
||||
|
||||
// Send heartbeat
|
||||
// Send heartbeat ONLY if something meaningful happened
|
||||
if notify {
|
||||
let heartbeat_msg = Message::merge(messages.clone());
|
||||
heartbeat.ping(&heartbeat_msg).await;
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
// Send notifications ONLY when IP changed or failed
|
||||
if notify {
|
||||
let notifier_msg = Message::merge(messages);
|
||||
notifier.send(¬ifier_msg).await;
|
||||
}
|
||||
|
||||
all_ok
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user