Skip to content

Conversation

@thisisjaymehta
Copy link

Summary

This PR adds support for per-response-code scoring in DNSBL checks, allowing administrators to assign different scores and custom rejection messages based on specific DNSBL return codes. This enables efficient use of combined DNSBLs like Spamhaus ZEN with granular control.

Problem

Combined DNSBLs like Spamhaus ZEN (zen.spamhaus.org) return different response codes for different listing types:

Response Code List Severity
127.0.0.2, 127.0.0.3 SBL (known spam sources) High
127.0.0.4-127.0.0.7 XBL (exploited/compromised hosts) High
127.0.0.10, 127.0.0.11 PBL (dynamic IPs) Lower

Currently, Maddy:

  1. Counts any response within 127.0.0.1/24 as a single "hit"
  2. Applies the same score regardless of which specific code was returned
  3. Cannot provide response-code-specific rejection messages
  4. If multiple codes are returned, they all count as one hit with one score

Users who want different scores for different listing types must query separate lists (sbl.spamhaus.org, xbl.spamhaus.org, pbl.spamhaus.org), resulting in 3 DNS queries instead of 1.

Reference: https://docs.spamhaus.com/datasets/docs/source/40-real-world-usage/PublicMirrors/MTAs/020-Postfix. html

Solution

Add a new response configuration block that allows per-response-code scoring and custom messages:

check.dnsbl {
    reject_threshold 10
    quarantine_threshold 5

    zen.spamhaus.org {
        client_ipv4 yes
        client_ipv6 yes
        
        # SBL - Spamhaus Block List (known spam sources)
        response 127.0.0.2 127.0.0.3 {
            score 10
            message "Listed in Spamhaus SBL. See https://check.spamhaus.org/"
        }
        
        # XBL - Exploits Block List (compromised hosts)
        response 127.0.0.4 127.0.0.5 127.0.0.6 127.0.0.7 {
            score 10
            message "Listed in Spamhaus XBL. See https://check.spamhaus.org/"
        }
        
        # PBL - Policy Block List (dynamic IPs)
        response 127.0.0.10 127.0.0.11 {
            score 5
            message "Listed in Spamhaus PBL. See https://check.spamhaus.org/"
        }
    }
}

When multiple response codes are returned (e.g., 127.0.0.2 and 127.0.0.11), their scores are summed (10 + 5 = 15 in this example).

Changes

Data Structures

  • Added ResponseRule struct with Networks, Score, and Message fields
  • Extended List struct with ResponseRules []ResponseRule
  • Extended ListedErr with Score and Message fields

Core Logic

  • checkIP() now matches response codes against rules and sums scores
  • checkLists() uses ListedErr.Score when set, falls back to legacy ScoreAdj
  • ListedErr.Fields() uses custom message when available

Configuration

  • Added parseResponseRule() to parse new response blocks
  • Updated readListCfg() to handle response blocks via AllowUnknown()

Backwards Compatibility

  • Legacy responses + score configuration works unchanged
  • New behavior only activates when ResponseRules is configured

Benefits

Feature Before After
DNS queries for ZEN 1 (codes ignored) 1 (codes interpreted)
Per-code scoring
Custom rejection messages
Backwards compatible N/A

Testing

  • Added test cases for multiple return codes with different scores
  • Added test cases for low-severity vs high-severity responses
  • Verified legacy configuration behavior is preserved

Copilot AI and others added 2 commits January 10, 2026 12:48
Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
Copilot AI and others added 5 commits January 11, 2026 04:50
Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
…ove version annotation

Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
Co-authored-by: thisisjaymehta <31812582+thisisjaymehta@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants