2020-03-21 21:42:29 +00:00
|
|
|
use serde_derive::{Deserialize, Serialize};
|
2020-03-22 21:10:50 +00:00
|
|
|
use anyhow::{anyhow};
|
2019-09-17 15:33:35 +00:00
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
2019-09-17 19:42:56 +00:00
|
|
|
struct CloudflareListResponse {
|
2019-09-17 15:33:35 +00:00
|
|
|
success: bool,
|
|
|
|
errors: Vec<String>,
|
2020-03-22 22:30:10 +00:00
|
|
|
result: Option<Vec<ObjectWithId>>,
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2019-09-17 19:42:56 +00:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
struct CloudflareUpdateResponse {
|
|
|
|
success: bool,
|
|
|
|
errors: Vec<String>,
|
|
|
|
result: ObjectWithId,
|
|
|
|
}
|
|
|
|
|
2019-09-17 15:33:35 +00:00
|
|
|
#[derive(Deserialize, Debug, PartialEq)]
|
|
|
|
struct ObjectWithId {
|
|
|
|
id: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Debug)]
|
|
|
|
struct UpdateIpData {
|
2019-09-18 09:12:50 +00:00
|
|
|
id: String,
|
|
|
|
r#type: String,
|
|
|
|
name: String,
|
|
|
|
content: String,
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2020-04-20 21:04:31 +00:00
|
|
|
pub fn get_zone_identifier(zone: &str, api_token: &str) -> anyhow::Result<String> {
|
2020-03-21 21:42:29 +00:00
|
|
|
let client = reqwest::blocking::Client::new();
|
2019-09-17 15:33:35 +00:00
|
|
|
let url = format!("https://api.cloudflare.com/client/v4/zones?name={}", zone);
|
2020-03-22 22:30:42 +00:00
|
|
|
|
|
|
|
let response = client
|
2019-09-17 15:33:35 +00:00
|
|
|
.get(&url)
|
2020-04-20 21:04:31 +00:00
|
|
|
.header("Authorization", format!("Bearer {}", api_token))
|
2019-09-17 15:33:35 +00:00
|
|
|
.header("Content-Type", "application/json")
|
2020-03-22 22:30:42 +00:00
|
|
|
.send()?;
|
|
|
|
|
|
|
|
if response.status() != 200 {
|
|
|
|
return Err(anyhow!("API Error: HTTP {}", response.status()));
|
|
|
|
}
|
|
|
|
|
|
|
|
let body: CloudflareListResponse = response
|
2019-09-17 15:33:35 +00:00
|
|
|
.json()?;
|
2020-03-22 21:10:50 +00:00
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
if !body.success {
|
|
|
|
let err: String = body
|
2019-09-18 09:12:50 +00:00
|
|
|
.errors
|
|
|
|
.iter()
|
|
|
|
.map(|s| format!("{}\n", s.to_owned()))
|
|
|
|
.collect();
|
2020-03-22 21:10:50 +00:00
|
|
|
return Err(anyhow!("API Error: {}", err));
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
let zones = match body.result {
|
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
|
|
|
return Err(anyhow!("No zones returned"))
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(zones[0].id.clone())
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2019-09-18 09:12:50 +00:00
|
|
|
pub fn get_dns_record_id(
|
|
|
|
zone_id: &str,
|
|
|
|
domain: &str,
|
2020-04-20 21:04:31 +00:00
|
|
|
api_token: &str,
|
2020-03-22 21:10:50 +00:00
|
|
|
) -> anyhow::Result<String> {
|
2020-03-21 21:42:29 +00:00
|
|
|
let client = reqwest::blocking::Client::new();
|
2019-09-18 09:12:50 +00:00
|
|
|
let url = format!(
|
|
|
|
"https://api.cloudflare.com/client/v4/zones/{}/dns_records?name={}",
|
|
|
|
zone_id, domain
|
|
|
|
);
|
2020-03-22 22:30:42 +00:00
|
|
|
|
|
|
|
let response = client
|
2019-09-17 15:33:35 +00:00
|
|
|
.get(&url)
|
2020-04-20 21:04:31 +00:00
|
|
|
.header("Authorization", format!("Bearer {}", api_token))
|
2019-09-17 15:33:35 +00:00
|
|
|
.header("Content-Type", "application/json")
|
2020-03-22 22:30:42 +00:00
|
|
|
.send()?;
|
|
|
|
|
|
|
|
if response.status() != 200 {
|
|
|
|
return Err(anyhow!("API Error: HTTP {}", response.status()));
|
|
|
|
}
|
|
|
|
|
|
|
|
let body: CloudflareListResponse = response.json()?;
|
2020-03-22 21:10:50 +00:00
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
if !body.success {
|
|
|
|
let err: String = body
|
2019-09-18 09:12:50 +00:00
|
|
|
.errors
|
|
|
|
.iter()
|
|
|
|
.map(|s| format!("{}\n", s.to_owned()))
|
|
|
|
.collect();
|
2020-03-22 21:10:50 +00:00
|
|
|
return Err(anyhow!("API Error: {}", err));
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
let records = match body.result {
|
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
|
|
|
return Err(anyhow!("No DNS records returned"))
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
let id = match records.first() {
|
2019-09-23 08:58:04 +00:00
|
|
|
Some(v) => v.id.clone(),
|
|
|
|
None => {
|
2020-03-22 21:10:50 +00:00
|
|
|
return Err(anyhow!(
|
2019-09-23 08:58:04 +00:00
|
|
|
"Unexpected API result for DNS record. Check if you passed the right options."
|
|
|
|
))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(id)
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2020-03-22 21:10:50 +00:00
|
|
|
pub fn get_current_ip() -> anyhow::Result<String> {
|
2020-03-21 21:42:29 +00:00
|
|
|
Ok(reqwest::blocking::Client::new()
|
2019-09-17 15:33:35 +00:00
|
|
|
.get("http://ipv4.icanhazip.com")
|
|
|
|
.send()?
|
2019-09-17 16:28:26 +00:00
|
|
|
.text()?
|
|
|
|
.trim()
|
|
|
|
.into())
|
2019-09-17 15:33:35 +00:00
|
|
|
}
|
|
|
|
|
2019-09-18 09:12:50 +00:00
|
|
|
pub fn update_ddns(
|
|
|
|
ip: &str,
|
|
|
|
domain: &str,
|
|
|
|
zone_id: &str,
|
|
|
|
record_id: &str,
|
2020-04-20 21:04:31 +00:00
|
|
|
api_token: &str,
|
2020-03-22 21:10:50 +00:00
|
|
|
) -> anyhow::Result<()> {
|
2020-03-21 21:42:29 +00:00
|
|
|
let client = reqwest::blocking::Client::new();
|
2019-09-18 09:12:50 +00:00
|
|
|
let url = format!(
|
|
|
|
"https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}",
|
|
|
|
zone_id, record_id
|
|
|
|
);
|
2019-09-17 15:33:35 +00:00
|
|
|
|
|
|
|
let update_data = UpdateIpData {
|
|
|
|
id: zone_id.to_owned(),
|
|
|
|
r#type: "A".to_owned(),
|
|
|
|
name: domain.to_owned(),
|
|
|
|
content: ip.to_owned(),
|
|
|
|
};
|
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
let response = client
|
2019-09-17 15:33:35 +00:00
|
|
|
.put(&url)
|
2020-04-20 21:04:31 +00:00
|
|
|
.header("Authorization", format!("Bearer {}", api_token))
|
2019-09-17 15:33:35 +00:00
|
|
|
.header("Content-Type", "application/json")
|
|
|
|
.json(&update_data)
|
2020-03-22 22:30:42 +00:00
|
|
|
.send()?;
|
|
|
|
|
|
|
|
if response.status() != 200 {
|
|
|
|
return Err(anyhow!("API Error: HTTP {}", response.status()));
|
|
|
|
}
|
|
|
|
|
|
|
|
let body: CloudflareUpdateResponse = response
|
2019-09-17 15:52:13 +00:00
|
|
|
.json()?;
|
|
|
|
|
2020-03-22 22:30:42 +00:00
|
|
|
if !body.success {
|
|
|
|
let err: String = body
|
2019-09-18 09:12:50 +00:00
|
|
|
.errors
|
|
|
|
.iter()
|
|
|
|
.map(|s| format!("{}\n", s.to_owned()))
|
|
|
|
.collect();
|
2020-03-22 21:10:50 +00:00
|
|
|
return Err(anyhow!("Unsuccessful update of DNS record: {}", err));
|
2019-09-17 15:52:13 +00:00
|
|
|
}
|
2019-09-17 15:33:35 +00:00
|
|
|
|
|
|
|
Ok(())
|
2019-09-18 09:12:50 +00:00
|
|
|
}
|