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