diff --git a/Cargo.lock b/Cargo.lock index 6baa792..c8aba53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,13 +211,14 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dreamhost-ddns" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "clap", "dotenvy", "env_logger", "log", + "rand", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index ea8a2dd..05edfb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dreamhost-ddns" -version = "0.1.1" +version = "0.2.0" edition = "2021" [dependencies] @@ -14,6 +14,7 @@ dotenvy = "0.15" log = "0.4" env_logger = "0.11" trust-dns-resolver = "0.23" +rand = "0.8" [profile.release] lto = true diff --git a/binaries/linux-aarch64/dreamhost-ddns b/binaries/linux-aarch64/dreamhost-ddns index 6c715b0..0692496 100644 Binary files a/binaries/linux-aarch64/dreamhost-ddns and b/binaries/linux-aarch64/dreamhost-ddns differ diff --git a/binaries/linux-rpi-armv7/dreamhost-ddns b/binaries/linux-rpi-armv7/dreamhost-ddns index 44c3db7..4aef866 100644 Binary files a/binaries/linux-rpi-armv7/dreamhost-ddns and b/binaries/linux-rpi-armv7/dreamhost-ddns differ diff --git a/binaries/linux-x86_64/dreamhost-ddns b/binaries/linux-x86_64/dreamhost-ddns index 7cabe19..4fe125b 100644 Binary files a/binaries/linux-x86_64/dreamhost-ddns and b/binaries/linux-x86_64/dreamhost-ddns differ diff --git a/binaries/windows/dreamhost-ddns.exe b/binaries/windows/dreamhost-ddns.exe index 2eb6690..167c1df 100644 Binary files a/binaries/windows/dreamhost-ddns.exe and b/binaries/windows/dreamhost-ddns.exe differ diff --git a/src/main.rs b/src/main.rs index 8744cce..59b0e4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use serde::Deserialize; use std::net::IpAddr; use std::sync::mpsc; use std::thread; +use rand::seq::SliceRandom; #[derive(Parser)] #[command( @@ -26,9 +27,6 @@ struct Args { #[arg(long)] record: Option, - #[arg(long, default_value_t = 300)] - interval: u64, - #[arg(long)] dry_run: bool, } @@ -95,6 +93,7 @@ impl DreamhostClient { } fn update_dns(&self, record: &str, old_ip: &str, new_ip: &str) -> Result<()> { + info!("Adding new DNS record {} -> {}", record, new_ip); self.call(&[ @@ -104,6 +103,9 @@ impl DreamhostClient { ("value", new_ip), ])?; + info!("Waiting briefly for DNS propagation..."); + std::thread::sleep(std::time::Duration::from_secs(3)); + info!("Removing old DNS record {} -> {}", record, old_ip); self.call(&[ @@ -135,11 +137,10 @@ fn main() -> Result<()> { let record = args.record.unwrap_or(config.dns_record); info!("Record: {}", record); - info!("Check interval: {} seconds", args.interval); let client = Client::builder() .timeout(std::time::Duration::from_secs(5)) - .user_agent("dreamhost-ddns/1.0") + .user_agent(format!("dreamhost-ddns/{}", env!("CARGO_PKG_VERSION"))) .build()?; let dh = DreamhostClient { @@ -168,7 +169,7 @@ fn main() -> Result<()> { } else { info!("Updating DNS..."); dh.update_dns(&record, &dns_ip, &wan_ip.to_string())?; - info!("DNS updated successfully"); + info!("DNS updated successfully to {}", wan_ip); } @@ -231,28 +232,43 @@ fn load_config(path: &str) -> Result { } fn get_wan_ip(client: &Client) -> Result { - let services = [ + let mut services = vec![ "https://icanhazip.com", "https://api.ipify.org", "https://ifconfig.me/ip", "https://checkip.amazonaws.com", ]; + services.shuffle(&mut rand::thread_rng()); + let (tx, rx) = mpsc::channel(); + let cancel = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); for url in services { let tx = tx.clone(); let client = client.clone(); + let cancel = cancel.clone(); let url = url.to_string(); thread::spawn(move || { - let result = client.get(&url).send() + + if cancel.load(std::sync::atomic::Ordering::Relaxed) { + return; + } + + let result = client + .get(&url) + .send() .and_then(|r| r.text()) .ok() .and_then(|text| text.trim().parse::().ok()); if let Some(ip) = result { - let _ = tx.send((url, ip)); + + if !cancel.swap(true, std::sync::atomic::Ordering::Relaxed) { + let _ = tx.send((url, ip)); + } + } }); } @@ -261,7 +277,7 @@ fn get_wan_ip(client: &Client) -> Result { match rx.recv() { Ok((url, ip)) => { - info!("WAN IP detected via {}: {}", url, ip); + info!("WAN IP detected via {}", url); Ok(ip) } Err(_) => Err(anyhow!("All WAN IP detection services failed")),