DNS Monitoring Setup (Changes, TTL, DNSSEC)
DNS monitoring is often overlooked — unjustly. Unauthorized DNS record changes, domain expiration, or DNSSEC failure can make a website inaccessible as effectively as a server outage. Meanwhile, DNS issues often go unnoticed in server monitoring.
What to Monitor in DNS
A/AAAA records. Unexpected IP changes indicate: DNS hijacking, erroneous changes in the control panel, registrar account compromise.
MX records. MX changes suggest possible email interception attacks.
NS records. NS server changes are a serious compromise indicator.
TTL. Anomalously low TTL (< 60 seconds) may indicate preparation for record changes.
DNSSEC. Broken DNSSEC signature = complete domain unavailability for DNSSEC-validating resolvers.
Domain expiration date. Expired domain = loss of entire DNS configuration.
Record Change Monitoring
import dns.resolver
import dns.dnssec
import hashlib
import json
from datetime import datetime
def get_dns_records(domain: str, record_types: list = None) -> dict:
if record_types is None:
record_types = ['A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME']
records = {}
resolver = dns.resolver.Resolver()
resolver.nameservers = ['8.8.8.8', '1.1.1.1'] # Check through different resolvers
for rtype in record_types:
try:
answers = resolver.resolve(domain, rtype)
records[rtype] = sorted([str(r) for r in answers])
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
records[rtype] = []
except Exception as e:
records[rtype] = [f'ERROR: {e}']
return records
def check_dns_changes(domain: str, stored_snapshot: dict) -> list:
current = get_dns_records(domain)
changes = []
for rtype, current_values in current.items():
stored_values = stored_snapshot.get(rtype, [])
if set(current_values) != set(stored_values):
changes.append({
'record_type': rtype,
'previous': stored_values,
'current': current_values,
'detected_at': datetime.utcnow().isoformat()
})
return changes
Run every 5-15 minutes. Upon detecting changes — immediate alert.
Monitoring Through Multiple Resolvers
DNS poisoning or improper zone configuration may propagate unevenly. Check through:
- Google (8.8.8.8)
- Cloudflare (1.1.1.1)
- OpenDNS (208.67.222.222)
- Regional resolvers (important for .ru domains)
If results differ across resolvers — sign of DNS hijacking or propagation issues.
Prometheus Blackbox Exporter for DNS
# blackbox.yml
modules:
dns_check:
prober: dns
timeout: 5s
dns:
query_name: "example.com"
query_type: "A"
valid_rcodes:
- NOERROR
validate_answer_rrs:
fail_if_not_matches_regexp:
- "example.com.\t.*\tIN\tA\t1.2.3.4"
# Alert: DNS not returning expected IP
- alert: DNSRecordChanged
expr: probe_success{job="dns_check"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "DNS check failed for {{ $labels.instance }}"
DNSSEC Validation
def check_dnssec(domain: str) -> dict:
resolver = dns.resolver.Resolver()
resolver.use_dnssec = True
resolver.nameservers = ['8.8.8.8']
try:
# Query with DO bit (DNSSEC OK)
answers = resolver.resolve(domain, 'A', raise_on_no_answer=False)
# Check for RRSIG presence
try:
rrsig = resolver.resolve(domain, 'RRSIG')
has_rrsig = len(rrsig) > 0
except:
has_rrsig = False
return {
'dnssec_valid': True,
'has_rrsig': has_rrsig,
'domain': domain
}
except dns.dnssec.ValidationFailure as e:
return {
'dnssec_valid': False,
'error': str(e),
'domain': domain
}
Manual verification tool: dig +dnssec example.com or https://dnsviz.net/.
Domain Expiration Monitoring
import whois
def get_domain_expiry(domain: str) -> int:
"""Returns days until expiration"""
w = whois.whois(domain)
expiry = w.expiration_date
if isinstance(expiry, list):
expiry = expiry[0]
days = (expiry.replace(tzinfo=None) - datetime.now()).days
return days
# Alert when < 30 days until expiration
WHOIS is not always reliable — some registrars hide the date. Alternative: monitor via Domainr API or registrar notifications.
Tools
- DNSCheck.tools — web interface for manual verification
- Pingdom — includes DNS monitoring in basic plan
- Zabbix with DNS templates — for on-premise monitoring
- AWS Route 53 Health Checks — monitor own DNS records
Implementation Timeline
- Change monitoring script + cron — 1-2 days
- Blackbox Exporter + Prometheus alerts — 1 day
- DNSSEC validation — 0.5 day
- Domain expiration monitoring — 0.5 day







