0

我目前正在尝试寻找一种方法来检查名称服务器是否可以响应 TCP 或 UDP 数据包。

我的想法是,从一个网站(例如 google.com)获取所有名称服务器,将它们存储在一个列表中,然后尝试向所有这些服务器发送 TCP 和 UDP 消息。

尽管我正在获取名称服务器,但当我尝试对 udp 进行查询(检查udpPacket代码)时,我的解释器显示了一个问题:

"TypeError: coercing to Unicode: need string or buffer, NS found"

我是 Python 新手(来自 C 和 C++),我猜这只是不兼容的类型。

我检查了dnspython的文档,找不到 NS 是什么类型(可能它本身就是一个类型)以及为什么它不能作为参数传递。

你认为问题是什么?有没有更好的方法来解决这类问题?

def getNSResults(url):

    #create an empty list where we can store all the nameservers we found
    nameServers = []

    nameServers = dns.resolver.query(url,dns.rdatatype.NS, raise_on_no_answer=False)

    #create a dictionary where based on all the nameservers.
    #1st label refers to the ns name of our url that we inserted.
    #2nd label shows wether or not we received a UDP response or not.
    #3rd label shows wether or not we received a TCP response or not.
    results = {}

    for nameServer in nameServers:

        #make a dns ns query, acts as a dumb message since whatever we send we just care of what we get back
        query = dns.message.make_query(dns.name.from_text(url), dns.rdatatype.ANY)

        query.flags |= dns.flags.AD

        query.find_rrset(query.additional, dns.name.root, 65535, dns.rdatatype.OPT, create=True, force_unique=True)

        #try sending a udp packet to see if it's listening on UDP
        udpPacket = dns.query.udp(query,nameServer)

        #try sending a tcp packet to see if it's listening on TCP
        tcpPacket = dns.query.tcp(None,nameServer)

        #add the results in a dictionary and return it, to be checked later by the user.
        results.update({"nsName" == nameServer, "receivedUDPPacket" == isNotNone(udpPacket),"receivedTCPPacket" == isNotNone(tcpPacket)})

提前致谢!

4

1 回答 1

0

查看您的代码,我看到一些 DNS 问题、一些 Python 问题和一些 dnspython 问题。让我们看看我们是否可以一起学习一些东西。

域名系统

首先,getNSResults调用函数的参数url。当您发送 DNS 查询时,您查询的是域名。URL 是完全不同的东西(例如https://example.com/index.html)。我会重命名urldomain_name,domainname. 有关 URL 和域名之间区别的更多信息,请参阅https://www.copahost.com/blog/domain-vs-url/

其次,让我们谈谈你想要做什么。

我目前正在尝试找到一种方法来检查名称服务器是否可以响应 tcp 或 udp 数据包。

我的想法是,从网站(例如 google.com)获取所有名称服务器,将它们存储在一个列表中,然后尝试向所有这些服务器发送 tcp 和 udp 消息。

这听起来是一个很好的方法。我想你可能在这里遗漏了一些细节。所以让我解释一下你可以采取的步骤:

  1. 对域名进行 NS 查询。您的代码中已经包含此步骤。您实际上从该查询中得到的只是另一个域名(或多个域名)。例如,如果您运行dig +short NS google.com,您将获得以下输出:
ns3.google.com.
ns1.google.com.
ns4.google.com.
ns2.google.com.
  1. 在这一步,我们有一个或多个权威服务器名称的列表。现在我们需要一个 IP 地址来向他们发送查询。因此,我们将对从步骤 1 中获得的每个名称进行 A 类查询。
  2. 现在我们有了一个 IP 地址列表。我们可以通过 UDP 和 TCP 发送一个 DNS 查询,看看它们是否受支持。

Python

在大多数情况下,您的 Python 语法是可以的。我看到的最大危险信号是以下代码:

results.update({"nsName" == nameServer, 
    "receivedUDPPacket" == isNotNone(udpPacket),
    "receivedTCPPacket" == isNotNone(tcpPacket)})

让我们分解一下。首先,你有results,这是一个dict。然后你有这个:

{"nsName" == nameServer, 
"receivedUDPPacket" == isNotNone(udpPacket),
"receivedTCPPacket" == isNotNone(tcpPacket)}

这是sset的一个bool。我认为你的意思是这样的:

results.update({
    "nsName": nameServer,
    "receivedUDPPacket": true,
    "receivedTCPPacket": true
})

Python 中的函数和变量名称通常用小写字母书写,单词之间用下划线分隔(例如my_variable, def my_function())。类名通常是大写的驼峰式(例如class MyClass)。这些都不是必需的,你可以随心所欲地命名你的东西,许多超级流行的库和内置函数打破了这个约定,只是想我会把它扔在那里,因为它在阅读 Python 代码时会很有帮助。

dnspython

当您不确定事物的类型或事物具有哪些属性时,请记住这四个朋友,它们都是 Python 内置的:1. pdb 2. dir 3. type 4.print

pdb是一个 Python 调试器。只是import pdb, 和pdb.set_trace()你想打破的地方。您的代码将停在那里,然后您可以检查所有变量的值。

dir将返回您传递给它的任何属性和方法。示例:print(dir(udpPacket))

type将返回对象的类型。

print正如您可能已经知道的那样,它将打印出一些内容以便您查看。

我将把这部分留给你测试。dir()如果您不知道它是什么,请运行所有内容。我还应该提一下help(),这对于内置的东西非常有用。

本节的总结是,有时文档并不全部存在,或者很难找到,尤其是当您不熟悉语言/库/任何东西时。所以你必须自己解决问题,这意味着使用我刚才提到的所有工具,查看源代码,诸如此类。

概括

我希望这可以帮到你。我知道这很多,可能太多了,但请耐心等待,并知道 DNS 和 Python 是一些非常有用和有趣的东西,值得学习。

我继续写了一些东西,这是我认为您希望实现的目标的开始。我建议您浏览整个过程并确保您了解正在发生的事情。如果您不理解某些内容,请记住pdbdir(并且总是有 Google、SO 等)。

import dns.resolver
import dns.message
import dns.rdatatype

import json
import sys

def check_tcp_and_udp_support(name):
    # this will give me the first default system resolver from /etc/resolv.conf
    # (or Windows registry)
    where = dns.resolver.Resolver().nameservers[0]

    q = dns.message.make_query(name, dns.rdatatype.NS)
    ns_response = dns.query.udp(q, where)

    ns_names = [t.target.to_text() for ans in ns_response.answer for t in ans]

    # this code is the same as the one-liner above
    # ns_names = []
    # for ans in ns_response.answer:
    #     for t in ans:
    #         ns_names.append(t.target.to_text())

    results = {}

    for ns_name in ns_names:

        # do type A lookup for nameserver
        q = dns.message.make_query(ns_name, dns.rdatatype.A)
        response = dns.query.udp(q, where)

        nameserver_ips = [item.address for ans in response.answer for item in ans.items if ans.rdtype == dns.rdatatype.A]

        # now send queries to the nameserver IPs
        for nameserver_ip in nameserver_ips:
            q = dns.message.make_query('example.com.', dns.rdatatype.A)
            try:
                udp_response = dns.query.udp(q, nameserver_ip)
                supports_udp = True
            except dns.exception.Timeout:
                supports_udp = False
            try:
                tcp_response = dns.query.tcp(q, nameserver_ip)
                supports_tcp = True
            except dns.exception.Timeout:
                supports_tcp = True

            results[nameserver_ip] = {
                'supports_udp': supports_udp,
                'supports_tcp': supports_tcp
            }

    return results

def main():
    results = check_tcp_and_udp_support('google.com')

    # this is just fancy JSON printing
    # you could do print(results) instead
    json.dump(results, sys.stdout, indent=4)

if __name__ == '__main__':
    main()

再次,我希望这会有所帮助。当我不知道你脑子里到底在想什么时,这很难,但这就是我为你准备的。

于 2020-04-23T02:14:57.010 回答