Saturday, 14 October 2023

Building a Simple DNS Forwarder in Python with Blocked Domain Support

Introduction

Domain Name System (DNS) is a critical part of internet infrastructure. It's the system that resolves human-readable domain names into IP addresses. In this article, we'll explore how to build a simple DNS forwarder in Python that can also block specific Fully Qualified Domain Names (FQDNs). The DNS forwarder will listen for DNS queries, check against a list of blocked FQDNs, and forward the request to a real DNS server if not blocked.

Prerequisites

  • Basic understanding of Python and networking.
  • Administrative access to run programs that bind to privileged ports.
  • Python installed on your system.

Code Structure

Extracting the FQDN

The first thing we need is a function to extract the FQDN from the DNS query packet.


def extract_fqdn(data):
    fqdn = ''
    i = 12  # Skip the header
    length = data[i]
    while length != 0:
        i += 1
        domain_part = data[i:i+length]
        fqdn += domain_part.decode() + '.'
        i += length
        length = data[i]
    return fqdn[:-1]
    

Loading Blocked FQDNs

We'll store the FQDNs that we want to block in a file called blocked_domains.txt, and then load them into a Python list.


with open("blocked_domains.txt", "r") as f:
    blocked_domains = [line.strip() for line in f.readlines()]
    

The Main Loop

The main part of the code sets up a UDP socket, listens for incoming DNS queries, and forwards them to a legitimate DNS server (Google's public DNS server 8.8.8.8 in this example).


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 53))

try:
    while True:
        data, addr = sock.recvfrom(512)
        fqdn = extract_fqdn(data)

        if fqdn in blocked_domains:
            print(f"Blocked request for {fqdn}")
            continue

        sock_forward = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock_forward.sendto(data, ('8.8.8.8', 53))
        forward_data, _ = sock_forward.recvfrom(512)
        sock.sendto(forward_data, addr)
finally:
    sock.close()
    

Important Notes

  1. This code should be run as a superuser to bind to port 53, a privileged port.
  2. The example is simplified for educational purposes and does not cover all edge cases.
  3. Exercise caution and use this script in a controlled environment to avoid any conflicts with existing DNS services.

Creating a DNS forwarder with domain-blocking capabilities can be a useful exercise for learning networking concepts and Python programming. While this example is quite basic, it lays the groundwork for building more complex DNS services.

No comments:

Post a Comment