Version 2.9.0 | Philippe TEMESI | https://www.tems.be
-
Introduction
-
Quick Start
-
DNSBL Query Tool (dnsbl-query)
-
DNSBL Server (dnsbl-server)
- Configuration File (INI Format)
- Command-Line Options
- Zone Configuration
-
Source Types
-
DNS Record Support
-
Access Control
-
Logging
-
Auto-Reload
-
Real-Time DNSBL Forwarding
-
Test Queries
-
Examples
The DNSBL Server is a complete toolkit for running DNS-based Blocklists (DNSBL). It provides:
- DNSBL Server (dnsbl-server): A full-featured DNS server that responds to blocklist queries
- DNSBL Query Tool (dnsbl-query): A client tool to test if an IP address is listed
Key features:
- Multi-zone support (run multiple DNSBL domains on a single server)
- HTTP/HTTPS and local file blocklist sources
- Real-time DNSBL forwarding with recursive NS discovery
- NS, SOA, MX, and TXT record support for your DNSBL domains
- Rate limiting and IP-based access control
- Query logging and DBL saving
- Auto-reload of blocklists
dnsbl-server -D dnsbl.example.com -r 127.0.0.2 -s 192.168.1.100 -f /path/to/blocklist.txt
dnsbl-query -d dnsbl.example.com 192.168.1.100
dnsbl-server --config /etc/dnsbl/server.ini
The query tool checks whether an IP address is listed in a DNSBL.
dnsbl-query [OPTIONS] -d DOMAIN IP_ADDRESS
-d, --domain DOMAIN DNSBL domain to query (e.g., dnsbl.tems.be) -s, --server SERVER DNS server to use (default: 127.0.0.1:53) -t, --timeout SECONDS DNS query timeout (default: 5 seconds) -v, --verbose Enable verbose output -q, --quiet Quiet mode - output only the result -h, --help Show help information
Normal mode (default):
- ✅ IP x.x.x.x is CLEAN - IP not listed
- ✅ IP x.x.x.x is BLOCKED - IP is listed, with response IP and reason
Quiet mode (-q):
- CLEAN - IP not listed
- BLOCKED:x.x.x.x - IP is blocked (x.x.x.x is the response IP)
- ERROR:message - An error occurred
# Query using system DNS
dnsbl-query -d dnsbl.tems.be 192.168.1.100
# Query using Google DNS
dnsbl-query -d dnsbl.tems.be -s 8.8.8.8 192.168.1.100
# Query with custom port and verbose output
dnsbl-query -d dnsbl.tems.be -s 127.0.0.1:5453 -v 192.168.1.100
# Quiet mode for scripting
dnsbl-query -d dnsbl.tems.be -q 192.168.1.100
When verbose mode is enabled, the tool interprets common DNSBL response codes:
127.0.0.2 General spam source 127.0.0.3 High confidence spam 127.0.0.4 Open proxy 127.0.0.5 Open relay 127.0.0.6 Hacked/Compromised 127.0.0.7 Dynamic IP 127.0.0.8 Dialup IP 127.0.0.9 Blacklisted
The server listens for DNS queries and responds based on configured blocklists.
The server can be configured in two ways:
- Configuration file (INI format) - Recommended for complex setups
- Command-line arguments - Simple setups or legacy compatibility
The configuration file uses INI format with a [global] section and one or more [domain "..."] sections.
[global]
interface = 0.0.0.0:53
max-requests = 60
no-request-limit = 192.168.1.0/24,10.0.0.5
no-request-limit-file = /etc/dnsbl/exempt.txt
deny-file = /etc/dnsbl/deny.txt
stats-interval = 60
query-log = /var/log/dnsbl/queries.log
dbl-save = /var/lib/dnsbl/blocked_ips.txt
reload = 30
daemon = true
verbose = false
log = /var/log/dnsbl/server.log
interface Network interface to bind (IP:port) max-requests Max requests per minute per IP (0 = unlimited) no-request-limit Comma-separated IPs/CIDRs exempt from rate limiting no-request-limit-file File with exempt IPs/CIDRs (one per line) deny-file File with IPs/CIDRs denied access (one per line) stats-interval Interval for rate limiting stats logging (seconds) query-log File path for DNS query logs dbl-save File path to save IPs found in remote DNSBLs reload Auto-reload interval (minutes, 0 = disabled) daemon Run as daemon (true/false) verbose Enable verbose logging (true/false) log Server log file path
Each zone is defined with [domain "your.domain.com"]:
[domain "dnsbl.example.com"]
response = 127.0.0.2
self = 192.168.1.100
txt = "Spam source - see https://example.com/remove\"
mx = mail.example.com,10
source = /var/lib/dnsbl/blocklist.txt
source = https://example.com/blocklist.txt
source = dnsbl://other-dnsbl.example.com
source-file = /etc/dnsbl/sources.txt
response IP address returned for blocked queries self IP address returned for queries to the domain itself txt TXT record (supports @, @dotted, @replaced placeholders) mx MX record (format: server,priority) source Blocklist source (file, http://, https://, or dnsbl://domain) source-file File containing one source per line
When not using a config file, command-line options are available:
-i, --interface INTERFACE Listening interface (default: 0.0.0.0:53) -v, --verbose Enable verbose mode -d, --daemon Run as daemon --no-daemon Do not run as daemon (override config) -l, --log LOG_FILE Server log file -R, --reload MINUTES Auto-reload interval (minutes) --config FILE Use configuration file
--max-requests COUNT Max requests per minute per IP --no-request-limit IP,RANGE,... IPs/CIDRs exempt from rate limiting --no-request-limit-file FILE File with exempt IPs/CIDRs --deny-file FILE File with denied IPs/CIDRs --stats-interval SECONDS Stats logging interval
--query-log FILE Log DNS queries to file --dbl-save FILE Save blocked IPs to file
-D, --domain DOMAIN DNSBL domain name -r, --response IP Response IP for blocked queries -s, --self-ip IP IP for self-domain queries -f, --file SOURCE Blocklist source (file/URL/dnsbl://) -F, --file-list FILE File containing sources --txt TEXT TXT record for the domain --mx SERVER,PRIORITY MX record for the domain
Note: When using multiple zones with command-line options, the number of -D, -r, and -s options must match. Sources are distributed evenly across zones.
The server supports three types of blocklist sources:
source = /path/to/blocklist.txt
File format: one IP address or CIDR range per line. Lines starting with # are ignored.
Example blocklist file:
# My blocklist
192.168.1.100
10.0.0.0/24
203.0.113.50
source = https://example.com/blocklist.txt
The server downloads the file from the URL. The same format as local files is expected.
source = dnsbl://other-dnsbl.example.com
The server forwards queries to another DNSBL in real-time. The queried IP is checked against the remote DNSBL before returning a result.
The server provides full DNS record support for your DNSBL domains.
- Queries for x.x.x.x.zone.domain: Returns response IP if the IP is blocked
- Queries for zone.domain: Returns self IP
Returns NS records for the domain, pointing to the self IP address.
Returns Start of Authority record for the domain.
Returns configured MX record for the domain.
Returns TXT information. Supports IP substitution placeholders:
@ or @dotted Dotted IP format: 192.168.1.100 @reversed Reversed IP format: 100.1.168.192
Example TXT with substitution:
txt = "IP @ is listed in our blocklist. See https://example.com/remove?ip=@dotted\"
For an IP 192.168.1.100, this becomes:
"IP 192.168.1.100 is listed in our blocklist. See https://example.com/remove?ip=192.168.1.100\"
The server implements three layers of access control:
IPs or CIDR ranges in the deny list are completely blocked from querying the server. No response is sent.
deny-file = /etc/dnsbl/deny.txt
IPs or CIDR ranges in the exempt list bypass rate limiting.
no-request-limit = 192.168.1.0/24,10.0.0.5
no-request-limit-file = /etc/dnsbl/exempt.txt
Limits the number of queries per minute from a single IP address.
max-requests = 60
When the limit is exceeded, the server returns a REFUSED response for the duration of the current minute.
- Deny list - If matched, query is rejected immediately
- Exempt list - If matched, rate limiting is bypassed
- Rate limit check - Applied only if not exempt
Logs server events including startup, errors, and reload operations.
dnsbl-server --log /var/log/dnsbl/server.log --verbose
Logs all DNS queries received by the server.
dnsbl-server --query-log /var/log/dnsbl/queries.log
Query log format:
[2026-01-15 10:30:45] 192.168.1.100 dnsbl.example.com A NXDOMAIN
[2026-01-15 10:30:46] 10.0.0.50 dnsbl.example.com A A_RESPONSE 127.0.0.2 [source:local]
[2026-01-15 10:30:47] 192.168.1.101 dnsbl.example.com TXT TXT_RESPONSE "IP 192.168.1.100 is blocked"
Fields:
- Timestamp
- Client IP address
- Query domain
- Query type (A, TXT, NS, MX, etc.)
- Status/Response (NXDOMAIN, A_RESPONSE IP, TXT_RESPONSE, etc.)
- Source (local, test, dnsbl:domain, ACTION:EXEMPT, etc.)
Saves IP addresses that were found to be blocked by remote DNSBL forwarders.
dnsbl-server --dbl-save /var/lib/dnsbl/blocked_ips.txt
Each blocked IP appears on a separate line, deduplicated automatically.
The server can automatically reload blocklists at regular intervals.
dnsbl-server -R 30 ... # Reload every 30 minutes
During reload:
- The server re-downloads HTTP/HTTPS sources
- Re-reads local file sources
- Updates the in-memory blocklist without restarting
- Existing queries continue to be served using the old data until reload completes
Note: DNSBL forwarder sources are not reloaded via this mechanism as they operate in real-time.
When using dnsbl:// sources, the server performs real-time DNSBL forwarding:
-
A query for x.x.x.x.your-zone.com is received
-
The server extracts the IP address from the query
-
For each DNSBL forwarder source (dnsbl://other-dnsbl.com):
- The server queries x.x.x.x.other-dnsbl.com (note: IP octets are reversed for DNSBL format)
- If the remote DNSBL returns an A record, the IP is considered blocked
- Results are cached for 5 minutes to reduce network traffic
The server automatically discovers NS servers for remote DNSBL domains:
- Performs recursive NS record lookup
- Resolves NS names to IP addresses
- Caches NS servers for 1 hour
- Uses round-robin selection among discovered servers
If NS discovery fails, fallback DNS servers (8.8.8.8, 1.1.1.1, 9.9.9.9) are used.
[domain "my-dnsbl.com"]
response = 127.0.0.2
self = 192.168.1.100
source = dnsbl://spamhaus.example.com
source = dnsbl://other-blocklist.net
Now queries to my-dnsbl.com will also check spamhaus.example.com and other-blocklist.net in real-time.
The server supports test queries using the IP 127.0.0.2 in reversed format.
Query domain: 2.0.0.127.* - the 2.0.0.127 part matches the test pattern.
# This query will always return a positive (blocked) response
dig 2.0.0.127.dnsbl.example.com
This is useful for:
- Testing server functionality
- Verifying DNS configuration
- Monitoring server health
# Create a blocklist file
echo "192.168.1.100" > /tmp/blocklist.txt
echo "10.0.0.0/24" >> /tmp/blocklist.txt
# Start the server
dnsbl-server \
-D my-dnsbl.com \
-r 127.0.0.2 \
-s 192.168.1.100 \
-f /tmp/blocklist.txt \
-v
/etc/dnsbl/server.ini:
[global]
interface = 0.0.0.0:53
max-requests = 120
no-request-limit = 127.0.0.1
query-log = /var/log/dnsbl/queries.log
reload = 60
daemon = true
log = /var/log/dnsbl/server.log
[domain "spam.example.com"]
response = 127.0.0.2
self = 10.0.0.1
txt = "This IP is a spam source"
source = https://example.com/spam-list.txt
source = dnsbl://other-spam-list.net
[domain "malware.example.com"]
response = 127.0.0.3
self = 10.0.0.1
txt = "Malware detected on IP @"
source = /var/lib/dnsbl/malware.txt
source = https://malware-domains.com/dnsbl.txt
mx = mail.example.com,10
Start the server:
dnsbl-server --config /etc/dnsbl/server.ini
# Forward all queries to another DNSBL without local blocklist
dnsbl-server \
-D forwarder.com \
-r 127.0.0.2 \
-s 192.168.1.100 \
-f dnsbl://upstream-dnsbl.org
# Setup: Start server in one terminal
dnsbl-server -D test.com -r 127.0.0.2 -s 127.0.0.1 -f /tmp/blocklist.txt
# In another terminal, test queries
dnsbl-query -d test.com 192.168.1.100 -v
dnsbl-query -d test.com 192.168.1.200 -v -q
dnsbl-query -d test.com 2.0.0.127 -s 127.0.0.1:53
/etc/systemd/system/dnsbl.service:
[Unit]
Description=DNSBL Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/dnsbl-server --config /etc/dnsbl/server.ini
Restart=always
User=dnsbl
Group=dnsbl
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
Problem: Permission denied on port 53
Solution: Run as root or use CAP_NET_BIND_SERVICE:
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/dnsbl-server
Problem: Remote DNSBL queries consistently fail
Solutions:
- Check network connectivity to remote DNS servers
- Verify the remote DNSBL domain is correct
- Increase query timeout in configuration
- Check DNS resolution of remote NS records
Solution: Reduce blocklist size or increase reload interval:
reload = 120 # Reload less frequently
Solutions:
- Increase max-requests value
- Add trusted IPs to no-request-limit
- Use no-request-limit-file for larger exempt lists
This software is released under the GNU General Public License.
Copyright (c) 2026, Philippe TEMESI - https://www.tems.be