feat: add dns.rs

This commit is contained in:
2022-02-05 15:38:13 +08:00
parent 5ebe0a2dae
commit 31e480a7b2
4 changed files with 99 additions and 23 deletions

View File

@@ -4,11 +4,10 @@ use std::collections::BTreeMap;
use acme_lib::{Directory, create_p256_key, create_p384_key, create_rsa_key};
use acme_lib::persist::FilePersist;
use rust_util::XResult;
use aliyun_openapi_core_rust_sdk::RPClient;
use crate::util::parse_dns_record;
use crate::network::{get_resolver, resolve_first_ipv4};
use crate::ali_dns::{add_txt_dns_record, build_dns_client, delete_dns_record, list_dns, simple_parse_aliyun_supplier};
use crate::config::{AcmeChallenge, AcmeMode};
use crate::dns::{DnsClient, DnsClientFactory, DnsRecord};
use crate::x509::{X509PublicKeyAlgo, X509EcPublicKeyAlgo};
@@ -64,9 +63,9 @@ pub fn request_acme_certificate(acme_request: AcmeRequest, dns_cleaned_domains:
let dir = opt_result!(Directory::from_url(persist, url), "Create directory from url failed: {}");
let acc = opt_result!(dir.account(acme_request.contract_email), "Directory set account failed: {}");
let mut ord_new = opt_result!( acc.new_order(acme_request.primary_name, acme_request.alt_names), "Create order failed: {}");
let ali_yun_client: Option<RPClient> = match acme_request.credential_supplier {
Some(credential_supplier) => Some(build_dns_client(
&opt_result!(simple_parse_aliyun_supplier(credential_supplier), "Parse credential supplier failed: {}"))),
let mut dns_client: Option<Box<dyn DnsClient>> = match acme_request.credential_supplier {
Some(credential_supplier) => Some(
opt_result!(DnsClientFactory::build(credential_supplier), "Build dns client failed: {}")),
None => None,
};
@@ -107,18 +106,16 @@ pub fn request_acme_certificate(acme_request: AcmeRequest, dns_cleaned_domains:
if !dns_cleaned_domains.contains(&rr_and_domain.1) {
information!("Clearing domain: {}", &rr_and_domain.1);
dns_cleaned_domains.push(rr_and_domain.1.clone());
ali_yun_client.as_ref().map(|client| {
match list_dns(client, &rr_and_domain.1) {
dns_client.as_mut().map(|client| {
match client.list_dns(&rr_and_domain.1) {
Err(e) => warning!("List dns for: {}, failed: {}", &rr_and_domain.1, e),
Ok(Err(e)) => warning!("List dns for: {}, failed: {:?}", &rr_and_domain.1, e),
Ok(Ok(s)) => {
for r in &s.domain_records.record {
Ok(records) => {
for r in &records {
let rr = &r.rr;
if rr == "_acme-challenge" || rr.starts_with("_acme-challenge.") {
match delete_dns_record(client, &r.record_id) {
Err(e) => warning!("Delete dns: {}.{}, failed: {}", r.rr, r.domain_name, e),
Ok(Err(e)) => warning!("Delete dns: {}.{}, failed: {:?}", r.rr, r.domain_name, e),
Ok(Ok(_)) => success!("Delete dns: {}.{}", r.rr, r.domain_name),
match client.delete_dns_record(&r.id) {
Err(e) => warning!("Delete dns: {}.{}, failed: {}", r.rr, r.domain, e),
Ok(_) => success!("Delete dns: {}.{}", r.rr, r.domain),
}
}
}
@@ -127,13 +124,18 @@ pub fn request_acme_certificate(acme_request: AcmeRequest, dns_cleaned_domains:
});
}
match &ali_yun_client {
match &mut dns_client {
Some(client) => {
let add_txt_dns_result = opt_result!(add_txt_dns_record(client, &rr_and_domain.1, &rr_and_domain.0, &proof), "Add DNS TXT record failed: {}");
match add_txt_dns_result {
Ok(s) => success!("Add dns txt record successes: {}", s.record_id),
Err(e) => return simple_error!("Add dns txt record failed: {:?}", e),
}
let dns_record = DnsRecord {
id: String::new(),
domain: rr_and_domain.1,
rr: rr_and_domain.0,
r#type: "TXT".into(),
ttl: -1,
value: proof,
};
let _ = opt_result!(client.add_dns_record(&dns_record), "Add DNS TXT record failed: {}");
success!("Add dns txt record successes: {}.{} -> {}", dns_record.rr, dns_record.domain, dns_record.value);
}
None => if acme_request.allow_interact {
let mut line = String::new();

View File

@@ -1,10 +1,53 @@
use rust_util::XResult;
use serde::{Deserialize, Serialize};
use aliyun_openapi_core_rust_sdk::RPClient;
use crate::dns::DnsClient;
static ALI_DNS_ENDPOINT: &str = "https://alidns.aliyuncs.com";
static ALI_DNS_API_VERSION: &str = "2015-01-09";
pub struct AlibabaCloudDnsClient {
client: RPClient,
}
impl AlibabaCloudDnsClient {
pub fn build(supplier: &str) -> XResult<AlibabaCloudDnsClient> {
let access_credential = simple_parse_aliyun_supplier(supplier)?;
Ok(AlibabaCloudDnsClient {
client: build_dns_client(&access_credential)
})
}
}
impl DnsClient for AlibabaCloudDnsClient {
fn list_dns(&mut self, domain: &str) -> XResult<Vec<crate::dns::DnsRecord>> {
let list_dns_response = opt_result!(list_dns(&self.client, domain)?, "List dns records failed: {:?}");
let mut dns_records = vec![];
list_dns_response.domain_records.record.into_iter().for_each(|record| {
dns_records.push(crate::dns::DnsRecord {
id: record.record_id,
domain: record.domain_name,
rr: record.rr,
r#type: record.r#type,
ttl: record.ttl,
value: record.value,
});
});
Ok(dns_records)
}
fn delete_dns_record(&mut self, record_id: &str) -> XResult<()> {
opt_result!(delete_dns_record(&self.client, record_id)?, "Delete dns record failed: {:?}");
Ok(())
}
fn add_dns_record(&mut self, dns_record: &crate::dns::DnsRecord) -> XResult<()> {
let _ = opt_result!(add_dns_record(&self.client, &dns_record.domain, &dns_record.rr, &dns_record.r#type, &dns_record.value),
"Add dns record failed: {}");
Ok(())
}
}
#[derive(Debug)]
pub struct AccessCredential {
access_key_id: String,
@@ -111,9 +154,9 @@ pub fn delete_dns_record(client: &RPClient, record_id: &str) -> XResult<Result<C
parse_result("DeleteDomainRecord", &delete_domain_record_response)
}
pub fn add_txt_dns_record(client: &RPClient, domain: &str, rr: &str, value: &str) -> XResult<Result<CommonSuccessResponse, CommonErrorResponse>> {
add_dns_record(client, domain, rr, "TXT", value)
}
// pub fn add_txt_dns_record(client: &RPClient, domain: &str, rr: &str, value: &str) -> XResult<Result<CommonSuccessResponse, CommonErrorResponse>> {
// add_dns_record(client, domain, rr, "TXT", value)
// }
// domain -> "example.com"
// rr -> "@", "_acme-challenge"

30
src/dns.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::{Deserialize, Serialize};
use rust_util::XResult;
use crate::ali_dns::AlibabaCloudDnsClient;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DnsRecord {
pub id: String,
pub domain: String,
pub rr: String,
pub r#type: String,
pub ttl: i32,
pub value: String,
}
pub trait DnsClient {
fn list_dns(&mut self, domain: &str) -> XResult<Vec<DnsRecord>>;
fn delete_dns_record(&mut self, record_id: &str) -> XResult<()>;
fn add_dns_record(&mut self, dns_record: &DnsRecord) -> XResult<()>;
}
pub struct DnsClientFactory {}
impl DnsClientFactory {
pub fn build(supplier: &str) -> XResult<Box<dyn DnsClient>> {
Ok(Box::new(AlibabaCloudDnsClient::build(supplier)?))
//simple_error!("Build dns client failed: {}", supplier)
}
}

View File

@@ -10,6 +10,7 @@ mod x509;
mod network;
mod statics;
mod dingtalk;
mod dns;
mod ali_dns;
// mod simple_thread_pool;