我想查询一个这样的域:
dns.resolver.resolve("dnssec-failed.org","A")
返回如下错误:
raise NoNameservers(request=self.request, errors=self.errors)
dns.resolver.NoNameservers: All nameservers failed to answer the query dnssec-failed.org. IN A: Server 127.0.0.1 UDP port 53 answered SERVFAIL
我希望能够在我的函数中捕捉到这样的异常:
def get_a_record(url):
try:
answers = dns.resolver.resolve(url,"A")
except dns.resolver.SERVFAIL:
print("SERVFAIL error for %s" % url)
except dns.resolver.NXDOMAIN:
print("No such domain %s" % url)
except dns.resolver.Timeout:
print("Timed out while resolving %s" % url)
except dns.exception.DNSException:
print("Unhandled exception")
现在我知道在上面的片段dns解析器中没有SERVAIL异常,但是我想要做的是捕捉错误,能够记录它,并继续我的脚本。是否有正确的方法使用dns解析器包来完成此操作,或者我是否需要调用dig
命令并解析该结果?
编辑
为了澄清起见,我只使用dnssec-failed.org作为示例,因为它的结果(我认为)与我专门寻找的响应是相同的,但实际上没有任何活动的示例。这个“东西”是指不再使用的ip地址的域。悬空的NS记录,换句话说。
例如,我使用AWS借给我的IP地址,用于一些基于XYZ云的应用程序,并在我的DNS区域中创建名称到地址映射记录。如果我决定放弃此服务,并将ip返回到云提供商的ips池,但忘记从区域中删除DNS记录,则会留下“悬空”。
这就是我所要寻找的,我错误地认为SERVFAIL是我从像dig domain-with-no-ip.com
这样的查询中得到的响应类型,对此我表示歉意。
编辑2
我已经注册了一个域名,并对此进行了测试。为其配置A记录,并将其指向侦听端口7272的Ubuntu EC2 (python3 -m http.server 7272)。等待区域传播5分钟,然后我就能够公开地到达我的域。一切都很好。
然后我停止了实例,等待了一会儿,然后重新启动了它。一回来,它就有了一个新的公共知识产权。太棒了。因此,在这一点上,有一个悬空的记录,让我来测试。
所以我在域名上进行挖掘和查找。两人都带着完美的答案回来了。他们只是简单地指出了现在旧的/原始的公共知识产权。这是有意义的,因为DNS记录没有改变。唯一能观察到的真正改变的东西是卷发之类的东西,它超时了。
因此,除非我的理解仍然是错误的,否则真的没有一种非常可靠的方法来寻找悬空的A记录,因为基于n个http超时的逻辑不一定意味着一个悬空记录。服务器可能只是关闭/关闭,ip仍然连接到资源。我的理解是正确的,还是我仍然遗漏了什么?
编辑3
接受答案是因为,尽管我的问题演变成了其他的问题,但从技术上讲,答案确实解决了我的帖子中最初的问题,我认为这是值得接受的。
发布于 2021-03-21 03:10:50
首先,dnssec-failed.org
有名称服务器,但在设计上却失败了。
因此,对任何执行DNSSEC验证的递归名称服务器的简单查询都将如预期的那样在SERVFAIL
中失败:
$ dig dnssec-failed.org NS +short
(no output)
$ dig dnssec-failed.org NS | grep status: | tail -1
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 46517
但是,一旦禁用了DNSSEC验证,就会得到名称服务器:
$ dig dnssec-failed.org NS +cdflag +noall +ans +nottlunits
dnssec-failed.org. 7200 IN NS dns105.comcast.net.
dnssec-failed.org. 7200 IN NS dns101.comcast.net.
dnssec-failed.org. 7200 IN NS dns102.comcast.net.
dnssec-failed.org. 7200 IN NS dns103.comcast.net.
dnssec-failed.org. 7200 IN NS dns104.comcast.net.
现在回到Python部分。
dnspython中的resolve()
是一个高级API调用,它执行解析器所做的所有事情,也就是说,它可能从根一直恢复到能够给出答案。因此,这个简单的调用可能隐藏多个问题和响应,因此可能不会暴露出真正的底层问题,而是使用异常在输出中提供高级API。
正如您在自己的示例中所看到的,您在错误消息中拥有SERVFAIL
权限,但它是一个NoNameservers
异常,因为代码要求注册中心名称服务器提供名称服务器列表(这很有效,父名称服务器中有此名称的DS ),然后请求任何这些名称服务器提供进一步的数据,然后它们在DNSSEC验证中失败,因此是最后的异常。
我不清楚你对DNSSEC错误的立场在你的情况下是什么,如果你不关心它们,或者你真的想研究它们并做一些特别的事情。因此,可能需要对上述解决方案进行调整。如果您不关心,只需记录NoNameservers
异常并继续进行,一切都将以例外方式工作,DNSSEC验证错误将完全像一个破碎的域一样发生,这是每个设计的结果。
因此,您真的需要以与任何其他错误不同的方式处理DNSSEC错误吗?为什么不能捕获NoNameservers
异常,记录它,并更进一步呢?
否则,只需解析附加到NoNameservers
异常的错误消息即可,如果您看到SERVFAIL
,您可以假设(但不是100%确定)这是一个DNSSEC问题,并且至少可以根据您的需要更进一步。
如果您确实需要获得更多的详细信息,并确保这是DNSSEC问题,则需要执行与dig
相同的操作,即执行两个与CD
标志不同的查询,并比较结果。这意味着“低于”resolve()
API并直接使用dns.query
,例如:
>>> import dns, dns.rcode
>>> resolver_ip = '8.8.8.8' # Use any recursive **validating** nameserver that you trust
>>> query=dns.message.make_query('dnssec-failed.org', 'A')
>>> response = dns.query.udp_with_fallback(query, resolver_ip)[0]
>>> response.rcode() == dns.rcode.SERVFAIL
True
# Now checking if disabling DNSSEC resolves the problem and gets us a reply
# If so, it really means there is a DNSSEC problem
>>> print(str(query))
id 65008
opcode QUERY
rcode NOERROR
flags RD
;QUESTION
dnssec-failed.org. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
>>> query.flags
<Flag.RD: 256>
>>> query.flags = query.flags | dns.flags.CD
>>> query.flags
<Flag.RD|CD: 272>
>>> print(str(query))
id 65008
opcode QUERY
rcode NOERROR
flags RD CD
;QUESTION
dnssec-failed.org. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
# We enabled flag "CD" aka checking disabled aka please do not do any DNSSEC validation, and now doing the same query as above again:
>>> response = dns.query.udp_with_fallback(query, resolver_ip)[0]
>>> response.rcode() == dns.rcode.SERVFAIL
False
>>> response.rcode() == dns.rcode.NOERROR
True
>>> response.answer[0][0]
<DNS IN A rdata: 69.252.80.75>
https://stackoverflow.com/questions/66727659
复制相似问题