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.

Medium Python 3.9+ Aug 9, 2026 Observability & SRE 16 views 0 copies

Python code

40 lines
Python 3.9+
import 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

stdout
[*] 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

  1. Use `socketserver.TCPServer` with a `StreamRequestHandler` to simplify threading.
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Observability & SRE

Related tutorials and quizzes for this topic.