首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用Python的dns解析器捕获SERVFAIL异常?

如何使用Python的dns解析器捕获SERVFAIL异常?
EN

Stack Overflow用户
提问于 2021-03-21 00:04:21
回答 1查看 1K关注 0票数 0

我想查询一个这样的域:

代码语言:javascript
运行
复制
dns.resolver.resolve("dnssec-failed.org","A")

返回如下错误:

代码语言:javascript
运行
复制
 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

我希望能够在我的函数中捕捉到这样的异常:

代码语言:javascript
运行
复制
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

接受答案是因为,尽管我的问题演变成了其他的问题,但从技术上讲,答案确实解决了我的帖子中最初的问题,我认为这是值得接受的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-21 03:10:50

首先,dnssec-failed.org有名称服务器,但在设计上却失败了。

因此,对任何执行DNSSEC验证的递归名称服务器的简单查询都将如预期的那样在SERVFAIL中失败:

代码语言:javascript
运行
复制
$ 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验证,就会得到名称服务器:

代码语言:javascript
运行
复制
$ 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,例如:

代码语言:javascript
运行
复制
>>> 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>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66727659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档