checker-blacklist/README.md

4 KiB

checker-blacklist

happyDomain checker that flags whether a domain is currently listed on widely-used reputation systems.

Sources

Source Type API key needed Configurable
Spamhaus DBL DNS-based DBL no admin (default on)
SURBL multi DNS-based DBL no admin (default on)
URIBL multi DNS-based DBL no admin (default on)
Extra DNSBL zones DNS-based DBL no admin
Google Safe Browsing HTTPS lookup yes (admin) admin
OpenPhish public feed downloaded list no user (default on)
abuse.ch URLhaus HTTPS lookup optional Auth-Key (admin) user (default on)
VirusTotal v3 HTTPS lookup yes (admin) admin

DNS-based blocklists are queried in parallel. The OpenPhish feed is downloaded once per hour by the provider and cached in memory.

Common failure scenarios surfaced in the HTML report

The report opens with a diagnosis-first "Action required" section that lists the most common, high-impact problems with a one-shot remediation:

  1. Listed on Spamhaus DBL / SURBL / URIBL: direct lookup link and removal procedure URL per operator.
  2. Flagged by Google Safe Browsing: link to Google Search Console's security-issues review request.
  3. Listed in the OpenPhish feed: instructions to treat the host as compromised (audit recently-added files, rotate credentials), plus a link to OpenPhish feedback.
  4. Listed in URLhaus (active malware distribution): direct link to the abuse.ch reference page and per-URL takedown notification flow.
  5. VirusTotal multi-vendor flag: Critical when at least one vendor reports malicious, Warning when only suspicious. Lists the flagging engines and links to the VT GUI page for re-scan / vendor contact.
  6. DNSBL query refused / API quota exhausted: most public resolvers are blocked by DBL/URIBL operators; surfaced as a warning so it does not pollute the OK status.

A per-source detail table follows for full context (return codes, TXT records, threat types, sample phishing URLs).

Adding a new source

Every reputation backend implements the Source interface in its own file and registers itself from init(). Skeleton:

package checker

import (
    "context"
    sdk "git.happydns.org/checker-sdk-go/checker"
)

func init() { Register(&mySource{}) }

type mySource struct{}

func (*mySource) ID() string   { return "mybl" }
func (*mySource) Name() string { return "My Blocklist" }

func (*mySource) Options() SourceOptions {
    return SourceOptions{
        Admin: []sdk.CheckerOptionField{ /* … */ },
    }
}

func (*mySource) Query(ctx context.Context, domain, registered string, opts sdk.CheckerOptions) []SourceResult {
    res := SourceResult{SourceID: "mybl", SourceName: "My Blocklist", Enabled: true}
    // …populate Listed / Severity / Reasons / Evidence / Reference / Error
    return []SourceResult{res}
}

func (*mySource) Diagnose(res SourceResult) Diagnosis {
    return Diagnosis{Severity: SeverityCrit, Title: "Listed", Detail: "…"}
}

That's it: rules, the report, metrics, the standalone /check form and the definition pick the new source up automatically. Sources that need richer rendering (a per-vendor table, etc.) additionally implement RenderDetail(SourceResult) (template.HTML, error).

Build

make                # standalone binary (HTTP server + /check form)
make plugin         # checker-blacklist.so for happyDomain dynamic load
make docker         # container image

Running standalone

./checker-blacklist -listen :8080
# then GET /check, /definition, /health, …

The standalone binary embeds an interactive form on GET /check so a human can paste a domain and run the full pipeline without happyDomain.

License

MIT (checker code); Apache 2.0 SDK dependency.