Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python DNS Server

I am adding a feature to my current project that will allow network admins to install the software to the network. I need to code a DNS server in Python that will allow me to redirect to a certain page if the request address is in my list. I was able to write the server, just not sure how to redirect.

Thank you. I am using Python 2.6 on Windows XP.

like image 584
Zac Brown Avatar asked May 12 '26 19:05

Zac Brown


2 Answers

There's little, simple example here that can easily be adapted to make all kinds of "mini fake dns servers". Note that absolutely no "redirect" is involved (that's not how DNS works): rather, the request is for a domain name, and the result of that request is an IP address. If what you want to do is drastically different from translating names to addresses, then maybe what you need is not actually a DNS server...?

like image 182
Alex Martelli Avatar answered May 15 '26 09:05

Alex Martelli


Using circuits and dnslib here's a full recursive dns server written in Python in only 143 lines of code:

#!/usr/bin/env python


from __future__ import print_function


from uuid import uuid4 as uuid


from dnslib import CLASS, QR, QTYPE
from dnslib import DNSHeader, DNSQuestion, DNSRecord


from circuits.net.events import write
from circuits import Component, Debugger, Event
from circuits.net.sockets import UDPClient, UDPServer


class lookup(Event):
    """lookup Event"""


class query(Event):
    """query Event"""


class response(Event):
    """response Event"""


class DNS(Component):

    def read(self, peer, data):
        record = DNSRecord.parse(data)
        if record.header.qr == QR["QUERY"]:
            return self.fire(query(peer, record))
        return self.fire(response(peer, record))


class ReturnResponse(Component):

    def response(self, peer, response):
        return response


class Client(Component):

    channel = "client"

    def init(self, server, port, channel=channel):
        self.server = server
        self.port = int(port)

        self.transport = UDPClient(0, channel=self.channel).register(self)
        self.protocol = DNS(channel=self.channel).register(self)
        self.handler = ReturnResponse(channel=self.channel).register(self)


class Resolver(Component):

    def init(self, server, port):
        self.server = server
        self.port = port

    def lookup(self, qname, qclass="IN", qtype="A"):
        channel = uuid()

        client = Client(
            self.server,
            self.port,
            channel=channel
        ).register(self)

        yield self.wait("ready", channel)

        self.fire(
            write(
                (self.server, self.port),
                DNSRecord(
                    q=DNSQuestion(
                        qname,
                        qclass=CLASS[qclass],
                        qtype=QTYPE[qtype]
                    )
                ).pack()
            )
        )

        yield (yield self.wait("response", channel))

        client.unregister()
        yield self.wait("unregistered", channel)
        del client


class ProcessQuery(Component):

    def query(self, peer, query):
        qname = query.q.qname
        qtype = QTYPE[query.q.qtype]
        qclass = CLASS[query.q.qclass]

        response = yield self.call(lookup(qname, qclass=qclass, qtype=qtype))

        record = DNSRecord(
            DNSHeader(id=query.header.id, qr=1, aa=1, ra=1),
            q=query.q,
        )

        for rr in response.value.rr:
            record.add_answer(rr)

        yield record.pack()


class Server(Component):

    def init(self, bind=("0.0.0.0", 53)):
        self.bind = bind

        self.transport = UDPServer(self.bind).register(self)
        self.protocol = DNS().register(self)
        self.handler = ProcessQuery().register(self)


class App(Component):

    def init(self, bind=("0.0.0.0", 53), server="8.8.8.8", port=53,
             verbose=False):

        if verbose:
            Debugger().register(self)

        self.resolver = Resolver(server, port).register(self)
        self.server = Server(bind).register(self)


def main():
    App().run()


if __name__ == "__main__":
    main()

Usage:

By default this example binds go 0.0.0.0:53 so you will need to do something like:

sudo ./dnsserver.py

Otherwise change the bind parameter.

like image 32
James Mills Avatar answered May 15 '26 09:05

James Mills



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!