Compare commits
4 commits
d715d3d408
...
9a7fefc16c
Author | SHA1 | Date | |
---|---|---|---|
9a7fefc16c | |||
96aa83dbfc | |||
8cd963ad59 | |||
3e1152edfe |
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -2,6 +2,18 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.5.2] - 2023-01-14
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Switch to cloudflare fork that actually parses API responses
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- Improve error handling
|
||||
- Fix clippy lints
|
||||
- Bump version and update changelog
|
||||
|
||||
## [0.5.1] - 2023-01-01
|
||||
|
||||
### Bug Fixes
|
||||
|
|
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -98,8 +98,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cloudflare"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0778f99ea7ad39b49b758eb418da7117b93232a5f6a09f9b79a094b77ac88cc2"
|
||||
source = "git+https://github.com/jcgruenhage/cloudflare-rs.git?branch=make-owner-fields-optional#02397fc4211886548a31a0731b240f2e17309de4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -119,7 +118,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cloudflare-ddns-service"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cloudflare",
|
||||
|
@ -1166,9 +1165,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.23.0"
|
||||
version = "1.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
|
||||
checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "cloudflare-ddns-service"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
authors = ["Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
|
||||
edition = "2018"
|
||||
description = "A daemon to use Cloudflare as a DDNS provider"
|
||||
|
@ -18,6 +18,7 @@ serde = { version = "1.0.152", features = ["derive"] }
|
|||
anyhow = "1.0.68"
|
||||
env_logger = "0.10.0"
|
||||
log = "0.4.17"
|
||||
tokio = { version = "1.23.0", features = ["time", "macros", "rt-multi-thread"] }
|
||||
tokio = { version = "1.24.1", features = ["time", "macros", "rt-multi-thread"] }
|
||||
serde_yaml = "0.9.16"
|
||||
cloudflare = "0.10.1"
|
||||
#cloudflare = "0.10.1"
|
||||
cloudflare = { git = "https://github.com/jcgruenhage/cloudflare-rs.git", branch = "make-owner-fields-optional" }
|
||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -56,12 +56,12 @@ async fn main() -> Result<()> {
|
|||
|
||||
let config_string = read_to_string("/etc/cloudflare-ddns-service/config.yaml")
|
||||
.context("couldn't read config file!")?;
|
||||
let config: Config = from_str(&config_string)?;
|
||||
let config: Config = from_str(&config_string).context("Failed to parse config file")?;
|
||||
let cache_dir = PathBuf::from("/var/cache/cloudflare-ddns-service");
|
||||
let cache_path = cache_dir.join("cache.yaml");
|
||||
let mut cache = match read_to_string(&cache_path) {
|
||||
Ok(cache) => from_str(&cache)?,
|
||||
Err(_) => {
|
||||
let mut cache = match read_to_string(&cache_path).map(|str| from_str(&str)) {
|
||||
Ok(Ok(cache)) => cache,
|
||||
_ => {
|
||||
create_dir_all(cache_dir)?;
|
||||
Cache::default()
|
||||
}
|
||||
|
@ -75,10 +75,13 @@ async fn main() -> Result<()> {
|
|||
},
|
||||
HttpApiClientConfig::default(),
|
||||
Environment::Production,
|
||||
)?;
|
||||
let zone = get_zone(config.zone.clone(), &mut cf_client).await?;
|
||||
)
|
||||
.context("Failed to initiate cloudflare API client")?;
|
||||
let zone = get_zone(config.zone.clone(), &mut cf_client)
|
||||
.await
|
||||
.context("Failed to get zone")?;
|
||||
loop {
|
||||
update(
|
||||
if let Err(error) = update(
|
||||
&config,
|
||||
&mut cache,
|
||||
&cache_path,
|
||||
|
@ -86,7 +89,10 @@ async fn main() -> Result<()> {
|
|||
&mut reqw_client,
|
||||
&mut cf_client,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
{
|
||||
log::error!("Failed to update record: {}", error);
|
||||
}
|
||||
interval.tick().await;
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +106,9 @@ async fn update(
|
|||
cf_client: &mut CfClient,
|
||||
) -> Result<()> {
|
||||
if config.ipv4 {
|
||||
let current = get_current_ipv4(reqw_client).await?;
|
||||
let current = get_current_ipv4(reqw_client)
|
||||
.await
|
||||
.context("Failed to query current IPv4 address")?;
|
||||
log::debug!("fetched current IP: {}", current.to_string());
|
||||
match cache.v4 {
|
||||
Some(old) if old == current => {
|
||||
|
@ -119,14 +127,18 @@ async fn update(
|
|||
DnsContent::A { content: current },
|
||||
cf_client,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.context("Failed to set DNS record")?;
|
||||
cache.v4 = Some(current);
|
||||
write_cache(cache, cache_path)?;
|
||||
write_cache(cache, cache_path)
|
||||
.context("Failed to write current IPv4 address to cache")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if config.ipv6 {
|
||||
let current = get_current_ipv6(reqw_client).await?;
|
||||
let current = get_current_ipv6(reqw_client)
|
||||
.await
|
||||
.context("Failed to query current IPv4 address")?;
|
||||
log::debug!("fetched current IP: {}", current.to_string());
|
||||
match cache.v6 {
|
||||
Some(old) if old == current => {
|
||||
|
@ -145,9 +157,11 @@ async fn update(
|
|||
DnsContent::AAAA { content: current },
|
||||
cf_client,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.context("Failed to set DNS record")?;
|
||||
cache.v6 = Some(current);
|
||||
write_cache(cache, cache_path)?;
|
||||
write_cache(cache, cache_path)
|
||||
.context("Failed to write current IPv4 address to cache")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +169,11 @@ async fn update(
|
|||
}
|
||||
|
||||
fn write_cache(cache: &mut Cache, cache_path: &PathBuf) -> Result<()> {
|
||||
to_writer(File::create(cache_path)?, cache)?;
|
||||
to_writer(
|
||||
File::create(cache_path).context("Failed to open cache file for writing")?,
|
||||
cache,
|
||||
)
|
||||
.context("Failed to serialize cache into file")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -32,25 +32,31 @@ pub const AAAA_RECORD: DnsContent = DnsContent::AAAA {
|
|||
};
|
||||
|
||||
pub async fn get_current_ipv4(client: &mut ReqwClient) -> Result<Ipv4Addr> {
|
||||
Ok(client
|
||||
client
|
||||
.get("https://ipv4.icanhazip.com")
|
||||
.send()
|
||||
.await?
|
||||
.await
|
||||
.context("Failed to query current IPv4 from ipv4.icanhazip.com")?
|
||||
.text()
|
||||
.await?
|
||||
.await
|
||||
.context("Failed to read text body")?
|
||||
.trim()
|
||||
.parse()?)
|
||||
.parse()
|
||||
.context("Failed to parse IPv4 address returned by ipv4.icanhazip.com")
|
||||
}
|
||||
|
||||
pub async fn get_current_ipv6(client: &mut ReqwClient) -> Result<Ipv6Addr> {
|
||||
Ok(client
|
||||
client
|
||||
.get("https://ipv6.icanhazip.com")
|
||||
.send()
|
||||
.await?
|
||||
.await
|
||||
.context("Failed to query current IPv6 from ipv6.icanhazip.com")?
|
||||
.text()
|
||||
.await?
|
||||
.await
|
||||
.context("Failed to read text body")?
|
||||
.trim()
|
||||
.parse()?)
|
||||
.parse()
|
||||
.context("Failed to parse IPv6 address returned by ipv6.icanhazip.com")
|
||||
}
|
||||
|
||||
pub async fn get_zone(domain: String, cf_client: &mut CfClient) -> Result<String> {
|
||||
|
@ -66,7 +72,8 @@ pub async fn get_zone(domain: String, cf_client: &mut CfClient) -> Result<String
|
|||
search_match: None,
|
||||
},
|
||||
})
|
||||
.await?
|
||||
.await
|
||||
.context("Failed to query zone from cf_client")?
|
||||
.result[0]
|
||||
.id
|
||||
.clone())
|
||||
|
@ -95,9 +102,7 @@ pub async fn get_record(
|
|||
.context("Couldn't fetch record")?
|
||||
.result
|
||||
.iter()
|
||||
.find(|record| {
|
||||
std::mem::discriminant(&record.content) == std::mem::discriminant(&r#type)
|
||||
})
|
||||
.find(|record| std::mem::discriminant(&record.content) == std::mem::discriminant(&r#type))
|
||||
.context("No matching record found")?
|
||||
.id
|
||||
.clone())
|
||||
|
|
Loading…
Reference in a new issue