Skip to main content
โšก Calmops

DNS Deep Dive: Resolution, Records, and Security

The Domain Name System (DNS) is often called the phonebook of the internet. It translates human-readable domain names into IP addresses that computers use to identify each other. Understanding DNS is essential for network engineers, developers, and anyone building internet-facing applications.

In this guide, we’ll explore how DNS works, the various record types, resolution processes, and security best practices.

How DNS Works

The Problem DNS Solves

# Without DNS, you'd need to remember:
ip_addresses = {
    "google": "142.250.185.14",
    "facebook": "157.240.221.35",
    "amazon": "18.164.174.19",
    # ... millions of addresses
}

# With DNS, just use:
domain = "google.com"  # Much easier to remember!

DNS Hierarchy

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    DNS Hierarchy                             โ”‚
โ”‚                                                             โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚   โ”‚                    Root Zone (.)                     โ”‚  โ”‚
โ”‚   โ”‚                 "." nameservers                       โ”‚  โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                           โ”‚                                  โ”‚
โ”‚       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”‚
โ”‚       โ–ผ                   โ–ผ                   โ–ผ              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚  โ”‚   .com  โ”‚        โ”‚   .org โ”‚        โ”‚   .net โ”‚          โ”‚
โ”‚  โ”‚    TLD  โ”‚        โ”‚   TLD  โ”‚        โ”‚   TLD  โ”‚          โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜        โ”‚
โ”‚       โ”‚                  โ”‚                   โ”‚               โ”‚
โ”‚       โ–ผ                  โ–ผ                   โ–ผ               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚              Authoritative Nameservers                โ”‚   โ”‚
โ”‚  โ”‚                                                        โ”‚   โ”‚
โ”‚  โ”‚  ns1.example.com    ns2.example.com    ns3.example.comโ”‚   โ”‚
โ”‚  โ”‚  (Your domain's DNS)                                  โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

DNS Resolution Process

# Step-by-step DNS resolution

resolution_steps = """
1. Client queries local resolver (ISP or local)

2. Local resolver checks cache
   - If cached: return result
   - If not: continue to root

3. Query Root Nameserver (.)
   - Returns: .com TLD nameserver addresses

4. Query .com TLD Nameserver
   - Returns: authoritative nameserver for example.com

5. Query Authoritative Nameserver for example.com
   - Returns: 93.184.216.34 (A record)

6. Return result to client
   - Cache the result for future requests
"""

DNS Query Types

# Iterative Query (most common)
# Resolver asks each server for the next step

iterative_query = """
Client โ†’ Local Resolver โ†’ Root Server (.com NS)
                โ†’ TLD Server (example.com NS)
                โ†’ Authoritative (93.184.216.34)
                โ†’ Client
"""

# Recursive Query
# Server does all the work

recursive_query = """
Client โ†’ Local Resolver (does all lookups)
                โ†’ Root โ†’ TLD โ†’ Auth โ†’ TLD โ†’ Root โ†’ Client
"""

# Both return the same result, but recursion
# is handled by the resolver

DNS Records

A and AAAA Records

# A Record - IPv4 Address
# Maps domain to IPv4 address

example.com.    IN A     93.184.216.34
www.example.com. IN A    93.184.216.34

# AAAA Record - IPv6 Address
# Maps domain to IPv6 address

example.com.    IN AAAA  2606:2800:220:1:248:1893:25c8:1946
www.example.com. IN AAAA 2606:2800:220:1:248:1893:25c8:1946

CNAME Record

# CNAME - Canonical Name (alias)
# Points one domain to another

blog.example.com.   IN CNAME   www.example.com.
shop.example.com.   IN CNAME   shops.shopify.com.
cdn.example.com.   IN CNAME   example.cloudfront.net.

# Good: blog -> www -> actual server
# CNAME chains are resolved at query time

MX Record

# MX Record - Mail Exchange
# Specifies mail servers for domain

example.com.    IN MX     10 mail1.example.com.
example.com.    IN MX     20 mail2.example.com.
example.com.    IN MX     30 mail.backup-provider.com.

# Priority: Lower number = higher priority
# Client tries 10 first, then 20, then 30

TXT Record

# TXT Record - Arbitrary text
# Used for verification, SPF, DKIM, DMARC

# SPF - Sender Policy Framework
example.com.    IN TXT    "v=spf1 include:_spf.google.com ~all"

# DKIM - DomainKeys Identified Mail
selector._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjAN..."

# DMARC - Domain-based Message Authentication
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"

# Google verification
google-site-verification.example.com. IN TXT "google-site-verification=abc123"

NS Record

# NS Record - Nameserver
# Delegates domain to nameservers

example.com.    IN NS     ns1.example.com.
example.com.    IN NS     ns2.example.com.
example.com.    IN NS     ns3.example.com.

SOA Record

# SOA Record - Start of Authority
# Contains admin info and timing

example.com.    IN SOA    ns1.example.com. admin.example.com. (
                        2025022101 ; Serial (YYYYMMDDNN)
                        3600       ; Refresh (1 hour)
                        1800       ; Retry (30 minutes)
                        604800     ; Expire (1 week)
                        86400 )    ; Minimum TTL (1 day)

Other Important Records

# PTR Record - Pointer Record (Reverse DNS)
# Maps IP to domain name

34.216.184.93.in-addr.arpa. IN PTR example.com.

# SRV Record - Service Location
# Defines location of services

_http._tcp.example.com. IN SRV 10 5 80 www.example.com.

# CAA Record - Certification Authority Authorization
# Specifies allowed CAs

example.com.    IN CAA    0 issue "letsencrypt.org"
example.com.    IN CAA    0 iodef "mailto:[email protected]"

# DNS TTL (Time To Live)
# How long to cache the record

example.com.    IN A      93.184.216.34
                3600     ; TTL (1 hour in seconds)

DNS Tools and Commands

dig Command

# Basic lookup
dig example.com

# Specific record type
dig A example.com
dig AAAA example.com
dig MX example.com
dig TXT example.com
dig NS example.com

# Query specific nameserver
dig @8.8.8.8 example.com A

# Reverse DNS lookup
dig -x 93.184.216.34

# Trace resolution path
dig +trace example.com

# Short output
dig +short example.com

# Show TTL values
dig +noall +answer example.com

nslookup

# Basic lookup
nslookup example.com

# Specific record type
nslookup -type=MX example.com

# Query specific server
nslookup example.com 8.8.8.8

# Reverse lookup
nslookup 93.184.216.34

whois

# Domain registration info
whois example.com

# Detailed output
whois -h whois.verisign.com example.com

Python DNS Examples

import dns.resolver
import dns.query
import dns.zone
import dns.name

# Basic DNS lookup
resolver = dns.resolver.Resolver()

# Resolve A record
answers = resolver.resolve('example.com', 'A')
for rdata in answers:
    print(f"A record: {rdata}")

# Resolve MX records
answers = resolver.resolve('example.com', 'MX')
for rdata in answers:
    print(f"MX: {rdata.preference} {rdata.exchange}")

# Reverse DNS lookup
ip = dns.reversename.from_address('93.184.216.34')
answers = resolver.resolve(ip, 'PTR')
print(f"PTR: {answers[0]}")

# Custom nameserver
resolver = dns.resolver.Resolver()
resolver.nameservers = ['8.8.8.8', '8.8.4.4']  # Google DNS
answers = resolver.resolve('example.com', 'A')

# DNSSEC validation
import dns.resolver
import dns.flags

def validate_dnssec(domain):
    resolver = dns.resolver.Resolver()
    request = dns.message.make_query(domain, 'A')
    request.flags |= dns.flags.AD
    
    response = resolver.resolve(request)
    
    if response.flags & dns.flags.AD:
        print(f"DNSSEC validated for {domain}")
    else:
        print(f"DNSSEC not validated for {domain}")

DNS Resolution in Applications

Python Socket Module

import socket

# Simple hostname to IP
ip = socket.gethostbyname('example.com')
print(f"IP: {ip}")

# Get all IP addresses
ips = socket.getaddrinfo('example.com', 80)
for ip_info in ips:
    family, socktype, proto, canonname, sockaddr = ip_info
    print(f"IP: {sockaddr[0]}")

# Reverse DNS
hostname = socket.gethostbyaddr('93.184.216.34')
print(f"Hostname: {hostname[0]}")

# Caching with dnspython
from dns.resolver import Cache

cache = Cache()
resolver = dns.resolver.Resolver()
resolver.cache = cache

DNS in Production Applications

# Good practice: Use multiple DNS servers

dns_servers = [
    '8.8.8.8',      # Google
    '8.8.4.4',      # Google
    '1.1.1.1',      # Cloudflare
    '1.0.0.1',      # Cloudflare
]

# Implement fallback
def resolve_with_fallback(hostname, record_type='A'):
    for server in dns_servers:
        try:
            resolver = dns.resolver.Resolver()
            resolver.nameservers = [server]
            answers = resolver.resolve(hostname, record_type)
            return [str(rdata) for rdata in answers]
        except:
            continue
    raise Exception(f"Failed to resolve {hostname}")

# Health checking with DNS
import socket
import time

def check_dns_health():
    test_domains = [
        ('google.com', 'A'),
        ('cloudflare.com', 'A'),
        ('example.com', 'A')
    ]
    
    for domain, rtype in test_domains:
        try:
            start = time.time()
            socket.gethostbyname(domain)
            elapsed = (time.time() - start) * 1000
            print(f"{domain}: {elapsed:.1f}ms")
        except:
            print(f"{domain}: FAILED")

DNS Security

DNS Attacks

# Common DNS attacks

dns_attacks = {
    "dns_spoofing": {
        "description": "Attacker injects fake DNS records",
        "mitigation": "DNSSEC"
    },
    "dns_amplification": {
        "description": "Attacker uses DNS to amplify DDoS",
        "mitigation": "Rate limiting, BCP38"
    },
    "dns_tunneling": {
        "description": "Exfiltrating data via DNS queries",
        "mitigation": "DNS filtering, monitoring"
    },
    "dns_hijacking": {
        "description": "Redirecting DNS queries to malicious servers",
        "mitigation": "DNSSEC, registry locks"
    },
    "NXDOMAIN_attack": {
        "description": "Flooding with fake NXDOMAIN responses",
        "mitigation": "RRL (Response Rate Limiting)"
    }
}

DNSSEC

# DNSSEC adds cryptographic signatures to DNS

# How it works:
# 1. Zone signs its records with ZSK (Zone Signing Key)
# 2. KSK (Key Signing Key) signs the ZSK
# 3. Chain of trust goes up to root

# Enable DNSSEC in BIND
options {
    dnssec-enable yes;
    dnssec-validation auto;
};

# DNSSEC key signing
dnssec-keygen -a RSASHA256 -b 2048 -K /etc/bind/keys example.com
dnssec-signzone -S -K /etc/bind/keys example.com

DNS over HTTPS (DoH)

# Traditional DNS (unencrypted)
# Queries sent in plain text over UDP/TCP port 53

# DNS over HTTPS (encrypted)
# Queries sent via HTTPS to DoH server

# Benefits:
# - Encryption hides queries from ISPs
# - Bypasses DNS-based blocking
# - More reliable on some networks

Python DoH Example

import requests
import json

# Cloudflare DoH
DOH_CLOUDFLARE = "https://cloudflare.com/dns-query"

def resolve_doh(domain, record_type='A'):
    headers = {
        'accept': 'application/dns-json'
    }
    
    params = {
        'name': domain,
        'type': record_type
    }
    
    response = requests.get(DOH_CLOUDFLARE, 
                          headers=headers, 
                          params=params)
    
    data = response.json()
    
    results = []
    if 'Answer' in data:
        for answer in data['Answer']:
            results.append({
                'type': answer['type'],
                'data': answer['data']
            })
    
    return results

# Example usage
results = resolve_doh('example.com')
for r in results:
    print(r)

DNS Filtering

# Block malicious domains
import re

BLOCKED_DOMAINS = {
    'malware.example.com',
    'phishing.bad-site.com',
    'ads.tracker.com',
}

def should_block(domain):
    # Exact match
    if domain in BLOCKED_DOMAINS:
        return True
    
    # Check subdomains
    for blocked in BLOCKED_DOMAINS:
        if domain.endswith('.' + blocked):
            return True
    
    return False

# Using Pi-hole for network-wide blocking
# Pi-hole is a DNS-level ad blocker
# 
# Configure in /etc/dnsmasq.d/:
# address=/doubleclick.net/0.0.0.0
# address=/facebook.com/0.0.0.0

DNS for High Availability

Multiple Nameservers

# Best practice: 3+ nameservers
# Different providers
# Different geographic locations

# Example configuration:
nameservers:
  - ns1.cloudprovider.com    # Primary (AWS Route 53)
  - ns2.cloudprovider.com    # Secondary
  - ns3.google.com           # Tertiary (GCP)
  - ns4.google.com            # Quaternary

TTL Strategy

# TTL (Time To Live) guidelines

ttl_strategy = {
    "standard_records": {
        "A": 3600,      # 1 hour
        "AAAA": 3600,
        "CNAME": 3600,
        "MX": 86400     # 24 hours (rarely changes)
    },
    
    "low_ttl_before_change": {
        "description": "Lower TTL before making changes",
        "value": 300,   # 5 minutes
        "when": "24-48 hours before DNS change"
    },
    
    "high_traffic": {
        "A": 300,       # Lower for frequently changing IPs
        "CNAME": 300
    },
    
    "stable": {
        "MX": 86400,    # Higher for stable records
        "NS": 86400
    }
}

Geographic DNS

# Route 53 Geolocation routing
geolocation_config = """
# Direct traffic based on user location

us-east-1  -> 53.40.10.10    # US users
eu-west-1  -> 53.50.20.20    # European users
ap-south-1 -> 53.60.30.30    # Asian users
default    -> 53.70.40.40    # Default

# Latency routing
# Route to lowest latency region
latency_config = {
    "us-east": {"region": "us-east-1", "ip": "53.40.10.10"},
    "eu-west": {"region": "eu-west-1", "ip": "53.50.20.20"}
}
"""

Conclusion

DNS is fundamental to internet infrastructure:

  • Resolution: DNS translates names to IPs through hierarchical nameservers
  • Records: Different record types serve different purposes (A, AAAA, CNAME, MX, TXT, etc.)
  • Security: DNSSEC, DoH, and filtering protect against attacks
  • Availability: Multiple nameservers, proper TTLs, and geographic routing ensure reliability

Understanding DNS is essential for network engineers and developers building internet-facing applications.


Comments