dns
DNS protocol and domain name resolution
Source facts
- Repository
- ffsshhttiikk/opencode-agents-skills
- Last source activity
- February 28, 2026 at 22:49
- Detected SKILL.md language
- English
- Stars
- 3
- Forks
- 2
Install options
The review-first prompt is selected by default. You can switch to a direct command or download a local copy.
Review the source files
Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.
Showing SKILL.md
SKILL.md
Source instructions · Read-only preview- name
- dns
- description
- DNS protocol and domain name resolution
- category
- networking
- difficulty
- intermediate
- tags
- ["dns","domain","resolution","nameserver"]
- author
- OpenCode Community
- version
- 1
- last_updated
- 2024-01-15T00:00:00.000Z
# DNS (Domain Name System)
## What I Do
I am DNS, the hierarchical naming system translating human-readable domain names into machine-readable IP addresses. I provide distributed, scalable hostname resolution through a global network of authoritative name servers, recursive resolvers, and caching servers. I support multiple record types (A, AAAA, CNAME, MX, TXT, NS, SRV) for various purposes. I implement caching at multiple levels to improve performance and reduce load. I support DNSSEC for authenticated responses, DNS-over-HTTPS for encrypted queries, and dynamic updates for real-time record management. I form the foundation of internet addressing, enabling users to access services using memorable names rather than numeric IP addresses.
## When to Use Me
- Implementing custom DNS resolution
- Configuring DNS records for services
- Building DNS-based service discovery
- DNS troubleshooting and diagnostics
- High-availability DNS infrastructure
- DNS-based load balancing (GeoDNS, latency-based)
- Domain registration and management
- DNSSEC implementation
- Private DNS zones
## Core Concepts
**Record Types**: A (IPv4), AAAA (IPv6), CNAME (alias), MX (mail), TXT (text), NS (nameserver), SRV (service), SOA (authority).
**DNS Hierarchy**: Root servers → TLD servers → Authoritative servers → Recursive resolvers.
**Caching**: TTL (Time to Live) controlling how long records are cached.
**Zones**: Portions of the DNS namespace managed by authoritative servers.
**DNSSEC**: DNS Security Extensions providing authentication for DNS responses.
**Anycast**: Multiple servers sharing the same IP for geographic distribution.
**Round-Robin**: Multiple IP addresses rotated for load distribution.
## Code Examples
### Example 1: DNS Client with Cache (Python)
```python
import socket
import struct
import time
import threading
from typing import Optional, Dict, List
from dataclasses import dataclass, field
from enum import Enum
class DNSRecordType(Enum):
A = 1
AAAA = 28
CNAME = 5
MX = 15
NS = 2
TXT = 16
SOA = 6
SRV = 33
@dataclass
class DNSRecord:
name: str
rtype: DNSRecordType
rdata: str
ttl: int
timestamp: float = field(default_factory=time.time)
class DNSCache:
def __init__(self, max_size: int = 1000, default_ttl: int = 300):
self.cache: Dict[str, List[DNSRecord]] = {}
self.lock = threading.RLock()
self.max_size = max_size
self.default_ttl = default_ttl
def get(self, name: str, rtype: DNSRecordType) -> Optional[List[DNSRecord]]:
with self.lock:
key = f"{name}:{rtype.name}"
if key not in self.cache:
return None
records = self.cache[key]
now = time.time()
valid = [r for r in records if r.ttl == 0 or (now - r.timestamp) < r.ttl]
if not valid:
del self.cache[key]
return None
if len(valid) < len(records):
self.cache[key] = valid
return valid
def set(self, name: str, rtype: DNSRecordType, records: List[DNSRecord]):
with self.lock:
key = f"{name}:{rtype.name}"
if len(self.cache) >= self.max_size:
self.evict_oldest()
self.cache[key] = records
def evict_oldest(self):
if not self.cache:
return
oldest_key = min(self.cache.keys(),
key=lambda k: min(r.timestamp for r in self.cache[k]))
del self.cache[oldest_key]
def clear(self):
with self.lock:
self.cache.clear()
def get_stats(self) -> Dict:
with self.lock:
return {
'entries': len(self.cache),
'records': sum(len(v) for v in self.cache.values())
}
class DNSClient:
DNS_SERVER = '8.8.8.8'
DNS_PORT = 53
TIMEOUT = 5.0
def __init__(self, server: str = None, cache: DNSCache = None):
self.server = server or self.DNS_SERVER
self.cache = cache or DNSCache()
self.socket = None
def _create_socket(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(self.TIMEOUT)
return sock
def resolve(self, name: str, rtype: DNSRecordType = DNSRecordType.A,
use_cache: bool = True) -> List[DNSRecord]:
if use_cache:
cached = self.cache.get(name, rtype)
if cached:
return cached
records = self._query(name, rtype)
if use_cache and records:
self.cache.set(name, rtype, records)
return records
def _query(self, name: str, rtype: DNSRecordType) -> List[DNSRecord]]:
sock = self._create_socket()
try:
# Build DNS query
transaction_id = struct.pack("!H", 0x1234)
flags = struct.pack("!H", 0x0100) # Standard query, RD=1
qdcount = struct.pack("!H", 1)
ancount = struct.pack("!H", 0)
nscount = struct.pack("!H", 0)
arcount = struct.pack("!H", 0)
# Encode domain name
qname = b''
for label in name.split('.'):
qname += struct.pack("!B", len(label)) + label.encode()
qname += b'\x00'
# Question type and class
qtype = struct.pack("!H", rtype.value)
qclass = struct.pack("!H", 1) # IN class
query = transaction_id + flags + qdcount nscount + + ancount + arcount + qname + qtype + qclass
sock.sendto(query, (self.server, self.DNS_PORT))
response = sock.recv(512)
finally:
sock.close()
return self._parse_response(response, name)
def _parse_response(self, response: bytes, original_name: str) -> List[DNSRecord]:
records = []
transaction_id = struct.unpack("!H", response[0:2])[0]
flags = struct.unpack("!H", response[2:4])[0]
qdcount = struct.unpack("!H", response[4:6])[0]
ancount = struct.unpack("!H", response[6:8])[0]
offset = 12
# Skip question section
for _ in range(qdcount):
while response[offset] != 0:
offset += 1 + response[offset]
offset += 5
# Parse answer records
for _ in range(ancount):
name, offset = self._parse_name(response, offset)
rtype = DNSRecordType(struct.unpack("!H", response[offset:offset+2])[0])
offset += 2
rclass = struct.unpack("!H", response[offset:offset+2])[0]
offset += 2
ttl = struct.unpack("!I", response[offset:offset+4])[0]
offset += 4
rdlength = struct.unpack("!H", response[offset:offset+2])[0]
offset += 2
rdata = response[offset:offset+rdlength]
offset += rdlength
parsed_rdata = self._parse_rdata(rdata, rtype, original_name)
records.append(DNSRecord(
name=name,
rtype=rtype,
rdata=parsed_rdata,
ttl=ttl
))
return records
def _parse_name(self, response: bytes, offset: int) -> (str, int):
name = []
original_offset = offset
while True:
length = response[offset]
if length == 0:
offset += 1
break
if (length & 0xC0) == 0xC0:
# Compression pointer
pointer = struct.unpack("!H", response[offset:offset+2])[0] & 0x3FFF
pointed_name, _ = self._parse_name(response, pointer)
name.append(pointed_name)
offset += 2
break
else:
offset += 1
name.append(response[offset:offset+length].decode())
offset += length
return '.'.join(name), offset
def _parse_rdata(self, rdata: bytes, rtype: DNSRecordType, original_name: str) -> str:
if rtype == DNSRecordType.A:
return '.'.join(str(b) for b in rdata)
elif rtype == DNSRecordType.AAAA:
return ':'.join(f'{b:02x}{b+1:02x}' for b in rdata[::2])
elif rtype == DNSRecordType.CNAME:
name, _ = self._parse_name(rdata, 0)
return name
elif rtype == DNSRecordType.MX:
preference = struct.unpack("!H", rdata[0:2])[0]
name, _ = self._parse_name(rdata, 2)
return f"{preference} {name}"
elif rtype == DNSRecordType.TXT:
length = rdata[0]
return rdata[1:1+length].decode('utf-8')
else:
return rdata.hex()
def resolve_a(self, name: str, use_cache: bool = True) -> List[str]:
records = self.resolve(name, DNSRecordType.A, use_cache)
return [r.rdata for r in records]
def resolve_aaaa(self, name: str, use_cache: bool = True) -> List[str]:
records = self.resolve(name, DNSRecordType.AAAA, use_cache)
return [r.rdata for r in records]
def resolve_mx(self, name: str, use_cache: bool = True) -> List[tuple]:
records = self.resolve(name, DNSRecordType.MX, use_cache)
return [(int(r.rdata.split()[0]), r.rdata.split()[1]) for r in records]
def resolve_txt(self, name: str, use_cache: bool = True) -> List[str]:
records = self.resolve(name, DNSRecordType.TXT, use_cache)
return [r.rdata for r in records]
if __name__ == "__main__":
client = DNSClient()
# Resolve various record types
print("Resolving A records for google.com:")
a_records = client.resolve_a("google.com")
for ip in a_records:
print(f" {ip}")
print("\nResolving MX records for example.com:")
mx_records = client.resolve_mx("example.com")
for pref, server in mx_records:
print(f" Priority {pref}: {server}")
print("\nCache statistics:")
print(client.cache.get_stats())
```
### Example 2: DNS Server with Zone Files (Go)
```go
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"log"
"net"
"os"
"strings"
"sync"
"time"
)
type DNSRecord struct {
Name string
Type string
RData string
TTL int
}
type Zone struct {
Origin string
Records []DNSRecord
SOA DNSRecord
mutex sync.RWMutex
}
type DNSServer struct {
zones map[string]*Zone
cache map[string][]DNSRecord
cacheMutex sync.RWMutex
udpSocket *net.UDPConn
tcpListener *net.TCPListener
}
const (
TYPE_A = 1
TYPE_NS = 2
TYPE_CNAME = 5
TYPE_SOA = 6
TYPE_PTR = 12
TYPE_MX = 15
TYPE_TXT = 16
TYPE_AAAA = 28
TYPE_SRV = 33
)
func NewDNSServer() *DNSServer {
return &DNSServer{
zones: make(map[string]*Zone),
cache: make(map[string][]DNSRecord),
}
}
func (s *DNSServer) LoadZoneFile(filename string, origin string) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open zone file: %w", err)
}
defer file.Close()
zone := &Zone{
Origin: origin,
Records: make([]DNSRecord, 0),
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, ";") {
continue
}
parts := strings.Fields(line)
if len(parts) < 5 {
continue
}
record := DNSRecord{
Name: parts[0],
Type: strings.ToUpper(parts[2]),
RData: strings.Join(parts[4:], " "),
TTL: 3600,
}
if parts[1] != "IN" {
continue
}
zone.Records = append(zone.Records, record)
}
s.zones[origin] = zone
return nil
}
func (s *DNSServer) StartUDP(address string) error {
addr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
return fmt.Errorf("failed to resolve address: %w", err)
}
s.udpSocket, err = net.ListenUDP("udp", addr)
if err != nil {
return fmt.Errorf("failed to listen: %w", err)
}
go s.handleUDP()
return nil
}
func (s *DNSServer) StartTCP(address string) error {
addr, err := net.ResolveTCPAddr("tcp", address)
if err != nil {
return fmt.Errorf("failed to resolve address: %w", err)
}
s.tcpListener, err = net.ListenTCP("tcp", addr)
if err != nil {
return fmt.Errorf("failed to listen: %w", err)
}
go s.handleTCP()
return nil
}
func (s *DNSServer) handleUDP() {
buffer := make([]byte, 512)
for {
n, clientAddr, err := s.udpSocket.ReadFromUDP(buffer)
View on GitHubThis SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub