When working with DNS configurations, you might encounter situations where standard command-line tools like dig
, nslookup
, or host
don't reveal all CNAME records. This often happens when dealing with:
- Complex DNS architectures with multiple layers of redirection
- Private or internal DNS zones
- DNS providers that implement rate limiting
- Domains using modern DNS features like CNAME flattening
Here are several reliable methods to enumerate CNAME records programmatically:
1. Using DNS Zone Transfer (AXFR)
If the nameserver allows zone transfers (rare in production environments), you can try:
dig @ns1.example.com example.com AXFR | grep CNAME
2. Cloud Provider APIs
For domains hosted on services like AWS Route 53:
import boto3
client = boto3.client('route53')
response = client.list_resource_record_sets(
HostedZoneId='Z23ABC4XYZL05B',
StartRecordName='subdomain.example.com',
StartRecordType='CNAME'
)
for record in response['ResourceRecordSets']:
if record['Type'] == 'CNAME':
print(record['Name'], '->', record['ResourceRecords'][0]['Value'])
3. DNS Query Brute-forcing
For situations where you need to discover subdomains:
import dns.resolver
base_domain = "example.com"
common_subdomains = ["www", "mail", "web", "api", "dev"]
for sub in common_subdomains:
try:
answers = dns.resolver.resolve(f"{sub}.{base_domain}", 'CNAME')
for rdata in answers:
print(f"{sub}.{base_domain} -> {rdata.target}")
except dns.resolver.NoAnswer:
continue
4. Using Specialized DNS Tools
Consider tools like:
dnsrecon
for comprehensive DNS enumerationfierce
for brute-force subdomain discoverysublist3r
for OSINT-based subdomain discovery
When querying DNS programmatically, always implement:
import time
import random
def query_with_backoff(domain, record_type):
max_retries = 3
for attempt in range(max_retries):
try:
return dns.resolver.resolve(domain, record_type)
except dns.resolver.NXDOMAIN:
return None
except (dns.resolver.Timeout, dns.resolver.NoNameservers):
if attempt < max_retries - 1:
sleep_time = random.uniform(1, 3) * (attempt + 1)
time.sleep(sleep_time)
continue
raise
For domains with CNAME chains:
def resolve_cname_chain(domain, max_hops=10):
chain = []
current_domain = domain
for _ in range(max_hops):
try:
answer = dns.resolver.resolve(current_domain, 'CNAME')
target = str(answer[0].target).rstrip('.')
chain.append((current_domain, target))
current_domain = target
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
break
return chain
Remember that DNS records can be cached at multiple levels (local resolver, ISP, etc.), so your program should account for possible stale data during development and testing.
When working with DNS configurations, developers often need to enumerate all CNAME records for troubleshooting or infrastructure management. Standard tools like dig
, nslookup
, and host
don't directly provide this capability because:
- CNAMEs are alias records that point to other domain names
- Most tools only show CNAMEs when querying specific subdomains
- DNS servers typically don't support wildcard queries for record types
1. Using dig with AXFR (Zone Transfer)
If you have proper permissions, perform a zone transfer:
dig example.com AXFR
Note: This requires zone transfer to be allowed on the DNS server (rare in production environments).
2. DNS Enumeration with dnsrecon
Security tools can help discover records:
dnsrecon -d example.com -t std
This will list various record types including CNAMEs.
3. Programmatic Approach Using Python
Here's a script using the dnspython
library:
import dns.resolver
def find_cnames(domain):
try:
answers = dns.resolver.resolve(domain, 'CNAME')
for rdata in answers:
print(f"{domain} CNAME {rdata.target}")
except dns.resolver.NoAnswer:
pass
except dns.resolver.NXDOMAIN:
print(f"{domain} does not exist")
# Example usage
domains = ['www.example.com', 'mail.example.com', 'api.example.com']
for domain in domains:
find_cnames(domain)
- For cloud providers (AWS Route 53, Cloudflare), use their APIs for complete record listings
- Remember that CNAME chains can exist (CNAME pointing to another CNAME)
- Some DNS providers limit the number of queries per second
Consider these specialized utilities:
fierce
- DNS reconnaissance tooldnsenum
- Perl script for DNS enumerationmassdns
- High-performance bulk resolver