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
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: timothyjmiller/cloudflare-ddns
|
images: timothyjmiller/cloudflare-ddns
|
||||||
tags: |
|
tags: |
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
type=raw,enable=${{ github.ref == 'refs/heads/master' }},value=${{ steps.version.outputs.version }}
|
type=raw,enable=${{ github.ref == 'refs/heads/master' }},value=${{ steps.version.outputs.version }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloudflare-ddns"
|
name = "cloudflare-ddns"
|
||||||
version = "2.0.2"
|
version = "2.0.3"
|
||||||
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"
|
||||||
|
|||||||
@@ -164,13 +164,17 @@ pub fn parse_trace_ip(body: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_trace_ip(client: &Client, url: &str, timeout: Duration) -> Option<IpAddr> {
|
async fn fetch_trace_ip(
|
||||||
let resp = client
|
client: &Client,
|
||||||
.get(url)
|
url: &str,
|
||||||
.timeout(timeout)
|
timeout: Duration,
|
||||||
.send()
|
host_override: Option<&str>,
|
||||||
.await
|
) -> Option<IpAddr> {
|
||||||
.ok()?;
|
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 body = resp.text().await.ok()?;
|
||||||
let ip_str = parse_trace_ip(&body)?;
|
let ip_str = parse_trace_ip(&body)?;
|
||||||
ip_str.parse::<IpAddr>().ok()
|
ip_str.parse::<IpAddr>().ok()
|
||||||
@@ -202,7 +206,7 @@ async fn detect_cloudflare_trace(
|
|||||||
let client = build_split_client(ip_type, timeout);
|
let client = build_split_client(ip_type, timeout);
|
||||||
|
|
||||||
if let Some(url) = custom_url {
|
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) {
|
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||||
return vec![ip];
|
return vec![ip];
|
||||||
}
|
}
|
||||||
@@ -220,7 +224,7 @@ async fn detect_cloudflare_trace(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Try primary (literal IP — guarantees correct address family)
|
// 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) {
|
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||||
return vec![ip];
|
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)
|
// 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) {
|
if validate_detected_ip(&ip, ip_type, ppfmt) {
|
||||||
return vec![ip];
|
return vec![ip];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ pub async fn update_once(
|
|||||||
|
|
||||||
let mut all_ok = true;
|
let mut all_ok = true;
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
|
let mut notify = false; // NEW: track meaningful events
|
||||||
|
|
||||||
if config.legacy_mode {
|
if config.legacy_mode {
|
||||||
all_ok = update_legacy(config, ppfmt).await;
|
all_ok = update_legacy(config, ppfmt).await;
|
||||||
@@ -108,6 +109,7 @@ pub async fn update_once(
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
SetResult::Updated => {
|
SetResult::Updated => {
|
||||||
|
notify = true; // NEW
|
||||||
let ip_strs: Vec<String> = ips.iter().map(|ip| ip.to_string()).collect();
|
let ip_strs: Vec<String> = ips.iter().map(|ip| ip.to_string()).collect();
|
||||||
messages.push(Message::new_ok(&format!(
|
messages.push(Message::new_ok(&format!(
|
||||||
"Updated {domain_str} -> {}",
|
"Updated {domain_str} -> {}",
|
||||||
@@ -115,6 +117,7 @@ pub async fn update_once(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
SetResult::Failed => {
|
SetResult::Failed => {
|
||||||
|
notify = true; // NEW
|
||||||
all_ok = false;
|
all_ok = false;
|
||||||
messages.push(Message::new_fail(&format!(
|
messages.push(Message::new_fail(&format!(
|
||||||
"Failed to update {domain_str}"
|
"Failed to update {domain_str}"
|
||||||
@@ -147,12 +150,14 @@ pub async fn update_once(
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
SetResult::Updated => {
|
SetResult::Updated => {
|
||||||
|
notify = true; // NEW
|
||||||
messages.push(Message::new_ok(&format!(
|
messages.push(Message::new_ok(&format!(
|
||||||
"Updated WAF list {}",
|
"Updated WAF list {}",
|
||||||
waf_list.describe()
|
waf_list.describe()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
SetResult::Failed => {
|
SetResult::Failed => {
|
||||||
|
notify = true; // NEW
|
||||||
all_ok = false;
|
all_ok = false;
|
||||||
messages.push(Message::new_fail(&format!(
|
messages.push(Message::new_fail(&format!(
|
||||||
"Failed to update WAF list {}",
|
"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());
|
let heartbeat_msg = Message::merge(messages.clone());
|
||||||
heartbeat.ping(&heartbeat_msg).await;
|
heartbeat.ping(&heartbeat_msg).await;
|
||||||
|
}
|
||||||
|
|
||||||
// Send notifications
|
// Send notifications ONLY when IP changed or failed
|
||||||
|
if notify {
|
||||||
let notifier_msg = Message::merge(messages);
|
let notifier_msg = Message::merge(messages);
|
||||||
notifier.send(¬ifier_msg).await;
|
notifier.send(¬ifier_msg).await;
|
||||||
|
}
|
||||||
|
|
||||||
all_ok
|
all_ok
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user