A Short Practical Tutorial of dig, DNS and DNSSEC

December 13, 2018

Introduction

dig is a DNS lookup utility, and a flexible tool for interrogating DNS name servers. (dig manual page)

I would like to show in this post, how DNS and DNSSEC basically works, using dig. It is from a user point of view, I am not going to talk about things like DNS Zone Transfer (AXFR), DNS NOTIFY or DNS UPDATE. I will use dig in this post, so it is also going to be a very brief tutorial of dig as well.

I will not explain the details of DNSSEC in this post, as I am already writing another one for that.

The reference for all information in this post are DNS and DNSSEC related RFCs and the manual page of dig.

Domain Name System (DNS)

Many many years ago, before DNS, all the information, like name to address mappings, was kept in a single file that have been shared with all the computers connected to the Internet (ARPANET). As you might guess, this became quickly unmaintainable. DNS is the solution to this problem.

DNS has three major components:

  • Domain Name Space and Resource Records
  • Name Servers
  • Resolvers

Domain Name Space

Domain Name Space is a (distributed) tree data structure, or in other words, an hierarchical distributed database. Each node in this tree has a label. The root node has an empty label, and no other label can be empty. A label can only contain ASCII letters A-Z, digits 0-9, and hyphen -. Labels are case-insensitive.

The domain name of a node in the Domain Name Space, by convention, is the list of labels, of the label of this node and the labels of its parents going upwards, reading from left to right in the same way. When a domain name need to be presented to user or read from a user input, the labels are joined by a dot.

Domain Name Space for metebalci.com:

digraph g {
  node[style=filled, shape=box]
  root[label="<empty label>"]
  com[label="com"]
  metebalci[label="metebalci"]
  root -> com
  com -> metebalci
}

Below each node contains the domain name (not the label) of each node:

digraph g {
  node[style=filled, shape=box]
  root[label=""]
  com[label="com."]
  metebalci[label="metebalci.com."]
  root -> com
  com -> metebalci
}

Each node in the Domain Name Space can keep information in the form of resource record sets containing resource records.

Resource Record (RR)

A resource record (RR) has five components:

  • owner: of this record. It is the domain name of the node which keeps this information.
  • type: a 16-bit value, specifying what this resource record is about
  • class: a 16-bit value, identifying a protocol
  • TTL: a 32-bit Time-To-Live value, in units of seconds, indicating how long this resource record can be cached
  • rdata: data of the resource

A real example is:

metebalci.com. 300 IN A 151.101.1.195
metebalci.com. 300 IN A 151.101.65.195

This RR has:

  • owner: metebalci.com.
  • TTL: 300 (seconds)
  • type: A (Address)
  • class: IN (Internet)
  • rdata: 151.101.1.195 and other record is 151.101.65.195

These two records form a resource record set (RRset). All resource records in a resource record set has the same name, type and class.

There are very few classes, and the important ones are IN (Internet) and ANY (used only in queries).

There are many types, a few important ones are:

  • SOA: Start of (a zone of) Authority, identifies the start of a zone
  • NS: DNS server responsible (authoritative) for a zone
  • A: IPv4 host address
  • AAAA: IPv6 host address

The contents of the resource data (rdata) depends on the resource type. As seen above, for a resource type=A, rdata contains an IPv4 address.

Name Servers

Name servers are server programs, which hold partial information about the Domain Name Space. Since the Domain Name Space is a distributed database, each name server may have complete and authoritive information only about a small part of the Domain Name Space, and possibly cache some other data in the Domain Name Space.

Resolvers

Resolvers are user programs, which are used to send queries to name servers, thus extract information from the Domain Name Space.

Iterative vs. Recursive Queries

Because DNS is a distributed database, and a name server has only partial information, there are two ways to extract information:

  • Iterative approach: where the resolver/client repeatedly queries different servers until it finds the answer
  • Recursive approach: where the resolver/client sends the query only to a single server, but the server repeatedly queries different servers until it finds and returns the answer to the resolver

I think it is now common to use the recursive approach. For example, you use a public DNS like Google’s, and it always return the answer if there is any.

DNS Protocol

The ascii diagrams in this section are taken from RFC 1035.

A resolver (user program, such as dig) sends a query to a name server, and server returns a response. This is called a DNS lookup, since the purpose of the query is looking up for a specific information stored as a resource record.

By default, DNS lookups are done over UDP at port number 53. It is assumed that a query and a response fits into a single UDP datagram. It is usually not a problem for a query, but the responses can be large. If this happens, DNS lookup can be retried over TCP.

DNS message always has the same format, it does not matter if it is a query or response. Its structure is:

+------------+
| Header     | 
+------------+
| Question   | the question for the name server
+------------+
| Answer     | RRs answering the question
+------------+
| Authority  | RRs pointing toward an authority
+------------+
| Additional | RRs holding additional information
+------------+
  • A fixed length Header, containing an ID, flags, information about the other sections
  • Question section contains query domain name (QNAME), query type (QTYPE) and query class (QCLASS). Response contains the same Question section as the Question.
  • Answer section may contain a list of resource records, each containing QNAME, QTYPE, QCLASS, TTL, the length of RDATA and RDATA
  • Authority section may contain a list of resource records, pointing to authoritative name servers
  • Additional section may contain a list of resource records, that may contain additional information to answers.

and the details of the Header section is:

  1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

ID is an 16-bit value, that is kept same in the response. Because UDP is connectionless, this is needed.

Flags:

  • QR: 0=Query, 1=response
  • OPCODE: 0000=query
  • AA: Authoritative Answer (set by the server)
  • TC: message is TrunCated (set by the server)
  • RD: Recursion Desired (set by the client and copied to the response)
  • RA: Recursion Available (set by the server)
  • AD: Authenticated Data, DNSSEC flag (set by the server)
  • CD: Checking Disabled, DNSSEC flag (set by the client, copied to the response)
  • RCODE, 4-bits: 0000=NOERROR.

Each count field (QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT) shows the number of records in each section.

dig

The information above will be very helpful to understand the output of dig.

dig supports many options and a few arguments, but there is a default for everthing. So the most simple usage is without any arguments and options:

$ dig

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32684
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;.				IN	NS

;; ANSWER SECTION:
.			516341	IN	NS	m.root-servers.net.
.			516341	IN	NS	b.root-servers.net.
.			516341	IN	NS	c.root-servers.net.
.			516341	IN	NS	d.root-servers.net.
.			516341	IN	NS	e.root-servers.net.
.			516341	IN	NS	f.root-servers.net.
.			516341	IN	NS	g.root-servers.net.
.			516341	IN	NS	h.root-servers.net.
.			516341	IN	NS	i.root-servers.net.
.			516341	IN	NS	a.root-servers.net.
.			516341	IN	NS	j.root-servers.net.
.			516341	IN	NS	k.root-servers.net.
.			516341	IN	NS	l.root-servers.net.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Dec 07 13:21:37 CET 2018
;; MSG SIZE  rcvd: 239

The default values above:

  • default QNAME=.(root domain), QTYPE=NS, default QCLASS=IN
  • default name server that the query has been sent to is the system default name server (e.g. Linux /etc/resolv.conf)
  • you only see the answer, query is hidden by default

Keep in mind that the default QTYPE=NS is used only for the root domain, if you specify a domain name, then the default QTYPE is A.

Recursive Query

Lets specify all these defaults explicitly, enable displaying the query +qr and ask for a specific domain name metebalci.com:

$ dig @8.8.8.8 metebalci.com IN A +qr

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 metebalci.com IN A +qr
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37069
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 5f798fcd227baee1
;; QUESTION SECTION:
;metebalci.com.			IN	A

;; QUERY SIZE: 54

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37069
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
metebalci.com.		299	IN	A	151.101.1.195
metebalci.com.		299	IN	A	151.101.65.195

;; Query time: 33 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 13:28:03 CET 2018
;; MSG SIZE  rcvd: 74

It displayed the query first, then the answer.

The defaults above are:

  • By default, rd (recursion desired) and ad (authenticated data) are set.
  • By default, EDNS (Extension mechanisms for DNS) is used, and the default EDNS version is set to 0 (also called EDNS0). EDNS is a mechanism to be able to add extra information to a DNS message, since the header is fixed, nothing can be added there. EDNS defines a pseudo-resource record (pseudo-RR) (it is called pseudo because it is actually not a resource record like others) called OPT.
    • The OPT pseudo-RR above sets the largest UDP payload sender can support. OPT pseudo-RR also extends the RCODE in the Header from 4-bits to 12-bits by carrying 8-bits in the OPT pseudo-RR. OPT pseudo-RR is carried in the Additional section.
    • Another option of EDNS is DNS COOKIE Option, that you can also see in the dig output. Client cookie is generated randomly from client IP, server IP and a minimum 64-bit secret only known to client. Client cookie is always 8-bytes. Server cookie is generated randomly from client IP, a secret known only to server and the client cookie. Server cookie is minimum 8-bytes, maximum 32-bytes. DNS cookies are used to provide some protection against certain attacks. Cookie is added before, because +cookie option is added by default, if you specify +nocookie, this is not sent. Google Public DNS (8.8.8.8) does not respond with a server cookie.

You can see in the answer, four flags are set: qr, rd, ra, ad.

  • QR is actually not a flag like others, if it is 0 (so not set), it is a query, here it is QR=1, so this is a response.
  • RD (recursive desired): set by the client, if the server is not authoritative, it will do a recursive query to find the answer.
  • RA (recursive available): set by the server, indicating recursive query is supported.
  • AD (authenticated data): set by the client to ask server to return the answer and authority sections only if all records are validated as secure. This is a DNSSEC feature.

Lets see the effect of Recursion Desired (RD) by not setting it with +nordflag:

$ dig @8.8.8.8 metebalci.com IN A +qr +nordflag

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 metebalci.com IN A +qr +nordflag
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59269
;; flags: ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 88c8ed8cc552cbd0
;; QUESTION SECTION:
;metebalci.com.			IN	A

;; QUERY SIZE: 54

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 59269
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

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

;; Query time: 11 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 13:48:46 CET 2018
;; MSG SIZE  rcvd: 42

Because Google’s Public DNS (8.8.8.8) is not authoritative for metebalci.com, if you do not ask for recursion, it basically returns nothing, actually SERVFAIL. Independent of RD is set or not, server replied with Recursion Available (RA).

Iterative Query

If you do not want to use recursive query, what can you do ? First, you should find the authoritative name server of the domain name. In order to do that, you can start from the root domain.

You saw above the root name servers, so you can ask the name servers of com to the root name servers:

$ dig @a.root-servers.net com NS +qr +nordflag
...

;; AUTHORITY SECTION:
com.			172800	IN	NS	e.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	a.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	k.gtld-servers.net.
com.			172800	IN	NS	c.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.

;; ADDITIONAL SECTION:
e.gtld-servers.net.	172800	IN	A	192.12.94.30
e.gtld-servers.net.	172800	IN	AAAA	2001:502:1ca1::30
b.gtld-servers.net.	172800	IN	A	192.33.14.30
b.gtld-servers.net.	172800	IN	AAAA	2001:503:231d::2:30
j.gtld-servers.net.	172800	IN	A	192.48.79.30
j.gtld-servers.net.	172800	IN	AAAA	2001:502:7094::30
m.gtld-servers.net.	172800	IN	A	192.55.83.30
m.gtld-servers.net.	172800	IN	AAAA	2001:501:b1f9::30
i.gtld-servers.net.	172800	IN	A	192.43.172.30
i.gtld-servers.net.	172800	IN	AAAA	2001:503:39c1::30
f.gtld-servers.net.	172800	IN	A	192.35.51.30
f.gtld-servers.net.	172800	IN	AAAA	2001:503:d414::30
a.gtld-servers.net.	172800	IN	A	192.5.6.30
a.gtld-servers.net.	172800	IN	AAAA	2001:503:a83e::2:30
g.gtld-servers.net.	172800	IN	A	192.42.93.30
g.gtld-servers.net.	172800	IN	AAAA	2001:503:eea3::30
h.gtld-servers.net.	172800	IN	A	192.54.112.30
h.gtld-servers.net.	172800	IN	AAAA	2001:502:8cc::30
l.gtld-servers.net.	172800	IN	A	192.41.162.30
l.gtld-servers.net.	172800	IN	AAAA	2001:500:d937::30
k.gtld-servers.net.	172800	IN	A	192.52.178.30
k.gtld-servers.net.	172800	IN	AAAA	2001:503:d2d::30
c.gtld-servers.net.	172800	IN	A	192.26.92.30
c.gtld-servers.net.	172800	IN	AAAA	2001:503:83eb::30
d.gtld-servers.net.	172800	IN	A	192.31.80.30
d.gtld-servers.net.	172800	IN	AAAA	2001:500:856e::30

...

This also shows a good use of Additional section. Since you need the IP addresses to query the name servers anyway, in order to avoid a second query, the IP addresses of the names servers are also returned in the Additional section. It was not queried (A records are not queried), so this is an additional information.

As you know the name servers of com, now you can ask for the nameservers of metebalci.com:

$ dig @a.gtld-servers.net metebalci.com NS +qr +nordflag
...

;; AUTHORITY SECTION:
metebalci.com.		172800	IN	NS	ns-cloud-b1.googledomains.com.
metebalci.com.		172800	IN	NS	ns-cloud-b2.googledomains.com.
metebalci.com.		172800	IN	NS	ns-cloud-b3.googledomains.com.
metebalci.com.		172800	IN	NS	ns-cloud-b4.googledomains.com.

;; ADDITIONAL SECTION:
ns-cloud-b1.googledomains.com. 172800 IN AAAA	2001:4860:4802:32::6b
ns-cloud-b1.googledomains.com. 172800 IN A	216.239.32.107
ns-cloud-b2.googledomains.com. 172800 IN AAAA	2001:4860:4802:34::6b
ns-cloud-b2.googledomains.com. 172800 IN A	216.239.34.107
ns-cloud-b3.googledomains.com. 172800 IN AAAA	2001:4860:4802:36::6b
ns-cloud-b3.googledomains.com. 172800 IN A	216.239.36.107
ns-cloud-b4.googledomains.com. 172800 IN AAAA	2001:4860:4802:38::6b
ns-cloud-b4.googledomains.com. 172800 IN A	216.239.38.107

...

Now you know the authoritative name servers of metebalci.com. You can ask other resource records (like A):

$ dig @ns-cloud-b1.googledomains.com metebalci.com A +qr +nordflag
...

;; ANSWER SECTION:
metebalci.com.		300	IN	A	151.101.1.195
metebalci.com.		300	IN	A	151.101.65.195

...

DNSSEC Checking Disabled (CD) and Authenticated Data (AD) Flags

You can see an example of Checking Disabled (CD) and Authenticated Data (AD) with a domain specifically configured with wrong DNSSEC signatures, that is dnssec-failed.org.

$ dig @8.8.8.8 www.dnssec-failed.org

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 www.dnssec-failed.org +qr
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51067
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 97d64f27b6c7173b
;; QUESTION SECTION:
;www.dnssec-failed.org.		IN	A

;; QUERY SIZE: 62

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 51067
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.dnssec-failed.org.		IN	A

;; Query time: 204 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 14:01:57 CET 2018
;; MSG SIZE  rcvd: 50

Because the records that would be returned by this query cannot be validated, it returns no records. In order to get the records even if validation fails, you need to use Checking Disabled (CD) bit:

$ dig @8.8.8.8 www.dnssec-failed.org +qr +cdflag

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 www.dnssec-failed.org +qr +cdflag
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20866
;; flags: rd ad cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 5290b2efedb75b2c
;; QUESTION SECTION:
;www.dnssec-failed.org.		IN	A

;; QUERY SIZE: 62

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20866
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.dnssec-failed.org.		IN	A

;; ANSWER SECTION:
www.dnssec-failed.org.	7199	IN	A	68.87.109.242
www.dnssec-failed.org.	7199	IN	A	69.252.193.191

;; Query time: 120 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 14:04:31 CET 2018
;; MSG SIZE  rcvd: 82

With CD set, you receive the records, but pay attention to flags in the answer, there is no Authenticated Data (AD). This indicates that there is a validation problem with one or more records returned.

DNSSEC Resource Records

DNSSEC defines four new record types:

  • DNSKEY: keeps the public key to verify RRSIGs
  • DS: keeps the digest of a DNSKEY RR
  • RRSIG: keeps the digital signature of an RRset
  • NSEC: used for authenticated denial existence, meaning to show an RRset is not part of a signed zone

As you see above, metebalci.com IN A query did return only A records. If you want to get RRSIG record for the A RRset, you have to use +dnssec option:

$ dig @8.8.8.8 metebalci.com +qr +dnssec

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 metebalci.com +qr +dnssec
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37727
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
; COOKIE: a263795b817be1b1
;; QUESTION SECTION:
;metebalci.com.			IN	A

;; QUERY SIZE: 54

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37727
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;metebalci.com.			IN	A

;; ANSWER SECTION:
metebalci.com.		299	IN	A	151.101.1.195
metebalci.com.		299	IN	A	151.101.65.195
metebalci.com.		299	IN	RRSIG	A 8 2 300 20181227144044 20181205144044 59764 metebalci.com. z6FupNLEU/8OcB3rNMkVqVaan05Xu89T8hV6+IC7LGjWPtrD+TlNJd8D cGeq8xJLR8b1Q+gBK0QSxpGvk89GaCTjNtMGHLBBdgpyV4syFv2BNzK7 iAJhA8QJ6i5xVFJdzMSsn3WvQvN1W71sirt8+56r1nQ47aVkBSLJoZKP lgw=

;; Query time: 41 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 14:09:43 CET 2018
;; MSG SIZE  rcvd: 247

As you see, now it returns two A records, and an RRSIG record associated with this RRset. There is an RRSIG for each RRset, not for individual RRs, that is why you have only one RRSIG above.

You might have noticed, in the OPT section, there is a difference after using +dnssec, it shows flags: do. do means DNSSEC OK, meaning the resolver supports DNSSEC, indicating to the server that it should return DNSSEC record types as well. That is why you received now the RRSIG record.

You can also query DNSKEY records:

$ dig @8.8.8.8 metebalci.com DNSKEY +qr

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 metebalci.com DNSKEY +qr
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41000
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 1cbc06703eaef210
;; QUESTION SECTION:
;metebalci.com.			IN	DNSKEY

;; QUERY SIZE: 54

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41000
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;metebalci.com.			IN	DNSKEY

;; ANSWER SECTION:
metebalci.com.		299	IN	DNSKEY	256 3 8 AwEAAfHph+LlPW5tn2zrQ/ka0OUjZGm+S84N+vJxkJ4WT7uBhK87c+bS HR35Bfq3hxjEGAe+qIbTrUQVIWrIVfZjKbD/2gh9CsDlOa3na2tv1QVC cguj0VUQp4dsFubpQXr3nvf2hV8bNO9AOO2adS/SMYuRcQNpyvBAMINL KxtKrTSx
metebalci.com.		299	IN	DNSKEY	257 3 8 AwEAAY9y/KiOTaMf0EqtlfC0PgMxladfiA9NpLtsECO7wk7Br7WkOnib s/qNExkPLAHktgyguhSKcWcAsueh61j1phkGzAh9Y/LtIe8oyf+PhL/q kl0TIjcZpdLVsWOX3bEGNFADosVKEe8QTDyb0z093CSe83Ho5HKryi9T OiVL145CPF7YxtPpm7UcfUtX0XQEDHYUhH64S77Pp64ebVvxjeIaY9wT 8vv3G+zxaL0V+EVCDGr3WlWU/H5ypHVD3D4gIOQRBlJKTxg4Ov9N2t/E O7xVMdbsxrHNDyafNbtQ4v+9GRV8dMkPSRv1QZudwdlbB+XpmQhb6s0G VQR4B3FWH20=

;; Query time: 23 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 14:13:21 CET 2018
;; MSG SIZE  rcvd: 466

and DS records:

$ dig @8.8.8.8 metebalci.com DS +qr

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> @8.8.8.8 metebalci.com DS +qr
; (1 server found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39831
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: b5dafd2648fa583b
;; QUESTION SECTION:
;metebalci.com.			IN	DS

;; QUERY SIZE: 54

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39831
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;metebalci.com.			IN	DS

;; ANSWER SECTION:
metebalci.com.		86399	IN	DS	48260 8 2 9BB9359BFCE4EF3EAC96F6E131D03665C274B47A7F0B2BB45A49AFCF 8F3A2F83

;; Query time: 29 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Dec 07 14:13:44 CET 2018
;; MSG SIZE  rcvd: 90

I am going to explain what these records contain and how they are used to validate an RRset in another post. Stay tuned!