summaryrefslogtreecommitdiff
path: root/DomainDig/EmailSecurityService.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-03 17:48:16 -0500
committerChristian Cleberg <[email protected]>2026-04-03 17:48:16 -0500
commit253e57bd3ba31ef533a904be84d43c8103ba81b4 (patch)
treefcb2cbc91443861f0a3906ed93cd137e6f4498eb /DomainDig/EmailSecurityService.swift
parent2c38b5edee339e5fe9060a835d9772a71606dc85 (diff)
downloaddomain-dig-253e57bd3ba31ef533a904be84d43c8103ba81b4.tar.gz
domain-dig-253e57bd3ba31ef533a904be84d43c8103ba81b4.tar.bz2
domain-dig-253e57bd3ba31ef533a904be84d43c8103ba81b4.zip
add custom port scans and improve DNS/email/security diagnosticsv1.7.0
Diffstat (limited to 'DomainDig/EmailSecurityService.swift')
-rw-r--r--DomainDig/EmailSecurityService.swift24
1 files changed, 20 insertions, 4 deletions
diff --git a/DomainDig/EmailSecurityService.swift b/DomainDig/EmailSecurityService.swift
index c6b05b0..50e5f73 100644
--- a/DomainDig/EmailSecurityService.swift
+++ b/DomainDig/EmailSecurityService.swift
@@ -9,9 +9,10 @@ struct EmailSecurityService {
/// Analyze email security records. SPF is parsed from existing TXT records;
/// DMARC and DKIM require additional DoH queries.
static func analyze(domain: String, txtRecords: [DNSRecord]) async -> EmailSecurityResult {
- // SPF: extract from existing TXT records
- let spfRecord = txtRecords.first(where: { $0.value.lowercased().hasPrefix("v=spf1") })
- let spf = EmailSecurityRecord(found: spfRecord != nil, value: spfRecord?.value)
+ // SPF: prefer the already-fetched apex TXT records, but fall back to a direct lookup
+ // in case the earlier DNS section missed or normalized the record differently.
+ let localSPFRecord = txtRecords.first(where: { isMatchingTXTRecord($0.value, prefix: "v=spf1") })?.value
+ async let remoteSPFRecord = queryMatchingTXT(subdomain: domain, prefix: "v=spf1")
// DMARC, DKIM, BIMI, and MTA-STS queries in parallel.
async let dmarcResult = queryTXT(subdomain: "_dmarc.\(domain)")
@@ -26,6 +27,13 @@ struct EmailSecurityService {
let dkimValue = await dkimResult
let bimiValue = await bimiResult
let mtaSts = await mtaStsResult
+ let fetchedSPFRecord = await remoteSPFRecord
+ let spfValue = localSPFRecord ?? fetchedSPFRecord
+
+ let spf = EmailSecurityRecord(
+ found: spfValue != nil,
+ value: spfValue
+ )
let dmarc = EmailSecurityRecord(
found: dmarcValue != nil,
@@ -63,7 +71,7 @@ struct EmailSecurityService {
private static func queryMatchingTXT(subdomain: String, prefix: String) async -> String? {
do {
let records = try await DNSLookupService.lookup(domain: subdomain, recordType: .TXT)
- return records.first(where: { $0.value.hasPrefix(prefix) })?.value
+ return records.first(where: { isMatchingTXTRecord($0.value, prefix: prefix) })?.value
} catch {
return nil
}
@@ -131,4 +139,12 @@ struct EmailSecurityService {
return nil
}
+
+ private static func isMatchingTXTRecord(_ value: String, prefix: String) -> Bool {
+ value
+ .trimmingCharacters(in: .whitespacesAndNewlines)
+ .trimmingCharacters(in: CharacterSet(charactersIn: "\""))
+ .lowercased()
+ .hasPrefix(prefix.lowercased())
+ }
}