How to Create a TCP DNS Mock Server in Python
This code creates a mock TCP DNS server that listens on a specified port, accepts probe connections, and returns a fixed DNS response header to simulate a live DNS service for testing and observability.
Python code
40 linesimport socket
import threading
def handle_client(client_socket, address):
print(f"[+] Connection from {address}")
try:
while True:
data = client_socket.recv(1024)
if not data:
break
print(f"[*] Received {len(data)} bytes (TCP DNS probe)")
# Mock response: echo a fixed DNS response header (2 bytes ID + 1 byte flags)
response = data[:2] + b"\x81\x80" + b"\x00\x01\x00\x01\x00\x00\x00\x00"
client_socket.send(response)
except Exception as e:
print(f"[-] Error: {e}")
finally:
client_socket.close()
print(f"[-] Closed connection from {address}")
def start_server(host="127.0.0.1", port=5353):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host, port))
server.listen(5)
print(f"[*] TCP DNS mock listening on {host}:{port}")
try:
while True:
client, addr = server.accept()
threading.Thread(target=handle_client, args=(client, addr), daemon=True).start()
except KeyboardInterrupt:
print("\n[!] Shutting down")
finally:
server.close()
if __name__ == "__main__":
start_server()
Output
[*] TCP DNS mock listening on 127.0.0.1:5353
[+] Connection from ('127.0.0.1', 52345)
[*] Received 512 bytes (TCP DNS probe)
[-] Closed connection from ('127.0.0.1', 52345)
How it works
The server uses a raw socket bound to a port, listening for TCP connections. Each client is handled in its own daemon thread, allowing concurrent probes without blocking. On receiving data, it constructs a mock DNS response by echoing the query ID (first two bytes) and appending a fixed header that indicates a successful response (flags 0x8180) with one question and one answer. The thread-safe design and SO_REUSEADDR option make it easy to restart during testing. This mock is lightweight and deterministic, perfect for validating monitoring scripts or network infrastructure checks.
Common mistakes
- Forgetting `socket.SO_REUSEADDR` can cause 'Address already in use' on restarts.
- Not using daemon threads may prevent the main loop from exiting cleanly on Ctrl+C.
- Assuming the client always sends a valid DNS query—should handle zero or malformed data.
Variations
- Use `socketserver.TCPServer` with a `StreamRequestHandler` to simplify threading.
- Make the response configurable via command-line arguments or environment variables.
Real-world use cases
- Simulating a DNS server in a test environment to verify monitoring probes and alerting thresholds.
- Providing a controlled endpoint for load testing DNS resolution modules in network automation.
- Acting as a stub for integration tests where external DNS dependencies must be mocked.
Sponsored
More from Observability & SRE
- Adding a Correlation ID to Log Context in Python medium
- Calculate Error Rate from Log Stream in Python easy
- Check if a Timestamp Falls in a Daily Maintenance Window in Python easy
- Export Metrics with OTLP Mock in Python medium
- Generate Mock CPU and Memory Metrics in Python easy
- Generate Prometheus Text Exposition Format in Python easy
Keep learning
Related tutorials and quizzes for this topic.