DNS Record History – A Tool for Restoring DNS Records

Article summary

People who work in IT Operations know that “Everything is a DNS Problem.” Recently, a client experienced an issue where the MX records for their domain were inadvertently changed, which resulted in e-mail not being delivered. Unfortunately there was no DNS history—no record existed of what the MX records had been. The DNS entries had been set up years ago, and no one knew exactly how the system had been configured. This necessitated an investigation and analysis to determine what the records should be.

Prior to the investigation, I tried to determine if there was someplace I could look up the history of DNS records for a domain. While I found some DNS records (notably NS and A records) and some sites that listed the history of WHOIS records, I didn’t find any that listed the history of MX records. Having encountered this issue before, I decided to write an application that would allow me to track the DNS history for a domain so that any would be logged and could be used for reference in the future.

The Concept

The application takes a set of domain names and record types, queries DNS for the records, and stores them in a database. The idea is to run checks periodically. When the application is run, it checks the previous value of a record against the current value. If it differs, the new record is stored in the database.

I made use of the Ruby Resolv library. Using it, we can query A records for a domain as follows:

resolver = Resolv::DNS.new
resolver.getresources('atomicobject.com', Resolv::DNS::Resource::IN::A)

Which returns an array containing an object representing the IPv4 address for atomicobject.com:

=> [#, @ttl=224>]

And then we can query MX records as follows:

resolver = Resolv::DNS.new
resolver.getresources('example.com', Resolv::DNS::Resource::IN::MX)

Which returns an array containing objects representing the mail exchanges for atomicobject.com:

=> [
#, @preference=50, @ttl=4805>,
 #, @preference=100, @ttl=4805>,
 #, @preference=0, @ttl=4805>,
 #, @preference=5, @ttl=4805>,
 #, @preference=10, @ttl=4805>,
 #, @preference=20, @ttl=4805>,
 #, @preference=30, @ttl=4805>

By storing this data, we can track any changes. This is useful not only to detect if the DNS records are changed, but also to be able to revert any changes if they were unintended or erroneous. Having this information readily available makes any such updates much faster without the need to do an investigation or analysis to determine what the correct DNS records should be.

The Application

I’ve published the application on GitHub. To test it out, you can push it to Heroku. All you need to do is add a config.yml following the example format in config.yml.example, add the Heroku Postgres add-on, and configure a Heroku Scheduler task (for periodic record checks).

The application uses the DATABASE_URL environment variable from Heroku Postgres to connect to the database.

The scheduled task can be configured at any frequency, but should invoke:

bundle exec rake dns:track_records

The records will be stored in the Heroku Postgres database in the records table which has a structure like:

   Column    |           Type           |                      Modifiers                       | Storage  | Stats target
 id          | integer                  | not null default nextval('records_id_seq'::regclass) | plain    |
 fqdn        | text                     |                                                      | extended |
 datetime    | timestamp with time zone |                                                      | plain    |
 record_type | text                     |                                                      | extended |
 record      | text                     |                                                      | extended |
    "primary_key" PRIMARY KEY, btree (id)

The actual records are stored as a serialized Ruby DNS resource object in YAML.

For example, after running the application, the following A record is stored for atomicobject.com:

- !ruby/object:Resolv::DNS::Resource::IN::A
  address: !ruby/object:Resolv::IPv4
    address: !binary |-
  ttl: 300

Which, when unmarshalled, provides:

=> [#, @ttl=300>]

I’m confident that tracking DNS history like this will help me in tackling future DNS problems. I hope that it will be useful to other IT operations professionals and teams as well.

  • Andres says:

    I am trying to come up with a tool that can track domain name changes. If a given domain is on a given IP today and changes IP tomorrow, I would like to be able to track these changes and update my DB. I work in security, mainly web protection and track malicious domains/IPs.

    Any ideas or thoughts that can help me out is greatly appreciated.



  • Comments are closed.