【问题标题】:Read IP addresses and TTL from DNS response with dpkt使用 dpkt 从 DNS 响应中读取 IP 地址和 TTL
【发布时间】:2015-10-05 23:47:08
【问题描述】:

我正在使用 dpkt 来读取 pcap 文件。

        try: dns = dpkt.dns.DNS(udp.data)
        except: continue

        if dns.qr != dpkt.dns.DNS_R: continue
        if dns.opcode != dpkt.dns.DNS_QUERY: continue
        if dns.rcode != dpkt.dns.DNS_RCODE_NOERR: continue
        if len(dns.an) < 1: continue

        for answer in dns.an:
            if answer.type == 5:
                print "CNAME request", answer.name, "\tresponse", answer.cname

我想读取每个答案的 IP 地址和 TTL。我做了dir(answer),但我找不到任何似乎返回响应的 ip 地址/TTL 的东西,而且我在文档中也找不到任何东西。

有办法吗?

【问题讨论】:

    标签: python pcap dpkt


    【解决方案1】:

    From this question

    我假设您正在阅读 pcap 文件,如下所示:

    import dpkt
    import sys
    
    f=file(sys.argv[1],"rb")
    pcap=dpkt.pcap.Reader(f)
    

    从以太网开始单独解析每一层。

    for ts, buf in pcap:
      eth=dpkt.ethernet.Ethernet(buf)
      ip=eth.data
      udp=ip.data
    

    然后从IP头中拉取相关的TTL和IP值。

    TTL 和 IP 值在 IP 标头中,而不是在 DNS 应答中。

    【讨论】:

    • 我认为您不会在 IP 标头中看到 DNS 信息。 IP 层在 DNS 之下
    • 没错。但是您可以在处理 DNS 数据之前解析 IP 标头。
    【解决方案2】:

    RR 对象有一个 ttl 属性,这是您正在寻找的:

    try:
        dns = dpkt.dns.DNS(udp.data)
    except:
        continue
    
        if dns.qr != dpkt.dns.DNS_R: continue
        if dns.opcode != dpkt.dns.DNS_QUERY: continue
        if dns.rcode != dpkt.dns.DNS_RCODE_NOERR: continue
        if len(dns.an) < 1: continue
    
        for answer in dns.an:
            if answer.type == 5:
                print "CNAME request", answer.name, "\tresponse", answer.cname, "\tttl", answer.ttl
    

    【讨论】:

      【解决方案3】:

      (这是一个可悲的迟到的答案。)Bob 您是在询问发送回复的服务器的 IP 地址,还是 CNAME 记录中名称的 IP 地址? DNS 回复的资源记录 (RR) 部分中的规范名称 (CNAME) 数据只有一个域名和一个 TTL。我测试过的名称服务器在不同的附加信息 RR 记录中返回 CNAME 答案的 IP 地址。

      如果你想阅读原文章节:https://www.ietf.org/rfc/rfc1035.txt

      这是一段使用 dpkt 的 Python 代码,可让您生成和探索 DNS 回复的内容。

      import dpkt
      import random
      import socket
      
      # build query
      query_id = int(random.random() * 10000)
      query = dpkt.dns.DNS(id=query_id)
      my_q = dpkt.dns.DNS.Q(name="www.yahoo.com")
      query.qd.append(my_q)
      
      sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      sock.connect(("8.8.8.8", 53))
      sock.send(str(query))
      buf = sock.recv(0xffff)
      
      # parse response
      response = dpkt.dns.DNS(buf)
      if query_id != response.id:
          print "Expected %d but received id %d" % (query_id, response.id)
      elif response.qr != dpkt.dns.DNS_R:
          print "Not a response!"
      elif response.opcode != dpkt.dns.DNS_QUERY:
          print "Not a query op!"
      elif response.rcode != dpkt.dns.DNS_RCODE_NOERR:
          print "Not a successful response!"
      elif len(response.an) == 0:
          print"Response has no answers!"
      else:
          print "%d bytes received, id is %d" % (len(buf), response.id)
          for rr in response.an:
              print "AN: class is %d, type is %d, name is %s" % (rr.cls, rr.type, rr.name)
              if hasattr(rr, 'ip'):
                  print "\tIP is %s" % socket.inet_ntoa(rr.ip)
          for rr in response.ns:
              print "NS: class is %d, type is %d, name is %s" % (rr.cls, rr.type, rr.name)
          for rr in response.ar:
              print "AR: class is %d, type is %d, name is %s" % (rr.cls, rr.type, rr.name)
      

      我看到的结果(坐在东海岸):

      240 bytes received, id is 5848
      AN: class is 1, type is 5, name is www.yahoo.com
      AN: class is 1, type is 1, name is fd-fp3.wg1.b.yahoo.com
          IP is 98.139.180.149
      AN: class is 1, type is 1, name is fd-fp3.wg1.b.yahoo.com
          IP is 98.139.183.24
      NS: class is 1, type is 2, name is wg1.b.yahoo.com
      NS: class is 1, type is 2, name is wg1.b.yahoo.com
      NS: class is 1, type is 2, name is wg1.b.yahoo.com
      NS: class is 1, type is 2, name is wg1.b.yahoo.com
      AR: class is 1, type is 1, name is yf2.yahoo.com
      AR: class is 1, type is 1, name is yf1.yahoo.com
      AR: class is 1, type is 1, name is yf3.a1.b.yahoo.net
      AR: class is 1, type is 1, name is yf4.a1.b.yahoo.net
      

      【讨论】: