The dig command is an incredibly powerful tool for querying DNS records. Dig stands for Domain Information Groper and is the utility of choice for most DNS administrators working on Linux. It can be used to confirm DNS entries, get your public IP address from the command line, troubleshoot DNS issues and get information about a DNS zone.

Dig is part of the BIND (Berkely Internet Name Domain) software utilities (bind-utils). Although not installed by default, it is available on nearly all Linux distributions by installing the bind-utils package or Red Hat variants or dnsutils on Debian based distros.

How to Install Dig

You can install bind-utils on Red Hat (rpm) based distros using the yum or dnf commands (depending on which distro you are using).

$ sudo yum install bind-utils -y

or

$ sudo dnf install bind-utils -y

For Debian based distros like Ubuntu, you can install with apt.

$ sudo apt-get install dnsutils -y

Once you have the package installed, you should have the dig command as well as nslookup and host.

Basic Dig Usage

The basic dig command syntax is:

dig [options] [type] [@nameserver] name

Here is a break down of each option.

dig - Calling the binary of the utility.
options - Options such as trace, short listing, and reverse lookup.
type - Type of record to query, if no type is specified it will default to an A record (other types include AAAA, MX, TXT, CNAME, etc.).
@nameserver - Specify the name server to query, if none is given it will default to name servers configured for the system.
name - Name of record to lookup.

Query an A Record

An A record is a basic forward zone lookup. It maps a name to an IP address. Since the A record is the default lookup, you do no need to specify the type. Here is an example:

$ dig ipaddr.pub
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> ipaddr.pub
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33214
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ipaddr.pub. IN A
;; ANSWER SECTION:
ipaddr.pub. 300 IN A 104.27.133.158
ipaddr.pub. 300 IN A 104.27.132.158

;; Query time: 173 msec
;; SERVER: 10.0.0.1#53(10.0.0.1)
;; WHEN: Fri Feb 15 22:04:16 EST 2019
;; MSG SIZE rcvd: 71

We received an answer giving us the IP address(es) highlighted in bold.

Specify Name Server to Query

You may specify a name server you wish to query using the @nameserver option. Here is an example query specifying Googles public DNS as the name server.

$ dig @8.8.8.8 ipaddr.pub
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> @8.8.8.8 ipaddr.pub
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19530
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;ipaddr.pub. IN A
;; ANSWER SECTION:
ipaddr.pub. 299 IN A 104.27.132.158
ipaddr.pub. 299 IN A 104.27.133.158

;; Query time: 52 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Feb 15 22:08:45 EST 2019
;; MSG SIZE rcvd: 71

We received an answer giving us the IP address(es) highlighted in bold.

Specify Record Type to Query

You can also specify the type of record to query. Here is an example query asking for the name servers associated with ipaddr.pub.

$ dig NS ipaddr.pub
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> NS ipaddr.pub
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34022
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;ipaddr.pub. IN NS
;; ANSWER SECTION:
ipaddr.pub. 86400 IN NS thomas.ns.cloudflare.com.
ipaddr.pub. 86400 IN NS vida.ns.cloudflare.com.

;; Query time: 171 msec
;; SERVER: 10.0.0.1#53(10.0.0.1)
;; WHEN: Fri Feb 15 22:06:58 EST 2019
;; MSG SIZE rcvd: 96

As you can see, dig answered with the name servers instead of the IP address, which is exactly what we asked for. This works for any type of record, except PTR records.

Querying Reverse Lookups

A reverse lookup (PTR record) is the opposite of an A record. It maps a name to an IP address. So for this example, we know the IP address and we want to know the name. We use the -x switch in dig to tell it we are looking for a reverse lookup. We will use one of my favorites.

$ dig -x 1.1.1.1
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> -x 1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35452
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;1.1.1.1.in-addr.arpa. IN PTR
;; ANSWER SECTION:
1.1.1.1.in-addr.arpa. 1800 IN PTR one.one.one.one.
;; Query time: 1197 msec
;; SERVER: 10.0.0.1#53(10.0.0.1)
;; WHEN: Fri Feb 15 22:28:51 EST 2019
;; MSG SIZE rcvd: 78

I love a DNS administrator with a sense of humor.

Getting the Short Answer

If you just want the answer without all the other information (which we will cover shortly) you can use the +short option.

$ dig +short ipaddr.pub
104.27.133.158
104.27.132.158

Ahhh, finally a straight answer.

Putting It All Together

You can use any of the options we covered or all of them, they are not mutually exclusive.

$ dig +short @8.8.8.8 TXT ipaddr.pub
"ca3-6cc4e64736bd4906bf2a6473136cd2b7"
"Get your public IP address here"

That it the basics of the dig command. Great, but if you don't understand the output you might as well use nslookup (sorry for the jab, nslookup is a fine tool). In the next section we will break down each line of the output.

Understanding Dig Output

As we mentioned in the introduction, dig is a very powerful tool. As such it has a bevy of options that can change the output. Here we will explain the output with the default global options and just touch on a few others.

Let's start with a fresh query, then we will break it down and explain it line by line.

$ dig @8.8.8.8 TXT ipaddr.pub
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> @8.8.8.8 TXT ipaddr.pub
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14764
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;ipaddr.pub. IN TXT
;; ANSWER SECTION:
ipaddr.pub. 299 IN TXT "ca3-6cc4e64736bd4906bf2a6473136cd2b7"
ipaddr.pub. 299 IN TXT "Get your public IP address here"
;; Query time: 51 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Feb 15 23:08:56 EST 2019
;; MSG SIZE rcvd: 132

Information Sections

Now let's break it down.

 ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> @8.8.8.8 TXT ipaddr.pub

The first line tells us the version information and the query we specified.

 ; (1 server found)

One server was found, this is because we specified a single server to query (and it was found).

;; global options: +cmd

This is the global options used, by default on my system it is +cmd which means print the output of the version (first line).

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14764

Above is the header information. The opcode is the action we requested (query), the status of that action was NOERROR, and the id is a unique identifier used by the client to match the response from the DNS server to the query.

Status codes can be:
NOERROR - The query was received and answered without any errors.
NXDOMAIN - The record requested does not exist.
SERVFAIL - The record exists, but the data is invalid or otherwise doesn't have a value.
REFUSED - The name server refused to perform the requested operation.

 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

Flags are codes for options being used for the operation and specify things such as recursion desired, authoritative answer, and recursion available. For a list of all available flags see page 26 of RFC 1035.

The rest of the line gives us amount information for each item. In this example there was 1 query, 2 answers, 0 authoritative answers and 1 piece of additional information.

 ;; OPT PSEUDOSECTION:

The above is just a section label.

 ; EDNS: version: 0, flags:; udp: 512

Question Section

EDNS is Extension Mechanisms for DNS which is a specification for expanding the size of parameters in the DNS protocol. This indicates conformance with EDNS0 (version 0), no flags were passed, and udp port 512 was used.

;; QUESTION SECTION:

Another section label.

;ipaddr.pub.            IN  TXT

Above is the query or question we asked of the DNS server. In this case we asked for the TXT record of ipaddr.pub.

Answer Section

 ;; ANSWER SECTION:

Answer section label.

 ipaddr.pub.        299 IN  TXT "ca3-6cc4e64736bd4906bf2a6473136cd2b7"
ipaddr.pub. 299 IN TXT "Get your public IP address here"

These are the answers that were provided by the name server. Remember back in the first line with the flags it said ANSWER: 2. The columns left to right are name, time to live (299), class (Internet), record type (TXT), and value.

 ;; Query time: 51 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Feb 15 23:08:56 EST 2019
;; MSG SIZE rcvd: 132

These last four lines tell us how long it took for the query to complete, which server we used, what time the query was made and the size of the return message in bytes.

More Examples

Let's take a look at some more examples of how to use dig and some new options.

Trace a DNS path

With the +trace option, we can actually follow the path of a query. It will "trace" the path of the query from the root servers down to the answer. This is very helpful for troubleshooting DNS issues.

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.1 <<>> +additional +trace +norec ipaddr.pub. @8.8.4.4
;; global options: +cmd
. 249804 IN NS h.root-servers.net.
. 249804 IN NS g.root-servers.net.
. 249804 IN NS a.root-servers.net.
. 249804 IN NS k.root-servers.net.
. 249804 IN NS f.root-servers.net.
. 249804 IN NS e.root-servers.net.
. 249804 IN NS b.root-servers.net.
. 249804 IN NS d.root-servers.net.
. 249804 IN NS l.root-servers.net.
. 249804 IN NS m.root-servers.net.
. 249804 IN NS c.root-servers.net.
. 249804 IN NS j.root-servers.net.
. 249804 IN NS i.root-servers.net.
;; Received 228 bytes from 8.8.4.4#53(8.8.4.4) in 5 ms
pub. 172800 IN NS demand.beta.aridns.net.au.
pub. 172800 IN NS demand.alpha.aridns.net.au.
pub. 172800 IN NS demand.delta.aridns.net.au.
pub. 172800 IN NS demand.gamma.aridns.net.au.
;; Received 324 bytes from 198.41.0.4#53(198.41.0.4) in 3 ms
ipaddr.pub. 86400 IN NS thomas.ns.cloudflare.com.
ipaddr.pub. 86400 IN NS vida.ns.cloudflare.com.
;; Received 85 bytes from 37.209.194.7#53(37.209.194.7) in 67 ms
ipaddr.pub. 300 IN A 104.27.132.158
ipaddr.pub. 300 IN A 104.27.133.158
;; Received 60 bytes from 173.245.59.238#53(173.245.59.238) in 2 ms

DNS names are read from right to left, so first the root servers "." are queried for the name servers responsible for .pub, then the servers responsible for the top level domain (TLD) .pub, then the authoritative name servers for ipaddr.pub are queried and finally the query is answered.

Query Multiple Domains from a File

We can use a simple text file with domains, one per line, to query multiple records with one command. The -f option tells dig to read through the file and perform a query with the string on each line. Here is a our example file:

$ cat domains.txt 
ipaddr.pub
putorius.net
google.com
hereyah.com
pinkfloyd.com

Here is the command and it's output:

$ dig -f domains.txt +short
104.27.132.158
104.27.133.158
50.116.93.91
172.217.10.238
50.116.93.91
70.32.66.139

It's a simple tip, but one that comes in handy for scripting or if you have an exported list of domains.

Custom Output Using Global Options

You can tailor the output to your needs by using some global options. Here are a couple examples.

Hide All Output

It sounds silly to hide all the output, but it comes in handy because once you hide all the output, you can show only what you want with more options.

$ dig +noall ipaddr.pub
$

The +noall option hides all of the output including the answer.

Version Information Only

$ dig +noall +cmd ipaddr.pub
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-13.P2.fc29 <<>> +noall +cmd ipaddr.pub
;; global options: +cmd

Using the +noall to hide all the output, we can use other options to show only what we choose. Here we use the +cmd option to show only the version information.

Statistics Only

$ dig +noall +stats ipaddr.pub
;; Query time: 0 msec
;; SERVER: 10.0.0.1#53(10.0.0.1)
;; WHEN: Sat Feb 16 00:17:57 EST 2019
;; MSG SIZE rcvd: 71

The +stats option used in conjunction with +noall, shows only the statistics.

Answer Only

$ dig +noall +answer ipaddr.pub
ipaddr.pub. 6 IN A 104.27.132.158
ipaddr.pub. 6 IN A 104.27.133.158

Using +short shows the answer also, but without the additional information (name, ttl, class, record type, and answer).

Set Custom Defaults

We can use a configuration file in our home directory named .digrc and set custom default options for dig. For example, of we want to short answers only we can make the file like so:

$ cat ~/.digrc
+noall
+answer

Now when we use dig, it will automatically use the options set in that file.

 $ dig ipaddr.pub
ipaddr.pub. 267 IN A 104.27.133.158
ipaddr.pub. 267 IN A 104.27.132.158

Any of the options available on the command line can be put into the configuration file as defaults. You can also use an alias to make "shortcuts" to your favorite command / option combinations.

Conclusion

As we have shown, dig is a great tool with a lot of options. We did not cover all the options but we covered the basics, showed examples of how to use options and explained the output in depth. This tutorial should be enough to put you on the path to dig mastery.

If you enjoyed this tutorial please consider sharing it with your friends and peers. Feel free to sound off in the comments with any questions or corrections.

Resources

dig man page
dig wikipedia page
DNS RFC list (some light reading)