MTA-STS Policy management
This commit is contained in:
@@ -254,6 +254,17 @@ impl JMAP {
|
||||
};
|
||||
}
|
||||
}
|
||||
("mta-sts.txt", &Method::GET) => {
|
||||
if let Some(policy) = self.core.build_mta_sts_policy() {
|
||||
return Resource {
|
||||
content_type: "text/plain",
|
||||
contents: policy.to_string().into_bytes(),
|
||||
}
|
||||
.into_http_response();
|
||||
} else {
|
||||
return RequestError::not_found().into_http_response();
|
||||
}
|
||||
}
|
||||
(_, &Method::OPTIONS) => {
|
||||
return ().into_http_response();
|
||||
}
|
||||
|
||||
@@ -224,6 +224,72 @@ impl JMAP {
|
||||
content: "v=spf1 mx ra=postmaster -all".to_string(),
|
||||
});
|
||||
|
||||
records.push(DnsRecord {
|
||||
typ: "CNAME".to_string(),
|
||||
name: format!("autoconfig.{domain_name}."),
|
||||
content: format!("{server_name}."),
|
||||
});
|
||||
|
||||
let mut has_https = false;
|
||||
for (protocol, port, is_tls) in self
|
||||
.core
|
||||
.storage
|
||||
.config
|
||||
.get_services()
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
{
|
||||
match (protocol.as_str(), port) {
|
||||
("smtp", port @ 26..=u16::MAX) => {
|
||||
records.push(DnsRecord {
|
||||
typ: "SRV".to_string(),
|
||||
name: format!(
|
||||
"_submission{}._tcp.{domain_name}.",
|
||||
if is_tls { "s" } else { "" }
|
||||
),
|
||||
content: format!("0 1 {port} {server_name}."),
|
||||
});
|
||||
}
|
||||
("imap" | "pop3", port @ 1..=u16::MAX) => {
|
||||
records.push(DnsRecord {
|
||||
typ: "SRV".to_string(),
|
||||
name: format!(
|
||||
"_{protocol}{}._tcp.{domain_name}.",
|
||||
if is_tls { "s" } else { "" }
|
||||
),
|
||||
content: format!("0 1 {port} {server_name}."),
|
||||
});
|
||||
}
|
||||
("http", port @ 1..=u16::MAX) => {
|
||||
if is_tls {
|
||||
has_https = true;
|
||||
records.push(DnsRecord {
|
||||
typ: "SRV".to_string(),
|
||||
name: format!("_autodiscover._tcp.{domain_name}."),
|
||||
content: format!("0 1 {port} {server_name}."),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Add MTA-STS record
|
||||
if has_https {
|
||||
if let Some(policy) = self.core.build_mta_sts_policy() {
|
||||
records.push(DnsRecord {
|
||||
typ: "CNAME".to_string(),
|
||||
name: format!("mta-sts.{domain_name}."),
|
||||
content: format!("{server_name}."),
|
||||
});
|
||||
records.push(DnsRecord {
|
||||
typ: "TXT".to_string(),
|
||||
name: format!("_mta-sts.{domain_name}."),
|
||||
content: format!("v=STSv1; id={}", policy.id),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add DMARC records
|
||||
records.push(DnsRecord {
|
||||
typ: "TXT".to_string(),
|
||||
@@ -236,39 +302,37 @@ impl JMAP {
|
||||
if !name.ends_with(domain_name) {
|
||||
continue;
|
||||
}
|
||||
let cert = if let Some(cert) = key.cert.first().map(|cert| cert.as_ref()) {
|
||||
cert
|
||||
} else {
|
||||
tracing::debug!("No certificate found for domain: {}", domain_name);
|
||||
continue;
|
||||
};
|
||||
let parsed_cert = match parse_x509_certificate(cert) {
|
||||
Ok((_, parsed_cert)) => parsed_cert,
|
||||
Err(err) => {
|
||||
tracing::debug!("Failed to parse certificate: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let name = if !name.starts_with('.') {
|
||||
format!("_25._tcp.{name}.")
|
||||
} else {
|
||||
format!("_25._tcp.mail.{name}.")
|
||||
};
|
||||
for (cert_num, cert) in key.cert.iter().enumerate() {
|
||||
let parsed_cert = match parse_x509_certificate(cert) {
|
||||
Ok((_, parsed_cert)) => parsed_cert,
|
||||
Err(err) => {
|
||||
tracing::debug!("Failed to parse certificate: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for (s, cert) in [cert, parsed_cert.subject_pki.raw].into_iter().enumerate() {
|
||||
for (m, hash) in [
|
||||
format!("{:x}", sha2::Sha256::digest(cert)),
|
||||
format!("{:x}", sha2::Sha512::digest(cert)),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
records.push(DnsRecord {
|
||||
typ: "TLSA".to_string(),
|
||||
name: name.clone(),
|
||||
content: format!("3 {} {} {}", s, m + 1, hash),
|
||||
});
|
||||
let name = if !name.starts_with('.') {
|
||||
format!("_25._tcp.{name}.")
|
||||
} else {
|
||||
format!("_25._tcp.mail.{name}.")
|
||||
};
|
||||
let cu = if cert_num == 0 { 3 } else { 2 };
|
||||
|
||||
for (s, cert) in [cert, parsed_cert.subject_pki.raw].into_iter().enumerate() {
|
||||
for (m, hash) in [
|
||||
format!("{:x}", sha2::Sha256::digest(cert)),
|
||||
format!("{:x}", sha2::Sha512::digest(cert)),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
records.push(DnsRecord {
|
||||
typ: "TLSA".to_string(),
|
||||
name: name.clone(),
|
||||
content: format!("{} {} {} {}", cu, s, m + 1, hash),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user