From ae9e7e43c2f205ea48f244aeff91008e378413be Mon Sep 17 00:00:00 2001 From: Michael Skrynski Date: Sun, 8 Jun 2025 12:30:44 +0200 Subject: [PATCH] using --ipv6 cli argument --- Cargo.lock | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- src/main.rs | 54 ++++++++++++++-------- 3 files changed, 164 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd74fe4..edddbd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,56 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.59.0", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -89,6 +139,52 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "clap" +version = "4.5.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "core-foundation" version = "0.9.4" @@ -291,10 +387,17 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hetzner_ddns" version = "0.1.0" dependencies = [ + "clap", "dotenv", "reqwest", "serde", @@ -553,6 +656,12 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.15" @@ -663,6 +772,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "openssl" version = "0.10.73" @@ -1104,6 +1219,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -1367,6 +1488,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 4ef95f1..13e227f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +clap = { version = "4.5", features = ["derive"] } +dotenv = "0.15" reqwest = { version = "0.12", features = ["json", "blocking", "rustls-tls"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -dotenv = "0.15" diff --git a/src/main.rs b/src/main.rs index c3da256..117a1b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::env; use reqwest::blocking::Client; use serde::{Deserialize, Serialize}; use dotenv::dotenv; +use clap::Parser; use dotenv::Error as DotenvError; #[derive(Deserialize)] @@ -31,7 +32,18 @@ struct RecordList { records: Vec, } +#[derive(Parser, Debug)] +#[command(name = "hetzner-ddns", version, about = "Dynamic DNS updater for Hetzner")] +struct Cli { + /// Update the AAAA (IPv6) record as well + #[arg(long)] + ipv6: bool, +} + fn main() -> Result<(), Box> { + let args = Cli::parse(); + let update_ipv6 = args.ipv6; + match dotenv() { Ok(_) => {} // .env loaded Err(DotenvError::Io(ref e)) if e.kind() == std::io::ErrorKind::NotFound => { @@ -100,31 +112,35 @@ fn main() -> Result<(), Box> { println!("âš ī¸ A record not found."); } - // --- IPv6 (AAAA) Record --- - if let Some(ip6) = ip6 { - if let Some(record6) = records.records.iter().find(|r| r.name == record_name && r.record_type == "AAAA") { - if record6.value != ip6 { - println!("🔄 Updating AAAA record from {} to {}", record6.value, ip6); - let updated6 = Record { - value: ip6.clone(), - ttl: Some(60), - ..record6.to_owned() - }; + // --- IPv6 (AAAA) Record --- + if update_ipv6 { + if let Some(ip6) = ip6 { + if let Some(record6) = records.records.iter().find(|r| r.name == record_name && r.record_type == "AAAA") { + if record6.value != ip6 { + println!("🔄 Updating AAAA record from {} to {}", record6.value, ip6); + let updated6 = Record { + value: ip6.clone(), + ttl: Some(60), + ..record6.to_owned() + }; - client.put(format!("https://dns.hetzner.com/api/v1/records/{}", record6.id)) - .header("Auth-API-Token", &api_token) - .header("Content-Type", "application/json") - .json(&updated6) - .send()?; - println!("✅ AAAA record updated."); + client.put(format!("https://dns.hetzner.com/api/v1/records/{}", record6.id)) + .header("Auth-API-Token", &api_token) + .header("Content-Type", "application/json") + .json(&updated6) + .send()?; + println!("✅ AAAA record updated."); + } else { + println!("✅ AAAA record already up to date: {}", ip6); + } } else { - println!("✅ AAAA record already up to date: {}", ip6); + println!("âš ī¸ AAAA record not found."); } } else { - println!("âš ī¸ AAAA record not found."); + println!("â„šī¸ No public IPv6 address found. Skipping AAAA update."); } } else { - println!("â„šī¸ No public IPv6 address found. Skipping AAAA update."); + println!("â„šī¸ Skipping AAAA update (use --ipv6 to enable)."); } Ok(())