A customer was doing an IP address change on a server and wanted a quick way to find all references to the old IP address across all of their domains.
This seemed like a good job for our DNS API and a few UNIX utilities.
Finding matching records
Our DNS API makes it easy to find records with particular content:
curl -sn https://api.mythic-beasts.com/dns/v2/zones/example1.com/records?data=1.2.3.4
The -n
assumes we’ve got a .netrc
file with our API credentials. See our DNS API tutorial for more details.
This gives us a block of JSON with any matching records:
{
"records": [
{
"data": "1.2.3.4",
"host": "www",
"ttl": 300,
"type": "A"
}
]
}
jq lets us turn the presence or absence of any matching records into an exit code that we can test with an if statement by piping into the following:
jq -e '.records | length > 0'
This counts the number of members of the records
array, and -e
sets the exit code based on the output of the last expression.
Getting a list of zones
We want to check this across all zones, so let’s get a list of zones:
curl -sn https://api.mythic-beasts.com/dns/v2/zones
This gives us some JSON:
{
"zones": [
"example1.com",
"example2.com"
]
}
What we really want is a flat list, so we can iterate over it in bash. jq to the rescue again. Simply pipe into:
jq -r '.zones[]'
and we get:
example1.com
example2.com
Putting it all together
Putting this all together with a for
loop and an if
:
IP=1.2.3.4
for zone in $(curl -sn https://api.mythic-beasts.com/dns/v2/zones | jq -r '.zones[]') ; do
if curl -sn "https://api.mythic-beasts.com/dns/v2/zones/$zone/records?data=$IP" |\
jq -e '.records | length > 0' >/dev/null ; then
echo "$IP found in $zone"
fi
done
Gives:
1.2.3.4 found in example1.com
More than one way to do it
Another approach would be to use the zone file output format and check if the output is empty or not:
curl -sn -H 'Accept: text/dns' \
"https://api.mythic-beasts.com/dns/v2/zones/$zone/records?data=$IP"
This give us matching records, one per line:
www 300 A 1.2.3.4
We can then test if we’ve got any matches using ifne
(if-not-empty, part of the moreutils package in most distributions):
curl -sn -H 'Accept: text/dns' \
"https://api.mythic-beasts.com/dns/v2/zones/$zone/records?data=$IP" \
| ifne echo $IP found in $zone
Access to our DNS API is included with all domains registered with us. API credentials can be limited to individual zones or even records, can be either read/write or read-only.
ANAME records
Of course, it’s generally desirable to avoid including an IP address in lots of different DNS records in the first place. It’s preferable to assign the IP to a single hostname, and then point other records at that. Our DNS service supports ANAME records which allow the use of hostnames rather than IP addresses in places where CNAMEs cannot be used.