• Python解析DNS数据包


    工作中有时需要对DNS数据包进行解析,抽取出其中的Qurey Name和Answer中的IP地址,今天写了一个简单的脚本分析PCAP包中的DNS,用到了dpkt模块。

    我只抽取了关键的Query Name和Answer中的IP地址,没有解析授权和额外信息。

    如果不想写脚本,可以使用tshark工具(wireshark的命令行版本),使用简单的命令行即可抽取想要的信息。但是tshark在抽取IP地址的时候,会将授权域和额外域中的IP地址也会一起抽取出来,难以区分。

      1 #!/usr/bin/python
      2 #coding = utf-8
      3 import struct
      4 import dpkt
      5 import sys
      6 import socket
      7 import binascii
      8 
      9 DNS_Q = 0
     10 DNS_R = 1
     11 
     12 # Opcodes
     13 DNS_QUERY = 0
     14 DNS_IQUERY = 1
     15 DNS_STATUS = 2
     16 DNS_NOTIFY = 4
     17 DNS_UPDATE = 5
     18 
     19 # Flags
     20 DNS_CD = 0x0010 # checking disabled
     21 DNS_AD = 0x0020 # authenticated data
     22 DNS_Z =  0x0040 # unused
     23 DNS_RA = 0x0080 # recursion available
     24 DNS_RD = 0x0100 # recursion desired
     25 DNS_TC = 0x0200 # truncated
     26 DNS_AA = 0x0400 # authoritative answer
     27 
     28 # Response codes
     29 DNS_RCODE_NOERR = 0
     30 DNS_RCODE_FORMERR = 1
     31 DNS_RCODE_SERVFAIL = 2
     32 DNS_RCODE_NXDOMAIN = 3
     33 DNS_RCODE_NOTIMP = 4
     34 DNS_RCODE_REFUSED = 5
     35 DNS_RCODE_YXDOMAIN = 6
     36 DNS_RCODE_YXRRSET = 7
     37 DNS_RCODE_NXRRSET = 8
     38 DNS_RCODE_NOTAUTH = 9
     39 DNS_RCODE_NOTZONE = 10
     40 
     41 # RR types
     42 DNS_A = 1
     43 DNS_NS = 2
     44 DNS_CNAME = 5
     45 DNS_SOA = 6
     46 DNS_PTR = 12
     47 DNS_HINFO = 13
     48 DNS_MX = 15
     49 DNS_TXT = 16
     50 DNS_AAAA = 28
     51 DNS_SRV = 33
     52 
     53 # RR classes
     54 DNS_IN = 1
     55 DNS_CHAOS = 3
     56 DNS_HESIOD = 4
     57 DNS_ANY = 255
     58 
     59 def addr2str(addrobj):
     60     if len(addrobj) != 4:
     61         return "addr error!"
     62     else:
     63         return str(ord(addrobj[0]))+"."+str(ord(addrobj[1]))+"."+str(ord(addrobj[2]))+"."+str(ord(addrobj[3]))
     64 
     65 def TCPorUDP(obj):
     66     if (ord(obj) == 0x01):
     67         return "ICMP"
     68     elif (ord(obj) == 0x02):
     69         return "IGMP"
     70     elif (ord(obj) == 0x06):
     71         return "TCP"
     72     elif (ord(obj) == 0x08):
     73         return "EGP"
     74     elif (ord(obj) == 0x09):
     75         return "IGP"
     76     elif (ord(obj) == 0x11):
     77         return "UDP"
     78     elif (ord(obj) == 41):
     79         return "IPv6"
     80     elif (ord(obj) == 89):
     81         return "OSPF"
     82     else:
     83         return "error"
     84 
     85 def dns_response_body_parse(body):        # parse the response message's body
     86     identification = body[0:2]
     87     flag = body[2:4]
     88     num_ques = body[4:6]
     89     num_ans_RR = body[6:8]
     90     num_auth_RR = body[8:10]
     91     num_addi_RR = body[10:12]
     92     query_name = ''
     93     ans_ip = []
     94     flag = 12
     95     while(ord(body[flag])!=0x0):
     96         query_name = query_name + body[flag+1:flag+ord(body[flag])+1]
     97         flag = flag + ord(body[flag]) + 1
     98         try:
     99             if ord(body[flag]) != 0x0:
    100                 query_name = query_name+'.'
    101         except Exception, e:
    102             print "error when parse query domain name"
    103     #print query_name
    104     flag = flag + 1
    105     query_type = ord(body[flag])*256 + ord(body[flag+1])
    106     if query_type == 0x01:            # use domain query IP addr
    107         flag = flag + 4
    108         i = 1
    109         answer_num = ord(num_ans_RR[0])*256 + ord(num_ans_RR[1])
    110         while(i<=answer_num):
    111             if ord(body[flag]) == 0xc0:
    112                 flag = flag + 2
    113             else:
    114                 while(ord(body[flag])!=0x0):
    115                     flag = flag + ord(body[flag]) + 1
    116                 flag = flag + 1
    117             if (    ord(body[flag])*256+ord(body[flag+1]) == DNS_A 
    118                 and ord(body[flag+2])*256+ord(body[flag+3]) == DNS_IN):
    119                 flag = flag + 8
    120                 RR_data_len = ord(body[flag])*256 + ord(body[flag+1])
    121                 if RR_data_len == 4:
    122                     ans_ip.append(addr2str(body[flag+2:flag+6]))
    123                 flag = flag + ord(body[flag])*256 + ord(body[flag+1]) + 2
    124             else:
    125                 flag = flag + 8
    126                 flag = flag + ord(body[flag])*256 + ord(body[flag+1]) + 2
    127             i = i + 1
    128     else:
    129         print "query type is PTR not A"
    130         return
    131     return "%s	%s"%(query_name,ans_ip)
    132 
    133 def main():
    134     paralen = len(sys.argv)
    135     if paralen != 3:
    136         print ("there is only %d parameter, %s"%(paralen,sys.argv))
    137         print "no enough parameter!"
    138         print "command should be: python *.py result.txt src_pcap_file.pcap"
    139         return
    140 
    141     print "parse result will write to:"+sys.argv[1]
    142     print "strat parse the pcap file:"+sys.argv[2]
    143 
    144     fw = open(sys.argv[1],"w")
    145     f = file(sys.argv[2],"rb")
    146     pcap = dpkt.pcap.Reader(f)
    147     for ts,buf in pcap:
    148         #fw.writelines("timestamp:"+str(ts)+"	packet len:"+str(len(buf))+"
    ")
    149         ethheader = buf[0:14]
    150         dstmac = ethheader[0:6]
    151         srcmac = ethheader[6:12]
    152         netlayer_type = ethheader[12:14]
    153         #fw.writelines("dstMAC:"+str(binascii.b2a_hex(dstmac))+"	srcMAC:"+str(binascii.b2a_hex(srcmac))+"
    ")
    154 
    155         pktheader = buf[14:34]
    156         trans_type = pktheader[9]
    157         srcip = pktheader[12:16]
    158         dstip = pktheader[16:20]
    159 
    160         #fw.writelines("dstIP:"+addr2str(dstip)+"	srcIP:"+addr2str(srcip)+"
    ")
    161         #fw.writelines("packet type:"+TCPorUDP(trans_type)+"
    ")
    162 
    163         if (ord(trans_type) == 0x11):     #UDP
    164             udpheader = buf[34:42]
    165             srcport = udpheader[0:2]
    166             dstport = udpheader[2:4]
    167             udplen = udpheader[4:6]
    168             #fw.writelines("srcport:"+str(ord(srcport[1])+ord(srcport[0])*16*16)+"	dstport:"+str(ord(dstport[1])+ord(dstport[0])*16*16)+"
    
    ")
    169             bodylen = ord(udplen[0])*256+ord(udplen[1])-8
    170             print "
    dns body length is "+str(bodylen)
    171             dnsbody = buf[42:(42+bodylen)]
    172             if (ord(dstport[0]) == 0x00 and ord(dstport[1]) == 0x35):
    173                 print "this is a DNS Request"
    174             elif (ord(srcport[0]) == 0x00 and ord(srcport[1]) == 0x35):
    175                 print "this is a DNS Response"
    176                 fw.writelines(dns_response_body_parse(dnsbody)+"
    ")    # wirte result to file
    177             else:
    178                 print ord(srcport[0]),ord(srcport[0])
    179         elif (ord(trans_type) == 0x06):     #TCP
    180             tcpheader = buf[34:54]
    181             srcport = tcpheader[0:2]
    182             dstport = tcpheader[2:4]
    183             #fw.writelines("srcport:"+str(ord(srcport[1])+ord(srcport[0])*16*16)+"	dstport:"+str(ord(dstport[1])+ord(dstport[0])*16*16)+"
    
    ")
    184     f.close()
    185     print ("process %s has finished, the result was in file %s"%(sys.argv[2],sys.argv[1]))
    186 if __name__ == "__main__":
    187     main()
  • 相关阅读:
    网站是HTTP?10分钟变成HTTPS!域名免费添加配置SSL证书,变成https//环境
    纯JS实现在一个字符串b中查找另一个字符串a出现的所有位置,并且不使用字符串的方法(递归)
    网站怎么上传到服务器流程,从本地到服务器上线过程并通过域名(IP地址)进行访问
    html5新特性-header,nav,footer,aside,article,section等各元素的详解
    Django2.2中间件详解
    掌握使用gitlab ci构建Android包的正确方式
    回想让你最有成就感的bug是什么?你是如何发现这个bug的?
    聊聊用Selenium做自动化碰到了哪些坑?都是怎么解决的?
    关于手机淘宝3.25bug我的一些思考与建议
    用docker搭建selenium grid分布式环境实践之路
  • 原文地址:https://www.cnblogs.com/yulele/p/3721305.html
Copyright © 2020-2023  润新知