Python DNS 服务器

3 投票
4 回答
8283 浏览
提问于 2025-04-16 04:29

我正在给我的项目添加一个新功能,这个功能可以让网络管理员把软件安装到网络上。我需要用Python编写一个DNS服务器,这样当请求的地址在我的列表里时,就可以把请求重定向到某个特定的页面。我已经写好了服务器,只是不太确定怎么进行重定向。

谢谢!我在Windows XP上使用Python 2.6。

4 个回答

1

这里有一个用Python写的DNS服务器/代理,对我来说很好用:

http://thesprawl.org/projects/dnschef/

2

这里有一个用 circuitsdnslib 写的完整递归 DNS 服务器,代码只有 143 行,都是用 Python 写的:

#!/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()

使用方法:

默认情况下,这个例子会绑定到 0.0.0.0:53,所以你需要做一些类似于以下的操作:

sudo ./dnsserver.py

如果不想这样,可以修改 bind 参数。

5

这里有一个简单的小例子,可以在这里找到,你可以很容易地把它改造成各种“迷你假DNS服务器”。需要注意的是,这里完全没有涉及“重定向”(这不是DNS的工作方式):请求的是一个域名,而这个请求的结果是一个IP地址。如果你想做的事情和把名字翻译成地址有很大不同,那么也许你需要的并不是真正的DNS服务器…?

撰写回答