From 8b906b777a13cd4e8c383bf24cf2b0319c726b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Christian=20Gr=C3=BCnhage?= Date: Sun, 15 Jan 2023 13:33:05 +0100 Subject: [PATCH] chore: replace homegrown public IP lookup with library --- Cargo.lock | 365 ++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 2 +- src/main.rs | 38 ++--- src/network.rs | 43 +----- 4 files changed, 378 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 243a902..45c3f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ dependencies = [ "cloudflare", "env_logger", "log", - "reqwest", + "public-ip", "serde", "serde_yaml", "tokio", @@ -200,14 +200,38 @@ dependencies = [ "syn", ] +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + [[package]] name = "darling" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.14.2", + "darling_macro 0.14.2", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn", ] [[package]] @@ -220,7 +244,18 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", "syn", ] @@ -230,11 +265,54 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ - "darling_core", + "darling_core 0.14.2", "quote", "syn", ] +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + +[[package]] +name = "derive_builder" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" +dependencies = [ + "darling 0.10.2", + "derive_builder_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" +dependencies = [ + "darling 0.10.2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dns-lookup" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53ecafc952c4528d9b51a458d1a8904b81783feff9fde08ab6ed2545ff396872" +dependencies = [ + "cfg-if", + "libc", + "socket2", + "winapi", +] + [[package]] name = "encoding_rs" version = "0.8.31" @@ -244,6 +322,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-as-inner" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -317,6 +413,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.25" @@ -324,6 +435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -332,12 +444,34 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.25" @@ -356,8 +490,11 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ + "futures-channel", "futures-core", "futures-io", + "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -401,6 +538,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -489,6 +632,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-system-resolver" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eea26c5d0b6ab9d72219f65000af310f042a740926f7b2fa3553e774036e2e7" +dependencies = [ + "derive_builder", + "dns-lookup", + "hyper", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -532,6 +689,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.3.0" @@ -641,6 +809,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "memchr" version = "2.5.0" @@ -683,6 +857,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -769,6 +952,26 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -787,6 +990,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.49" @@ -796,6 +1005,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "public-ip" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4c40db5262d93298c363a299f8bc1b3a956a78eecddba3bc0e58b76e2f419a" +dependencies = [ + "dns-lookup", + "futures-core", + "futures-util", + "http", + "hyper", + "hyper-system-resolver", + "pin-project-lite", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "trust-dns-client", + "trust-dns-proto", +] + [[package]] name = "quote" version = "1.0.23" @@ -805,6 +1035,46 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1012,7 +1282,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa" dependencies = [ - "darling", + "darling 0.14.2", "proc-macro2", "quote", "syn", @@ -1040,6 +1310,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.7" @@ -1050,6 +1326,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + [[package]] name = "strsim" version = "0.10.0" @@ -1230,9 +1512,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -1242,6 +1536,63 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "futures", + "futures-task", + "pin-project", + "tracing", +] + +[[package]] +name = "trust-dns-client" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b4ef9b9bde0559b78a4abb00339143750085f05e5a453efb7b8bef1061f09dc" +dependencies = [ + "cfg-if", + "data-encoding", + "futures-channel", + "futures-util", + "lazy_static", + "log", + "radix_trie", + "rand", + "thiserror", + "time 0.3.17", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "trust-dns-proto" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca94d4e9feb6a181c690c4040d7a24ef34018d8313ac5044a61d21222ae24e31" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -1288,7 +1639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna", + "idna 0.3.0", "percent-encoding", ] diff --git a/Cargo.toml b/Cargo.toml index 7d73d22..580308c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ documentation = "https://git.jcg.re/jcgruenhage/cloudflare-ddns-service" readme = "README.md" [dependencies] -reqwest= { version = "0.11.13", features = ["blocking", "json"] } serde = { version = "1.0.152", features = ["derive"] } anyhow = "1.0.68" env_logger = "0.10.0" @@ -22,3 +21,4 @@ tokio = { version = "1.24.1", features = ["time", "macros", "rt-multi-thread"] } serde_yaml = "0.9.16" #cloudflare = "0.10.1" cloudflare = { git = "https://github.com/jcgruenhage/cloudflare-rs.git", branch = "make-owner-fields-optional" } +public-ip = "0.2.2" diff --git a/src/main.rs b/src/main.rs index 3410709..80dac37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ mod network; use anyhow::{Context, Result}; -use network::{get_current_ipv4, get_current_ipv6, get_record, get_zone, update_record}; +use network::{get_record, get_zone, update_record}; use serde::{Deserialize, Serialize}; use serde_yaml::{from_str, to_writer}; use std::{ @@ -25,11 +25,8 @@ use tokio::time::interval; use cloudflare::{ endpoints::dns::DnsContent, - framework::{ - async_api::Client as CfClient, auth::Credentials, Environment, HttpApiClientConfig, - }, + framework::{async_api::Client, auth::Credentials, Environment, HttpApiClientConfig}, }; -use reqwest::Client as ReqwClient; #[derive(Serialize, Deserialize)] struct Config { @@ -68,8 +65,7 @@ async fn main() -> Result<()> { }; let mut interval = interval(Duration::new(config.interval, 0)); - let mut reqw_client = ReqwClient::new(); - let mut cf_client = CfClient::new( + let mut client = Client::new( Credentials::UserAuthToken { token: config.api_token.clone(), }, @@ -77,20 +73,11 @@ async fn main() -> Result<()> { Environment::Production, ) .context("Failed to initiate cloudflare API client")?; - let zone = get_zone(config.zone.clone(), &mut cf_client) + let zone = get_zone(config.zone.clone(), &mut client) .await .context("Failed to get zone")?; loop { - if let Err(error) = update( - &config, - &mut cache, - &cache_path, - &zone, - &mut reqw_client, - &mut cf_client, - ) - .await - { + if let Err(error) = update(&config, &mut cache, &cache_path, &zone, &mut client).await { log::error!("Failed to update record: {}", error); } interval.tick().await; @@ -102,11 +89,10 @@ async fn update( cache: &mut Cache, cache_path: &PathBuf, zone: &str, - reqw_client: &mut ReqwClient, - cf_client: &mut CfClient, + client: &mut Client, ) -> Result<()> { if config.ipv4 { - let current = get_current_ipv4(reqw_client) + let current = public_ip::addr_v4() .await .context("Failed to query current IPv4 address")?; log::debug!("fetched current IP: {}", current.to_string()); @@ -116,7 +102,7 @@ async fn update( } _ => { log::info!("ipv4 changed, setting record"); - let rid = get_record(zone, config.domain.clone(), network::A_RECORD, cf_client) + let rid = get_record(zone, config.domain.clone(), network::A_RECORD, client) .await .context("couldn't find record!")?; log::debug!("got record ID {}", rid); @@ -125,7 +111,7 @@ async fn update( &rid, &config.domain, DnsContent::A { content: current }, - cf_client, + client, ) .await .context("Failed to set DNS record")?; @@ -136,7 +122,7 @@ async fn update( } } if config.ipv6 { - let current = get_current_ipv6(reqw_client) + let current = public_ip::addr_v6() .await .context("Failed to query current IPv4 address")?; log::debug!("fetched current IP: {}", current.to_string()); @@ -146,7 +132,7 @@ async fn update( } _ => { log::info!("ipv6 changed, setting record"); - let rid = get_record(zone, config.domain.clone(), network::AAAA_RECORD, cf_client) + let rid = get_record(zone, config.domain.clone(), network::AAAA_RECORD, client) .await .context("couldn't find record!")?; log::debug!("got record ID {}", rid); @@ -155,7 +141,7 @@ async fn update( &rid, &config.domain, DnsContent::AAAA { content: current }, - cf_client, + client, ) .await .context("Failed to set DNS record")?; diff --git a/src/network.rs b/src/network.rs index 52b7fac..062f21f 100644 --- a/src/network.rs +++ b/src/network.rs @@ -20,9 +20,8 @@ use cloudflare::{ }, zone::{ListZones, ListZonesParams}, }, - framework::async_api::Client as CfClient, + framework::async_api::Client, }; -use reqwest::Client as ReqwClient; pub const A_RECORD: DnsContent = DnsContent::A { content: Ipv4Addr::UNSPECIFIED, @@ -31,36 +30,8 @@ pub const AAAA_RECORD: DnsContent = DnsContent::AAAA { content: Ipv6Addr::UNSPECIFIED, }; -pub async fn get_current_ipv4(client: &mut ReqwClient) -> Result { - client - .get("https://ipv4.icanhazip.com") - .send() - .await - .context("Failed to query current IPv4 from ipv4.icanhazip.com")? - .text() - .await - .context("Failed to read text body")? - .trim() - .parse() - .context("Failed to parse IPv4 address returned by ipv4.icanhazip.com") -} - -pub async fn get_current_ipv6(client: &mut ReqwClient) -> Result { - client - .get("https://ipv6.icanhazip.com") - .send() - .await - .context("Failed to query current IPv6 from ipv6.icanhazip.com")? - .text() - .await - .context("Failed to read text body")? - .trim() - .parse() - .context("Failed to parse IPv6 address returned by ipv6.icanhazip.com") -} - -pub async fn get_zone(domain: String, cf_client: &mut CfClient) -> Result { - Ok(cf_client +pub async fn get_zone(domain: String, client: &mut Client) -> Result { + Ok(client .request_handle(&ListZones { params: ListZonesParams { name: Some(domain), @@ -83,9 +54,9 @@ pub async fn get_record( zone_identifier: &str, domain: String, r#type: DnsContent, - cf_client: &mut CfClient, + client: &mut Client, ) -> Result { - Ok(cf_client + Ok(client .request_handle(&ListDnsRecords { zone_identifier, params: ListDnsRecordsParams { @@ -113,9 +84,9 @@ pub async fn update_record( identifier: &str, name: &str, content: DnsContent, - cf_client: &mut CfClient, + client: &mut Client, ) -> Result<()> { - cf_client + client .request_handle(&UpdateDnsRecord { zone_identifier, identifier,