Skip to main content

SRE Toolbox

DNS Blacklist Checker

Check whether an IP address or hostname is listed on DNS blacklists.

Each hostname is resolved to every IPv4 and IPv6 address. Each address is reversed and queried against the built-in DNSBL zones in parallel. A loopback answer is a listing, and the line includes the return code and TXT reason when the zone provides them. Spamhaus 127.255.255.0/24 answers and Abusix 127.0.0.11 / 127.0.0.12 are notes, not listings. A zone timeout is not a listing.

Install

Requires Python 3.13 or newer. dnspython is installed with the package.

pip install lupaxa-dns-blacklist-checker
dns-blacklist-checker --help

CLI

dns-blacklist-checker is the command. dnsbl is an alias for that same command: same flags, same output. python -m lupaxa.dns_blacklist_checker runs that same program. Examples use the full command name.

dns-blacklist-checker 192.0.2.1 example.com
dns-blacklist-checker 2001:db8::1
dns-blacklist-checker 203.0.113.9 --zone zen.spamhaus.org --timeout 2
dns-blacklist-checker example.com --mx
dns-blacklist-checker 203.0.113.9 --spamhaus-key "$SPAMHAUS_DQS_KEY"
Flag Default Description
TARGET required, repeatable IPv4 address, IPv6 address, or hostname
--timeout, -t 5 Per-zone DNS timeout in seconds
--zone, -z built-in zone list DNSBL zone; repeat to replace the built-in list
--mx off Check every address of each mail exchanger
--spamhaus-key SPAMHAUS_DQS_KEY Spamhaus Data Query Service key
--version — Print the package version and exit

--timeout must be greater than 0. It bounds each zone query, and hostname and MX lookups.

--zone replaces the built-in list. Repeat the flag for each zone. Whitespace and a trailing dot are ignored, and duplicate names are queried once.

--mx requires a domain. Exchangers are ordered by preference, and every address of each one is checked. An IP address with --mx is an error.

--spamhaus-key rewrites Spamhaus zones to <key>.<zone>.dq.spamhaus.net. The printed zone name stays the public name. When the flag is omitted, the command reads SPAMHAUS_DQS_KEY.

Exit Codes

Code When
0 Help, version, or every address resolved and none were listed
1 At least one address is listed, or library input was invalid
2 Usage failed, a target could not be resolved, or no zone applied

When one target is listed and another cannot be resolved, the command exits 1.

Output

Each address is one line.

192.0.2.1 (192.0.2.1) is not blacklisted.
203.0.113.9 (203.0.113.9) is blacklisted on: zen.spamhaus.org [127.0.0.2] SBL123
example.com (192.0.2.10) is not blacklisted.
example.com (2001:db8::10) is not blacklisted.
example.com mx=mail.example (192.0.2.10) is not blacklisted.
missing.example error: name resolution failed
203.0.113.9 (203.0.113.9) is not blacklisted. (zen.spamhaus.org: query via public resolver)
192.0.2.1 (192.0.2.1) is not blacklisted. (1 zone query failed)
2001:db8::1 (2001:db8::1) error: no zones support IPv6

IPv6 queries use nibble names. Built-in zones that publish IPv4 data only are skipped for IPv6. A zone passed with --zone is queried for both families. If none of the selected zones apply, that address is an error.

Zones

The built-in list starts with zen.spamhaus.org and combined.mail.abusix.zone. It does not include SORBS, the separate Spamhaus SBL, XBL, and PBL zones, CBL, or UCEPROTECT levels 2 and 3. b.barracudacentral.org answers after the querying address is registered with Barracuda.

Library

from lupaxa.dns_blacklist_checker import check

result = check("203.0.113.9", zones=("zen.spamhaus.org",), timeout=5.0)
if result.error:
    print(result.query, result.error)
else:
    for item in result.addresses:
        print(item.address, item.listed)
        for zone in item.zones:
            if zone.listed:
                print(zone.zone, zone.return_codes, zone.reason)

check returns a result when a name does not resolve. It raises ValueError for an empty target, a non-positive timeout, or a zone list that is empty after normalisation. listed is true when any address was listed. check_mail_exchangers checks each MX host. dnsbl_qname builds the reversed query name.

Development

make init
make python-install-dev
make python-check
The Lupaxa Project Footer

Metadata

Release files for lupaxa-dns-blacklist-checker 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lupaxa-dns-blacklist-checker 0.1.5
File Size Uploaded
lupaxa_dns_blacklist_checker-0.1.5.tar.gz 11.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lupaxa-dns-blacklist-checker 0.1.5
File Interpreter ABI Platform
lupaxa_dns_blacklist_checker-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 24.8 kB

Release files / lupaxa_dns_blacklist_checker-0.1.5.tar.gz

Download URL lupaxa_dns_blacklist_checker-0.1.5.tar.gz
Size 11.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a5c2e3cadf2e68fdb6b53df496778a15b6320f5b450b9327f1477c9fb2461d39
BLAKE2b-256 checksum
How to use checksums
d4a403a7102092485c925fabefd167327f308a0083d33fd767466a4cd29138f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / lupaxa_dns_blacklist_checker-0.1.5-py3-none-any.whl

Download URL lupaxa_dns_blacklist_checker-0.1.5-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
21572baef509402056ee203f5b7d98f21f09751e75bbe685dca0e5d2398d9f22
BLAKE2b-256 checksum
How to use checksums
75bf0b39419ef3b9c27c293452bfa8d24ad2ff08c4110f1f82b8a7568f7d6f64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.5 This release

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page