Detect SPF all mechanism

This commit is contained in:
nemunaire 2025-10-23 13:27:29 +07:00
commit 326abc0744
3 changed files with 65 additions and 27 deletions

View file

@ -867,6 +867,11 @@ components:
type: boolean
description: Whether the SPF record is valid
example: true
all_qualifier:
type: string
enum: ["+", "-", "~", "?"]
description: "Qualifier for the 'all' mechanism: + (pass), - (fail), ~ (softfail), ? (neutral)"
example: "~"
error:
type: string
description: Error message if validation failed

View file

@ -245,28 +245,34 @@ func (d *DNSAnalyzer) resolveSPFRecords(domain string, visited map[string]bool,
// Basic validation
valid := d.validateSPF(spfRecord)
// Check for strict -all mechanism
// Extract the "all" mechanism qualifier
var allQualifier *api.SPFRecordAllQualifier
var errMsg *string
if !valid {
errMsg = api.PtrTo("SPF record appears malformed")
} else if !d.hasSPFStrictFail(spfRecord) {
// Check what mechanism is used
if strings.HasSuffix(spfRecord, " ~all") {
errMsg = api.PtrTo("SPF uses ~all (softfail) instead of -all (hardfail). This weakens email authentication and may reduce deliverability.")
} else if strings.HasSuffix(spfRecord, " +all") || strings.HasSuffix(spfRecord, " ?all") {
errMsg = api.PtrTo("SPF uses permissive 'all' mechanism. This severely weakens email authentication. Use -all for strict policy.")
} else {
// Extract qualifier from the "all" mechanism
if strings.HasSuffix(spfRecord, " -all") {
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("-"))
} else if strings.HasSuffix(spfRecord, " ~all") {
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("~"))
} else if strings.HasSuffix(spfRecord, " +all") {
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("+"))
} else if strings.HasSuffix(spfRecord, " ?all") {
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("?"))
} else if strings.HasSuffix(spfRecord, " all") {
errMsg = api.PtrTo("SPF uses neutral 'all' mechanism. Use -all for strict policy to improve deliverability.")
} else {
errMsg = api.PtrTo("SPF record should end with -all for strict policy to improve deliverability and prevent spoofing.")
// Implicit + qualifier (default)
allQualifier = api.PtrTo(api.SPFRecordAllQualifier("+"))
}
}
results = append(results, api.SPFRecord{
Domain: &domain,
Record: &spfRecord,
Valid: valid,
Error: errMsg,
Domain: &domain,
Record: &spfRecord,
Valid: valid,
AllQualifier: allQualifier,
Error: errMsg,
})
// Extract and resolve include: directives
@ -694,23 +700,23 @@ func (d *DNSAnalyzer) CalculateDNSScore(results *api.DNSResults) (int, string) {
mainSPF := (*results.SpfRecords)[0]
if mainSPF.Valid {
// Full points for valid SPF
score += 20
score += 15
// Check for strict -all mechanism
if mainSPF.Record != nil && !d.hasSPFStrictFail(*mainSPF.Record) {
// Deduct points for weak SPF policy
if strings.HasSuffix(*mainSPF.Record, " ~all") {
// Deduct points based on the all mechanism qualifier
if mainSPF.AllQualifier != nil {
switch *mainSPF.AllQualifier {
case "-":
// Strict fail - no deduction, this is the recommended policy
score += 5
case "~":
// Softfail - moderate penalty
score -= 5
} else if strings.HasSuffix(*mainSPF.Record, " +all") ||
strings.HasSuffix(*mainSPF.Record, " ?all") ||
strings.HasSuffix(*mainSPF.Record, " all") {
case "+", "?":
// Pass/neutral - severe penalty
score -= 10
} else {
// No 'all' mechanism at all - severe penalty
score -= 10
score -= 5
}
} else {
// No 'all' mechanism qualifier extracted - severe penalty
score -= 5
}
} else if mainSPF.Record != nil {
// Partial credit if SPF record exists but has issues

View file

@ -50,6 +50,33 @@
<span class="badge bg-danger">Invalid</span>
{/if}
</div>
{#if spf.all_qualifier}
<div class="mb-2">
<strong>All Mechanism Policy:</strong>
{#if spf.all_qualifier === '-'}
<span class="badge bg-success">Strict (-all)</span>
{:else if spf.all_qualifier === '~'}
<span class="badge bg-warning">Softfail (~all)</span>
{:else if spf.all_qualifier === '+'}
<span class="badge bg-danger">Pass (+all)</span>
{:else if spf.all_qualifier === '?'}
<span class="badge bg-warning">Neutral (?all)</span>
{/if}
{#if index === 0}
<div class="alert small mt-2" class:alert-warning={spf.all_qualifier !== '-'} class:alert-success={spf.all_qualifier === '-'}>
{#if spf.all_qualifier === '-'}
All unauthorized servers will be rejected. This is the recommended strict policy.
{:else if spf.all_qualifier === '~'}
Unauthorized servers will softfail. Consider using <code>-all</code> for stricter policy, though this rarely affects legitimate email deliverability.
{:else if spf.all_qualifier === '+'}
All servers are allowed to send email. This severely weakens email authentication. Use <code>-all</code> for strict policy.
{:else if spf.all_qualifier === '?'}
No statement about unauthorized servers. Use <code>-all</code> for strict policy to prevent spoofing.
{/if}
</div>
{/if}
</div>
{/if}
{#if spf.record}
<div class="mb-2">
<strong>Record:</strong><br>