use crate::{DnsRecord, IntoFqdn, NamedDnsRecord};
pub struct BindSerializer;
impl BindSerializer {
pub fn serialize(records: &[NamedDnsRecord]) -> String {
let mut output = String::new();
for named in records {
let name = &named.name;
match &named.record {
DnsRecord::A(addr) => {
output.push_str(&format!("{name} IN A {addr}\n"));
}
DnsRecord::AAAA(addr) => {
output.push_str(&format!("{name} IN AAAA {addr}\n"));
}
DnsRecord::CNAME(cname) => {
output.push_str(&format!("{name} IN CNAME {}\n", cname.into_fqdn()));
}
DnsRecord::NS(ns) => {
output.push_str(&format!("{name} IN NS {}\n", ns.into_fqdn()));
}
DnsRecord::MX(mx) => {
output.push_str(&format!(
"{name} IN MX {} {}\n",
mx.priority,
(&mx.exchange).into_fqdn()
));
}
DnsRecord::TXT(text) => {
output.push_str(&format!("{name} IN TXT "));
if text.len() <= 255 {
output.push_str(&format!("\"{}\"\n", escape_txt(text)));
} else {
output.push_str("(\n");
for chunk in text.as_bytes().chunks(255) {
let chunk_str = String::from_utf8_lossy(chunk);
output.push_str(&format!(" \"{}\"\n", escape_txt(&chunk_str)));
}
output.push_str(")\n");
}
}
DnsRecord::SRV(srv) => {
output.push_str(&format!(
"{name} IN SRV {} {} {} {}\n",
srv.priority,
srv.weight,
srv.port,
(&srv.target).into_fqdn()
));
}
DnsRecord::TLSA(tlsa) => {
output.push_str(&format!("{name} IN TLSA {tlsa}\n"));
}
DnsRecord::CAA(caa) => {
output.push_str(&format!("{name} IN CAA {caa}\n"));
}
DnsRecord::HTTPS(https) => {
output.push_str(&format!("{name} IN HTTPS {https}\n"));
}
}
}
output
}
}
#[inline(always)]
fn escape_txt(s: &str) -> String {
s.replace('\\', "\\\\").replace('"', "\\\"")
}