Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
be17cc5234 | |||
84db7292a6 | |||
2c1f19d647 | |||
8b906b777a |
|
@ -2,6 +2,14 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.5.3] - 2023-01-15
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- Replace homegrown public IP lookup with library
|
||||
- Update dependencies
|
||||
- Bump version and update changelog
|
||||
|
||||
## [0.5.2] - 2023-01-14
|
||||
|
||||
### Bug Fixes
|
||||
|
|
644
Cargo.lock
generated
644
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "cloudflare-ddns-service"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
authors = ["Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
|
||||
edition = "2018"
|
||||
description = "A daemon to use Cloudflare as a DDNS provider"
|
||||
|
@ -13,12 +13,15 @@ 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"
|
||||
log = "0.4.17"
|
||||
tokio = { version = "1.24.1", features = ["time", "macros", "rt-multi-thread"] }
|
||||
serde_yaml = "0.9.16"
|
||||
#cloudflare = "0.10.1"
|
||||
cloudflare = "0.10.1"
|
||||
public-ip = "0.2.2"
|
||||
|
||||
[patch.crates-io]
|
||||
cloudflare = { git = "https://github.com/jcgruenhage/cloudflare-rs.git", branch = "make-owner-fields-optional" }
|
||||
public-ip = { git = "https://github.com/jcgruenhage/rust-public-ip.git", branch = "cloudflare-provider" }
|
||||
|
|
38
src/main.rs
38
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")?;
|
||||
|
|
|
@ -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<Ipv4Addr> {
|
||||
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<Ipv6Addr> {
|
||||
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<String> {
|
||||
Ok(cf_client
|
||||
pub async fn get_zone(domain: String, client: &mut Client) -> Result<String> {
|
||||
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<String> {
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue