python - 使用 Twisted 模拟 DNS 服务器
问题描述
我正在尝试编写一个基于 Twisted 的模拟 DNS 服务器来进行一些测试。
从本指南中汲取灵感,我编写了一个非常简单的服务器,它将所有内容解析为127.0.0.1
:
from twisted.internet import defer, reactor
from twisted.names import dns, error, server
class MockDNSResolver:
def _doDynamicResponse(self, query):
name = query.name.name
record = dns.Record_A(address=b"127.0.0.1")
answer = dns.RRHeader(name=name, payload=record)
authority = []
additional = []
return [answer], authority, additional
def query(self, query, timeout=None):
print("Incoming query for:", query.name)
if query.type == dns.A:
return defer.succeed(self._doDynamicResponse(query))
else:
return defer.fail(error.DomainError())
if __name__ == "__main__":
clients = [MockDNSResolver()]
factory = server.DNSServerFactory(clients=clients)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(10053, protocol)
reactor.listenTCP(10053, factory)
reactor.run()
以上与dig
and nslookup
(来自不同的终端)一起工作得很好:
$ dig -p 10053 @localhost something.example.org A +short
127.0.0.1
$ nslookup something.else.example.org 127.0.0.1 -port=10053
Server: 127.0.0.1
Address: 127.0.0.1#10053
Non-authoritative answer:
Name: something.else.example.org
Address: 127.0.0.1
我还在运行服务器的终端上获得了相应的命中:
Incoming query for: something.example.org
Incoming query for: something.else.example.org
然后,我根据关于发出请求的部分和关于安装自定义解析器的部分编写了以下代码:
from twisted.internet import reactor
from twisted.names.client import createResolver
from twisted.web.client import Agent
d = Agent(reactor).request(b'GET', b'http://does.not.exist')
reactor.installResolver(createResolver(servers=[('127.0.0.1', 10053)]))
def callback(result):
print('Result:', result)
d.addBoth(callback)
d.addBoth(lambda _: reactor.stop())
reactor.run()
但这失败了(而且我在服务器终端中没有任何线路)。看起来好像查询不是去模拟服务器,而是去系统定义的服务器:
Result: [Failure instance: Traceback: <class 'twisted.internet.error.DNSLookupError'>: DNS lookup failed: no results for hostname lookup: does.not.exist.
/.../venv/lib/python3.6/site-packages/twisted/internet/_resolver.py:137:deliverResults
/.../venv/lib/python3.6/site-packages/twisted/internet/endpoints.py:921:resolutionComplete
/.../venv/lib/python3.6/site-packages/twisted/internet/defer.py:460:callback
/.../venv/lib/python3.6/site-packages/twisted/internet/defer.py:568:_startRunCallbacks
--- <exception caught here> ---
/.../venv/lib/python3.6/site-packages/twisted/internet/defer.py:654:_runCallbacks
/.../venv/lib/python3.6/site-packages/twisted/internet/endpoints.py:975:startConnectionAttempts
]
我在用着:
- macOS 10.14.6 Python 3.6.6,Twisted 18.9.0
- Linux Mint 19.1、Python 3.6.9、Twisted 19.7.0
感谢您的帮助,如果需要其他信息,请告诉我。
谢谢!
解决方案
解决方案是:
- (客户端)按照@Hadus 的建议交换安装解析器并为请求创建延迟的行的顺序。我认为这无关紧要,因为反应堆还没有运行。
- (服务器)实现
lookupAllRecords
,重用现有_doDynamicResponse
方法。
# server
from twisted.internet import defer, reactor
from twisted.names import dns, error, server
class MockDNSResolver:
"""
Implements twisted.internet.interfaces.IResolver partially
"""
def _doDynamicResponse(self, name):
print("Resolving name:", name)
record = dns.Record_A(address=b"127.0.0.1")
answer = dns.RRHeader(name=name, payload=record)
return [answer], [], []
def query(self, query, timeout=None):
if query.type == dns.A:
return defer.succeed(self._doDynamicResponse(query.name.name))
return defer.fail(error.DomainError())
def lookupAllRecords(self, name, timeout=None):
return defer.succeed(self._doDynamicResponse(name))
if __name__ == "__main__":
clients = [MockDNSResolver()]
factory = server.DNSServerFactory(clients=clients)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(10053, protocol)
reactor.listenTCP(10053, factory)
reactor.run()
# client
from twisted.internet import reactor
from twisted.names.client import createResolver
from twisted.web.client import Agent
reactor.installResolver(createResolver(servers=[('127.0.0.1', 10053)]))
d = Agent(reactor).request(b'GET', b'http://does.not.exist:8000')
def callback(result):
print('Result:', result)
d.addBoth(callback)
d.addBoth(lambda _: reactor.stop())
reactor.run()
$ python client.py
Result: <twisted.web._newclient.Response object at 0x101077f98>
(我正在python3 -m http.server
另一个终端中运行一个简单的 Web 服务器,否则我会得到一个合理的twisted.internet.error.ConnectionRefusedError
例外)。
推荐阅读
- javascript - 为什么 new Date(undefined) 会创建一个无效的日期,但 new Date(null) 不会?
- javascript - 除非刷新,否则redux不会重新渲染
- css - 更改输入文本框大小(高度和宽度)
- javascript - 使用 Jquery 从元素中获取源代码
- google-apps-script - 自动从 Google Drive 中删除超过 n 天的文件 - “getFolderById”问题
- sql - SQL Server 2016如何更新标签中包含点的json列
- c - 蛇和梯子板 - 输出不打印出来
- r - 在 R 中,使用 diff() 查找每个间隔的开始和结束日期
- arrays - 我想将 \x0a 作为字节发送,而不是作为 \n
- javascript - vuetify 自动完成预加载