Troubleshooting DNS issues with dig

Keet Malin Sugathadasa
10 min readAug 27, 2023

--

Domain Name Systems are responsible for translating human-readable hostnames into IP addresses of backend servers. It sounds straightforward, but in reality, this process is complicated underneath and there are many hops for a request until it reaches the destination.

To continue with this article, you would need a good understanding of how DNS works, its caching, nameserver, and record types.

Let’s go through some of the basic commands first and dive deep into troubleshooting certain scenarios using these commands.

Installing dig

First of all, let’s see whether these tools are already installed on your Linux machine. You could also install these on your Windows machine, but it is beyond the scope of this article.

Let’s install dnsutils which comes with both dig , nslookup and some other dns tools.

> apt install dnsutils

To verify the installation run the following command:

> dig -v
DiG 9.10.6

Basic commands for dig

How to use the dig command

dig <@dns-server> <domain> <record-type> <class> <query-options> <default-options>
  • <@dns-server> → Default is the local DNS server given in /etc/resolve.conf . But we can also specify a server with the @ sign
  • <domain> → Domain or host address to be queried
  • <record-type> → is one of (a,any,mx,ns,soa,hinfo,axfr,txt,…) [default:a]
  • <class> → is one of (in,hs,ch,…) [default: in]
  • <query-options> → query options start with - . Some common query options are
-b address[#port]   (bind to source address/port)
-p port (specify port number)
-x dot-notation (shortcut for reverse lookups)
  • <display-options> → is of the form +keyword[=value]. Some common display options are
 +[no]additional     (Control display of additional section)
+[no]answer (Control display of answer section)
+[no]authority (Control display of authority section)
+[no]cl (Control display of class in records)
+[no]comments (Control display of comment lines)
+[no]expire (Request time to expire)
+[no]fail (Don't try next server on SERVFAIL)
+[no]question (Control display of question section)
+[no]short (Display nothing except short form of answer)
+[no]trace (Trace delegation down from root [+dnssec])

Understanding the output of dig

➜  ~ dig google.com

; <<>> DiG 9.10.6 <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39959
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 200 IN A 74.125.68.138
google.com. 200 IN A 74.125.68.102
google.com. 200 IN A 74.125.68.113
google.com. 200 IN A 74.125.68.139
google.com. 200 IN A 74.125.68.101
google.com. 200 IN A 74.125.68.100

;; Query time: 67 msec
;; SERVER: 172.20.10.1#53(172.20.10.1)
;; WHEN: Sun Aug 27 18:58:34 +0530 2023
;; MSG SIZE rcvd: 135

Let’s break down each section and try to understand the response.

  • Lines starting with ; are comments. They do not include the actual DNS server details.
  • ; <<>> DiG 9.10.6 <<>> google.com → shows the dig version and the query we entered
  • The HEADER section is the response it received from the DNS server. The flags refer to the answer section.
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39959
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
  • The OPT PSEUDOSECTION displays advanced data.

EDNS — Extension system for DNS, if used
Flags — blank because no flags were specified
UDP — UDP packet size

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
  • The QUESTION SECTION displays the query that was sent.

google.com. → domain name queried

IN → type of query (IN: Internet)

A → DNS record type

;; QUESTION SECTION:
;google.com. IN A
  • The ANSWER SECTION is what gives the relevant records

google.com. → domain name queried

200 → this is the TTL for each record in seconds

IN → type of query (IN: Internet)

A → DNS record type

74.125.68.138 → the IP address associated with the domain name

;; ANSWER SECTION:
google.com. 200 IN A 74.125.68.138
google.com. 200 IN A 74.125.68.102
google.com. 200 IN A 74.125.68.113
google.com. 200 IN A 74.125.68.139
google.com. 200 IN A 74.125.68.101
google.com. 200 IN A 74.125.68.100
  • The STATISTICS section shows metadata about the query

Query time — The amount of time it took for a response
SERVER — The IP address and port of the responding DNS server. You may notice a loopback address in this line — this refers to a local setting that translates DNS addresses. Usually found in /etc/resolv.conf
WHEN — Timestamp when the command was run
MSG SIZE rcvd — The size of the reply from the DNS server

;; Query time: 67 msec
;; SERVER: 172.20.10.1#53(172.20.10.1)
;; WHEN: Sun Aug 27 18:58:34 +0530 2023
;; MSG SIZE rcvd: 135

Troubleshooting with dig

Check if the server is reachable

In the HEADER SECTION , the status shows the status of the DNS or backend server.

  • NOERROR — Everything’s cool. The zone is being served by the requested authority without issues.
  • SERVFAIL — The name that was queried exists, but there’s no data or invalid data for that name at the requested authority.
  • NXDOMAIN — The name in question does not exist, and therefore there is no authoritative DNS data to be served.
  • REFUSED — Not only does the zone not exist at the requested authority, but their infrastructure is not in the business of serving things that don’t exist at all.

Let’s try out a few examples

➜  ~ dig google.com

....
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46275
....
➜  ~ dig keetmalin.com

....
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 58183
....

Specify a DNS resolver for a query

This helps you understand how a DNS is resolved by a public DNS resolver. By default, dig uses the local configuration given in /etc/resolv.conf to decide which nameserver to query. These are known as public DNS resolvers. Some examples are

  • cloudflare: 1.1.1.1
  • google: 8.8.8.8
  • quad9: 9.9.9.9
➜  ~ dig @1.1.1.1 google.com

; <<>> DiG 9.10.6 <<>> @1.1.1.1 google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18888
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;google.com. IN A

;; ANSWER SECTION:
google.com. 114 IN A 142.251.37.46

;; Query time: 200 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Sun Aug 27 20:32:08 +0530 2023
;; MSG SIZE rcvd: 55

Verify whether the DNS reaches the final server IP

This is probably the most common use case of dig. Let’s see the final server IP address of keetmalin.medium.com. You can also do the same for your domains and see if it lists your relevant backend servers.

As you can see below, keetmalin.medium.com points to 2 backend servers 162.159.152.4 and 162.159.153.4.

➜  ~ dig keetmalin.medium.com

; <<>> DiG 9.10.6 <<>> keetmalin.medium.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55713
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;keetmalin.medium.com. IN A

;; ANSWER SECTION:
keetmalin.medium.com. 377 IN A 162.159.153.4
keetmalin.medium.com. 377 IN A 162.159.152.4

;; Query time: 77 msec
;; SERVER: 172.20.10.1#53(172.20.10.1)
;; WHEN: Sun Aug 27 21:42:46 +0530 2023
;; MSG SIZE rcvd: 81

Trace hostname A records and DNS name server records

For the sake of this article, let’s do this with a single command. If I summarise the journey of a request in DNS, it goes through the following

  • DNS recursive resolver: This is the first stop in a DNS query. The recursive resolver acts as a middleman between a client and a DNS nameserver. It accepts a hostname from the client, checks with DNS servers and returns an IP address to the client.
  • DNS root nameserver: The 13 DNS root nameservers are known to every recursive resolver, and they are the first stop in a recursive resolver’s quest for DNS records. A root server accepts a recursive resolver’s query which includes a domain name, and the root nameserver responds by directing the recursive resolver to a TLD nameserver, based on the extension of that domain (.com, .net, .org, etc.).
  • TLD nameserver: A TLD nameserver maintains information for all the domain names that share a common domain extension, such as .com, .net, or whatever comes after the last dot in a URL. This nameserver responds by directing the resolver to an authoritative nameserver.
  • Authoritative nameserver: The authoritative nameserver is usually the resolver’s last step in the journey for an IP address. This returns an A record, or a CNAME record pointing to an alias A record. However it is done, the resolver should get an IP address if it exists.

Now let’s debug this with +trace , for the hostname: keetmalin.medium.com.

➜  ~ dig keetmalin.medium.com +trace

; <<>> DiG 9.10.6 <<>> keetmalin.medium.com +trace
;; global options: +cmd
. 2745 IN NS a.root-servers.net.
. 2745 IN NS c.root-servers.net.
. 2745 IN NS j.root-servers.net.
. 2745 IN NS m.root-servers.net.
. 2745 IN NS g.root-servers.net.
. 2745 IN NS e.root-servers.net.
. 2745 IN NS d.root-servers.net.
. 2745 IN NS h.root-servers.net.
. 2745 IN NS l.root-servers.net.
. 2745 IN NS i.root-servers.net.
. 2745 IN NS b.root-servers.net.
. 2745 IN NS f.root-servers.net.
. 2745 IN NS k.root-servers.net.
;; Received 239 bytes from 172.20.10.1#53(172.20.10.1) in 42 ms

com. 172800 IN NS e.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS d.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
com. 172800 IN NS f.gtld-servers.net.
com. 172800 IN NS j.gtld-servers.net.
com. 172800 IN NS k.gtld-servers.net.
com. 172800 IN NS c.gtld-servers.net.
com. 172800 IN NS g.gtld-servers.net.
com. 172800 IN NS h.gtld-servers.net.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS m.gtld-servers.net.
com. 86400 IN DS 30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com. 86400 IN RRSIG DS 8 1 86400 20230909050000 20230827040000 11019 . Jg5GfQXXzS37hg6eMjYtwr4Sq7L7ojgJS2bsLN8/zxv8K3i+R4Lj8v9j nfUT5v2MImm1rel0y0NLfNMGuJhawllnCWrgYoGPbm6+lZugixjLkm/7 XWcR4/vXDwBDChPp7+wBH5K97yk+b8NraN4/F/J5Xf+PuJKdoKLH5pSn vxkt1pf25fqvfAhiofiJRvrZ6ayVJf0p5svBArSgDvB+YdbV/x6AA5PD d7tkNNR4QCGLAtzj5hRKe5UJUTsFmXuohlNEnSo+tPUboNAhWNfGEXez JgCkZjfFQOB4UlnYcwAit4ocWYj19o3Voa5iUXg4FCQnXoZ0ETdxMLQ9 X6pduA==
;; Received 1180 bytes from 192.203.230.10#53(e.root-servers.net) in 182 ms

medium.com. 172800 IN NS kip.ns.cloudflare.com.
medium.com. 172800 IN NS alina.ns.cloudflare.com.
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q2D6NI4I7EQH8NA30NS61O48UL8G5 NS SOA RRSIG DNSKEY NSEC3PARAM
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20230903042431 20230827031431 4459 com. OROhP15YNzk5K7aj9L7UbApWHWLqii/AeMOR8oZdBfKYWk3+wmtoeD+R PjYwx4pOLvcrxaA6nV/kCkdNyU1cPv1434vMHkrjbarCx+Ri+tzpEByX jtTLGNzY3XAF3MoyU+nbYqM0PNRCgujYUV+PW3AR2J4UxQviKuyrCAaO 0cbrds7Qw8bxSwGHRz3F2NbkHc0D9gNjkNBFSCvo+8ttxw==
78A5DP9D1TN3VTQRVL40V82OTKSFKVFP.com. 86400 IN NSEC3 1 1 0 - 78A5S0E2MBIKEB8RG0QO9ULGBOQQFBCP NS DS RRSIG
78A5DP9D1TN3VTQRVL40V82OTKSFKVFP.com. 86400 IN RRSIG NSEC3 8 2 86400 20230903045253 20230827034253 4459 com. SSMkDi+YTY/Wn+VrjbfCEMpxTFYflgCbMI/lxhf1UqqiN7kB5BWpf7uR +A0nrovj5mVwKF5b4BN/CzpEfey02Amt0xuXq+XCoecVUtWHNFxJ6Pre IK4v4TnPVKR7qNWw/t295rXiENoc1vRtpPYAGokXc6wFa41+fYZsmg+S 2inELesbkFAQYpXCpLUYk0Mn4J0FbC21gzooRCvlluJByA==
;; Received 914 bytes from 192.43.172.30#53(i.gtld-servers.net) in 170 ms

keetmalin.medium.com. 300 IN A 162.159.152.4
keetmalin.medium.com. 300 IN A 162.159.153.4
;; Received 81 bytes from 173.245.58.61#53(alina.ns.cloudflare.com) in 176 ms
  • Your DNS recursive resolver is 172.20.10.1 and it knows a set of root-servers. And it queries from e.root-servers.net .
.   2745 IN NS a.root-servers.net.
. 2745 IN NS c.root-servers.net.
. 2745 IN NS j.root-servers.net.
. 2745 IN NS m.root-servers.net.
. 2745 IN NS g.root-servers.net.
. 2745 IN NS e.root-servers.net.
. 2745 IN NS d.root-servers.net.
. 2745 IN NS h.root-servers.net.
. 2745 IN NS l.root-servers.net.
. 2745 IN NS i.root-servers.net.
. 2745 IN NS b.root-servers.net.
. 2745 IN NS f.root-servers.net.
. 2745 IN NS k.root-servers.net.
;; Received 239 bytes from 172.20.10.1#53(172.20.10.1) in 42 ms
  • Your DNS root nameserver is e.root-servers.net. Since our initial query hostname ended with .com , this root server will direct your resolver to the .com TLD nameservers. In this case it i.gtld-servers.net.
com.   172800 IN NS e.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS d.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
com. 172800 IN NS f.gtld-servers.net.
com. 172800 IN NS j.gtld-servers.net.
com. 172800 IN NS k.gtld-servers.net.
com. 172800 IN NS c.gtld-servers.net.
com. 172800 IN NS g.gtld-servers.net.
com. 172800 IN NS h.gtld-servers.net.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS m.gtld-servers.net.
com. 86400 IN DS 30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com. 86400 IN RRSIG DS 8 1 86400 20230909050000 20230827040000 11019 . Jg5GfQXXzS37hg6eMjYtwr4Sq7L7ojgJS2bsLN8/zxv8K3i+R4Lj8v9j nfUT5v2MImm1rel0y0NLfNMGuJhawllnCWrgYoGPbm6+lZugixjLkm/7 XWcR4/vXDwBDChPp7+wBH5K97yk+b8NraN4/F/J5Xf+PuJKdoKLH5pSn vxkt1pf25fqvfAhiofiJRvrZ6ayVJf0p5svBArSgDvB+YdbV/x6AA5PD d7tkNNR4QCGLAtzj5hRKe5UJUTsFmXuohlNEnSo+tPUboNAhWNfGEXez JgCkZjfFQOB4UlnYcwAit4ocWYj19o3Voa5iUXg4FCQnXoZ0ETdxMLQ9 X6pduA==
;; Received 1180 bytes from 192.203.230.10#53(e.root-servers.net) in 182 ms
  • Your TLD nameserver is i.gtld-servers.net . This server knows where the medium.com domain (which is the domain for the subdomain keetmalin.medium.com) resides. There are two locations and it picks alina.ns.cloudflare.com, which is an authoritative nameserver.
medium.com.  172800 IN NS kip.ns.cloudflare.com.
medium.com. 172800 IN NS alina.ns.cloudflare.com.
...
;; Received 914 bytes from 192.43.172.30#53(i.gtld-servers.net) in 170 ms
  • Your Authoritative nameserver is alina.ns.cloudflare.com . And this returns 2 A records, pointing to 2 server IPs. 162.159.152.4 and 162.159.153.4.

If you run the dig command again, you will be able to see that the selected nameservers at each step are different. At each step, since there are multiple nameservers the DNS resolver decides which one to use.

Reverse DNS lookup

This is helpful when you have the IP address and would like to know the domains or subdomains associated with it. For this to work, the network admins of that website should have set up the PTR Records to allow reverse lookups.

As an example, let’s look at sb-in-f101.1e100.net and let’s find the IP of this hostname.

➜  ~ dig sb-in-f101.1e100.net +nocomment +nostat
...
sb-in-f101.1e100.net. 2158 IN A 74.125.130.101

If we take this IP and do a reverse lookup, it should have a PTR record pointing to the above hostname.

➜  ~ dig -x 74.125.130.101 +nocomment +nostat
...
101.130.125.74.in-addr.arpa. 4502 IN PTR sb-in-f101.1e100.net.

In the above example, the reverse lookup status was NOERROR since there was a PTR Record in place. But let’s look at the following IP of keetmalin.medium.com which does not have a PTR.

➜  ~ dig keetmalin.medium.com +nocomment +nostat
...
keetmalin.medium.com. 377 IN A 162.159.152.4
keetmalin.medium.com. 377 IN A 162.159.153.4
➜  ~ dig -x 162.159.153.4
...
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 45635
...

Here you can clearly see that the status is NXDOMAIN , and this is because the PTR record is not in place for this host.

--

--