bindy/bind9/records/
cname.rs1use super::super::types::RndcKeyData;
7use super::{build_authenticated_client, build_record_fqdn, should_update_record};
8use anyhow::Result;
9use hickory_net::client::ClientHandle;
10use hickory_proto::op::ResponseCode;
11use hickory_proto::rr::{rdata, DNSClass, Name, RData, Record, RecordType};
12use std::str::FromStr;
13use tracing::info;
14
15use crate::constants::DEFAULT_DNS_RECORD_TTL_SECS;
16
17#[allow(clippy::too_many_arguments)]
23pub async fn add_cname_record(
24 zone_name: &str,
25 name: &str,
26 target: &str,
27 ttl: Option<i32>,
28 server: &str,
29 key_data: &RndcKeyData,
30) -> Result<()> {
31 let target_for_comparison = target.to_string();
32 let should_update = should_update_record(
33 zone_name,
34 name,
35 RecordType::CNAME,
36 "CNAME",
37 server,
38 |existing_records| {
39 if existing_records.len() == 1 {
40 if let RData::CNAME(existing_cname) = &existing_records[0].data {
41 return existing_cname.0.to_string() == target_for_comparison;
42 }
43 }
44 false
45 },
46 )
47 .await?;
48
49 if !should_update {
50 return Ok(());
51 }
52
53 let ttl_value = u32::try_from(ttl.unwrap_or(DEFAULT_DNS_RECORD_TTL_SECS))
54 .unwrap_or(u32::try_from(DEFAULT_DNS_RECORD_TTL_SECS).unwrap_or(300));
55
56 let zone = Name::from_str(zone_name)?;
57 let fqdn = build_record_fqdn(zone_name, name)?;
58 let target_name = Name::from_str(target)?;
59
60 let mut record = Record::from_rdata(
61 fqdn.clone(),
62 ttl_value,
63 RData::CNAME(rdata::CNAME(target_name)),
64 );
65 record.dns_class = DNSClass::IN;
66
67 info!(
68 "Adding CNAME record: {} -> {} (TTL: {})",
69 record.name, target, ttl_value
70 );
71
72 let mut client = build_authenticated_client(server, key_data).await?;
73 let response = client.append(record, zone, false).await?;
74
75 match response.metadata.response_code {
76 ResponseCode::NoError => {
77 info!("Successfully added CNAME record: {} -> {}", name, target);
78 Ok(())
79 }
80 code => Err(anyhow::anyhow!(
81 "DNS update failed with response code: {code:?}"
82 )),
83 }
84}
85
86#[cfg(test)]
87#[path = "cname_tests.rs"]
88mod cname_tests;