A rented IP block can change status without warning: an address ends up on a blacklist because of one customer, a geolocation database moves the range to another country, or a ROA change makes your announcement invalid. Finding out from users weeks later is expensive. This guide builds a small monitoring script that checks every address in your blocks every day against the main DNS blacklists, compares geolocation with the expected country, verifies RPKI, and sends a Telegram message when something changes.
# Debian / Ubuntu
apt install -y unbound dnsutils jq curl
systemctl enable --now unbound
# Test: a listed test address must return 127.0.0.x through the local resolver
dig +short 2.0.0.127.zen.spamhaus.org @127.0.0.1
The answer 127.0.0.2 (and others) for the test address 127.0.0.2 confirms that blacklist lookups work.
To check 203.0.113.10 against a blacklist zone, reverse the octets and append the zone. No answer (NXDOMAIN) means not listed; an answer in 127.0.0.0/8 means listed, and the last octet says which list.
dig +short 10.113.0.203.zen.spamhaus.org @127.0.0.1
# 127.0.0.2 / .3 SBL / CSS (spam sources)
# 127.0.0.4 – .7 XBL (exploited hosts, malware)
# 127.0.0.9 DROP (hijacked or criminal ranges)
# 127.0.0.10 / .11 PBL (policy: not expected to send mail directly; not a sign of abuse)
# 127.255.255.x query error (public resolver, rate limit), not a listing
mkdir -p /opt/ipmon
cat > /opt/ipmon/blocks.txt <<'EOF2'
# prefix expected country origin ASN
203.0.113.0/24 JP AS64500
198.51.100.0/24 KR AS64500
EOF2
cat > /opt/ipmon/check.sh <<'EOF2'
#!/bin/bash
# Daily IP block check: DNSBL listings, geolocation and RPKI. Prints problems only.
ZONES="zen.spamhaus.org bl.spamcop.net psbl.surriel.com dnsbl-1.uceprotect.net"
grep -v '^#' /opt/ipmon/blocks.txt | while read -r PREFIX CC ASN; do
[ -z "$PREFIX" ] && continue
BASE=${PREFIX%.*} # works for /24 blocks: 203.0.113
IFS=. read -r a b c _ <<< "$PREFIX"
for d in $(seq 1 254); do
for z in $ZONES; do
r=$(dig +short +time=2 +tries=1 "$d.$c.$b.$a.$z" @127.0.0.1 | head -1)
case "$r" in
127.255.255.*|"") ;; # error or not listed
127.0.0.10|127.0.0.11) ;; # Spamhaus PBL: policy list, ignore
127.*) echo "LISTED $BASE.$d on $z ($r)";;
esac
done
done
# Geolocation of a few sample addresses
for d in 1 64 128 200 254; do
got=$(curl -s --max-time 10 "https://ipinfo.io/$BASE.$d/country" | tr -d '[:space:]')
[ -n "$got" ] && [ "$got" != "$CC" ] && echo "GEO $BASE.$d is $got, expected $CC"
done
# RPKI status of the announcement
st=$(curl -s --max-time 20 "https://stat.ripe.net/data/rpki-validation/data.json?resource=$ASN&prefix=$PREFIX" | jq -r '.data.status')
[ "$st" != "valid" ] && echo "RPKI $PREFIX from $ASN is $st"
done
EOF2
chmod +x /opt/ipmon/check.sh
/opt/ipmon/check.sh
The script prints nothing when everything is fine. It is written for /24 blocks; split larger blocks into /24 lines. A full /24 against four zones is about a thousand DNS queries, which takes a few minutes and is acceptable once a day.
Create a Telegram bot and find your chat ID as described in Uptime Kuma monitoring with Telegram alerts. Then wrap the check in a small sender that only messages you when there are findings:
cat > /opt/ipmon/run.sh <<'EOF2'
#!/bin/bash
TOKEN="123456:ABC-your-bot-token"
CHAT="123456789"
OUT=$(/opt/ipmon/check.sh 2>&1)
if [ -n "$OUT" ]; then
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
--data-urlencode "chat_id=$CHAT" \
--data-urlencode "text=IP block check $(hostname) $(date +%F):
$OUT" >/dev/null
fi
EOF2
chmod 700 /opt/ipmon/run.sh
# Every day at 07:30
echo '30 7 * * * root /opt/ipmon/run.sh' > /etc/cron.d/ipmon
Your queries go through a public or shared resolver, which Spamhaus blocks; the answers are errors, not listings. Make sure the script uses @127.0.0.1 with unbound running, or use a DQS key.
The Spamhaus PBL lists ranges that are not expected to send mail directly to the internet. It is a policy list, not a sign of abuse; IPs that do send mail can be removed from it on the Spamhaus website.
Yes, add zones to ZONES. Check each list's usage policy first; some require registration for automated queries, and some list whole ranges for reasons unrelated to your own behaviour.
Still stuck after following these steps? Open a support ticket and the IMIDC 24/7 technical team will help. Include your IP blocks, the script output and the blacklist or database that reports a problem so we can pinpoint the issue faster.