bindy/bind9/records/
txt.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_txt_record(
24 zone_name: &str,
25 name: &str,
26 texts: &[String],
27 ttl: Option<i32>,
28 server: &str,
29 key_data: &RndcKeyData,
30) -> Result<()> {
31 let texts_for_comparison = texts.to_vec();
32 let should_update = should_update_record(
33 zone_name,
34 name,
35 RecordType::TXT,
36 "TXT",
37 server,
38 |existing_records| {
39 if existing_records.len() == 1 {
40 if let RData::TXT(existing_txt) = &existing_records[0].data {
41 let existing_texts: Vec<String> = existing_txt
42 .txt_data
43 .iter()
44 .map(|bytes| String::from_utf8_lossy(bytes).to_string())
45 .collect();
46 return existing_texts == texts_for_comparison;
47 }
48 }
49 false
50 },
51 )
52 .await?;
53
54 if !should_update {
55 return Ok(());
56 }
57
58 let ttl_value = u32::try_from(ttl.unwrap_or(DEFAULT_DNS_RECORD_TTL_SECS))
59 .unwrap_or(u32::try_from(DEFAULT_DNS_RECORD_TTL_SECS).unwrap_or(300));
60
61 let zone = Name::from_str(zone_name)?;
62 let fqdn = build_record_fqdn(zone_name, name)?;
63
64 let mut record = Record::from_rdata(
65 fqdn.clone(),
66 ttl_value,
67 RData::TXT(rdata::TXT::new(texts.to_vec())),
68 );
69 record.dns_class = DNSClass::IN;
70
71 info!(
72 "Adding TXT record: {} -> {:?} (TTL: {})",
73 record.name, texts, ttl_value
74 );
75
76 let mut client = build_authenticated_client(server, key_data).await?;
77 let response = client.append(record, zone, false).await?;
78
79 match response.metadata.response_code {
80 ResponseCode::NoError => {
81 info!("Successfully added TXT record: {}", name);
82 Ok(())
83 }
84 code => Err(anyhow::anyhow!(
85 "DNS update failed with response code: {code:?}"
86 )),
87 }
88}
89
90#[cfg(test)]
91#[path = "txt_tests.rs"]
92mod txt_tests;