A Simple Guide to DNS and Privacy
DNS translates domain names into IP addresses, but its unencrypted queries can expose your browsing habits. Learn how DNS works, what data is exposed in plaintext, and why it matters for your privacy — with hands-on examples.
Introduction to The DNS series
As constant user monitoring becomes more common, it's important for users to take steps to protect their privacy while browsing the web. This series focuses on the Domain Name System (DNS), which is essential for internet communication by converting domain names into IP addresses. However, DNS queries can pose significant privacy and security risks, as they can be intercepted and monitored, revealing sensitive information about your online activities.
To address these concerns, we will explore advanced DNS technologies such as DNS over TLS (DoT), DNS over HTTPS (DoH), and DNSSEC. Through hands-on examples and practical scenarios, you'll learn how to implement these technologies to boost your privacy and security, reducing the risks associated with DNS query monitoring and surveillance.
How DNS Works: A Step-by-Step Breakdown
Almost every activity on the Internet starts with a DNS query (and often several). Think of DNS as the internet’s phonebook—just as you look up a contact’s name to find their phone number, DNS helps your browser find the correct server by converting a website’s name into an IP address. Every device connected to the internet has a unique IP address, which allows other machines to locate and communicate with it. Without DNS, we would need to remember numerical addresses like 96.7.128.175 (IPv4) or even longer, more complex IPv6 addresses like 2600:1408:ec00:36::1736:7f24 instead of simply typing example.com.
When you enter a website’s name into your browser, a series of steps happen behind the scenes to resolve the domain name into an IP address:
- DNS Query: Your device sends a query to a DNS resolver, which acts as a middleman between your device and the DNS nameserver. Most internet users use a resolver provided by their Internet Service Provider (ISP), but there are alternative options available.
- Resolver Lookup: The resolver checks its cache for the domain's IP address.
- Recursive Resolution: If the IP address isn't found in the cache, the resolver queries other DNS servers, starting with the root servers. These servers direct the resolver to a top-level domain (TLD) nameserver based on the domain extension (e.g., .com, .net, .org). The resolver then follows the hierarchy down to locate the authoritative DNS server for the domain.
- Response: The authoritative DNS server responds with the IP address, which is then relayed back to the original device.
Once the IP of example.com is received, browser will attempt to connect to that remote server using the IP it got from the DNS resolver.
While there are additional complexities, these are the fundamental concepts we need to understand at this stage. For a more comprehensive exploration, refer to Clouflares learning material.
Hands-On Example: Tracing a DNS Query
Now that we have a basic understanding of DNS, let's explore a real example to see what happens when we query a webpage.
We'll use the dig command on Linux (or WSL/VM on Windows), and see how yahoo.com is resolved. To get a detailed view of all the queries sent to different servers, we'll use the +trace option. Install dig (if needed):
sudo apt install dnsutils
Open a terminal and enter the following command
dig yahoo.com +trace
The output will likely be extensive, so we will break it down and explain each part. The first step in the DNS resolution process involves querying the root DNS servers. The initial block of the output shows the response from the local DNS resolver (in this case, 127.0.0.53, commonly used by systemd-resolved on Linux systems) regarding the root DNS servers.
; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> yahoo.com +trace
;; global options: +cmd
. 87203 IN NS m.root-servers.net.
. 87203 IN NS d.root-servers.net.
...
. 87203 IN NS e.root-servers.net.
;; Received 239 bytes from 127.0.0.53#53(127.0.0.53) in 21 ms
The output of the root DNS servers has several parameters, these have the follwoing meaning:
| Field | Meaning |
|---|---|
. |
Specifies the domain or subdomain for which the DNS record provides information. In this case the root domain. |
87203 |
The Time-to-Live (TTL) value in seconds. It indicates how long this record should be cached before it is refreshed. In this case, it's approximately 24 hours. |
IN |
Stands for "Internet." It specifies the class of the DNS record, indicating that this record is used on the Internet. |
NS |
Stands for "Name Server." It specifies that the following domain is an authoritative name server for the root domain. |
m.root-servers.net. |
The domain name of one of the root name servers. This server can provide information about the top-level domains (TLDs) like .com |
Next, our resolver queries the root DNS server, which it obtained from the local resolver, to receive the addresses of the TLD (Top-Level Domain) servers for the .com domain.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
...
com. 172800 IN NS k.gtld-servers.net.
;; Received 1169 bytes from 202.12.27.33#53(m.root-servers.net) in 278 ms
There are additional fields in the output, such as the DS Record and RRSIG Record, which are relevant to DNSSEC. We will not cover these fields at this time but will explore them in a future discussion on DNSSEC.)
The next step is querying the TLD servers for .com. The TLD servers respond with the addresses of the authoritative name servers for yahoo.com.
yahoo.com. 172800 IN NS ns1.yahoo.com.
...
yahoo.com. 172800 IN NS ns4.yahoo.com.
;; Received 677 bytes from 192.43.172.30#53(i.gtld-servers.net) in 46 ms
Finally, the query reaches the authoritative name servers for yahoo.com. The authoritative name servers respond with the IP addresses associated with yahoo.com.
yahoo.com. 1800 IN A 74.6.231.20
yahoo.com. 1800 IN A 74.6.143.25
yahoo.com. 1800 IN A 98.137.11.163
yahoo.com. 1800 IN A 98.137.11.164
yahoo.com. 1800 IN A 74.6.143.26
yahoo.com. 1800 IN A 74.6.231.21
;; Received 444 bytes from 68.180.131.16#53(ns1.yahoo.com) in 10 ms
| Filed | Meaning |
|---|---|
A |
Stands for "Address." It specifies that this record maps a domain name to an IPv4 address. |
And that's it, quite a long chain of requests and responses! This process happens every time you load a webpage, for every hostname involved.
The Privacy Problem: Unencrypted DNS Queries
DNS wasn't designed with security in mind, making it vulnerable to various attacks. Since it mostly operates over unencrypted UDP or TCP on port 53 by default, attackers can intercept, manipulate, or spoof DNS queries. This also raises significant privacy and security concerns, as unencrypted DNS traffic can be:
- Monitored: ISPs, governments, and attackers can see which domains you access. Some ISPs log DNS queries at the resolver and share this information with third-parties in ways not known or obvious to end users. They might even embed user information (like a user ID or MAC address) within DNS queries for fingerprinting individual users..
- Hijacked: Attackers can intercept DNS queries and return fake IP addresses (DNS spoofing or man-in-the-middle (MITM) attacks).
- Used for tracking: Advertisers and data brokers can log your browsing habits.
To address these risks, modern solutions such as DNS over HTTPS (DoH) and DNS over TLS (DoT) encrypt DNS queries to prevent unauthorized interception.
Hands on Example: What’s Actually Being Sent?
Let’s go deeper and capture the actual DNS packets flying across your network.
Step 1: Install Tools
For this example we will need to install additional tools:
tcpdump: A powerful command-line packet analyzer (man pages).tshark: A network traffic analyzer.
sudo apt -y install tcpdump tshark
Step 2: Start DNS Traffic Capture
Start packet capture on port 53. The -i option specifies the interface (like your wired ethernet or WiFi adapter), the -n tells the tool not to convert IP addresses to names, and -w will write the raw packets to file. The port 53 is a capture filter, so it only captures packets if the source or destination port is 53.
sudo tcpdump -i any -n port 53 -w capture.pcap
We could make sure that no other application uses internet, to make the capture much easier to analyze later!
Step 3: Query a DNS Server
Open up a new terminal and run dig command. Let's use Google as our DNS Resolver, the @ defines the server dig will query.
dig @8.8.8.8 yahoo.com
Step 4: Analyze the Capture
Stop packet capture and display the results with tshark. We could also use Wireshark to graphically view the packets, but lets stick to the simple method for now.
$ tshark -r capture.pcap
1 0.000000 127.0.0.1 → 127.0.0.53 DNS 98 Standard query 0x5917 A yahoo.com OPT
2 0.000277 192.168.1.17 → 8.8.8.8 DNS 86 Standard query 0x112c A yahoo.com OPT
3 0.004699 8.8.8.8 → 192.168.1.17 DNS 182 Standard query response 0x112c A yahoo.com A 98.137.11.163 A 74.6.231.20 A 74.6.143.26 A 74.6.231.21 A 98.137.11.164 A 74.6.143.25 OPT
4 0.004892 127.0.0.53 → 127.0.0.1 DNS 182 Standard query response 0x5917 A yahoo.com A 98.137.11.163 A 74.6.231.20 A 74.6.143.26 A 74.6.231.21 A 98.137.11.164 A 74.6.143.25 OPT
In this example, our device queried systemd-resolved at 127.0.0.53 for yahoo.com. Our device, 192.168.1.17, then asked Google DNS for yahoo.com. Unlike the previous example, we only observe the request to the recursive resolver and do not see the subsequent interactions. As before, Google returns us the IP aadress.
From this, it's clear which website we visited. On a larger scale, this data can lead to user profiling, monitoring, and censorship.
What’s Next?
By default, most devices use their ISP’s DNS servers, but not all resolvers are equal. Some prioritize speed, while others focus on privacy and security.
In the next post, we’ll dive into public DNS resolvers, how to choose one that respects your privacy and why switching from your ISP’s default resolver matters.
How to Find the Memory Address of a Symbol in an ELF File
A quick and useful tip for locating symbol memory addresses in ELF files using arm-none-eabi-nm combined with grep—perfect for embedded debugging scenarios like setting up SEGGER RTT or inspecting linker placements and runtime symbols.
How to Move RTT to a Custom RAM Section in Embedded Rust
Learn how to place RTT buffers and the control block into a fixed RAM section in embedded Rust. This guide covers linker script changes, custom RTT initialization, and setting up a reliable RTT print channel.
Automating OpenOCD Distribution with a Private Gitea Package Registry
Turn your OpenOCD updates from a manual chore into a one-click process. Learn how to set up a private Gitea Package Registry, upload .deb files, and install them effortlessly on any Debian-based machine. Automation made simple.
Whether you're building something new, fixing stability issues, or automating what slows your team down — we can help.