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
3import struct
4import dpkt
5import sys
6import socket
7import 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
59def addr2str(addrobj):
60if len(addrobj) != 4:
61return"addr error!"
62else:
63return str(ord(addrobj[0]))+"."+str(ord(addrobj[1]))+"."+str(ord(addrobj[2]))+"."+str(ord(addrobj[3]))
64
65def TCPorUDP(obj):
66if (ord(obj) == 0x01):
67return"ICMP"
68elif (ord(obj) == 0x02):
69return"IGMP"
70elif (ord(obj) == 0x06):
71return"TCP"
72elif (ord(obj) == 0x08):
73return"EGP"
74elif (ord(obj) == 0x09):
75return"IGP"
76elif (ord(obj) == 0x11):
writelines使用方法python77return"UDP"
78elif (ord(obj) == 41):
79return"IPv6"
80elif (ord(obj) == 89):
81return"OSPF"
82else:
83return"error"
84
85def 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
95while(ord(body[flag])!=0x0):
96 query_name = query_name + body[flag+1:flag+ord(body[flag])+1]
97 flag = flag + ord(body[flag]) + 1
98try:
99if ord(body[flag]) != 0x0:
100 query_name = query_name+'.'
101except Exception, e:
102print"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])
106if 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])
110while(i<=answer_num):
111if ord(body[flag]) == 0xc0:
112 flag = flag + 2
113else:
114while(ord(body[flag])!=0x0):
115 flag = flag + ord(body[flag]) + 1
116 flag = flag + 1
117if ( ord(body[flag])*256+ord(body[flag+1]) == DNS_A
118and 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])
121if 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
124else:
125 flag = flag + 8
126 flag = flag + ord(body[flag])*256 + ord(body[flag+1]) + 2
127 i = i + 1
128else:
129print"query type is PTR not A"
130return
131return"%s\t%s"%(query_name,ans_ip)
132
133def main():
134 paralen = len(sys.argv)
135if paralen != 3:
136print ("there is only %d parameter, %s"%(paralen,sys.argv))
137print"no enough parameter!"
138print"command should be: python *. src_pcap_file.pcap"
139return
140
141print"parse result will write to:"+sys.argv[1]
142print"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)
147for ts,buf in pcap:
148#fw.writelines("timestamp:"+str(ts)+"\tpacket len:"+str(len(buf))+"\n")
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))+"\tsrcMAC:"+str(binascii.b2a_hex(srcmac))+"\n") 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)+"\tsrcIP:"+addr2str(srcip)+"\n")
161#fw.writelines("packet type:"+TCPorUDP(trans_type)+"\n")
162
163if (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)+"\tdstport:"+str(ord(dstport[1])+ord(dstport[0])*16*16)+"\n\n") 169 bodylen = ord(udplen[0])*256+ord(udplen[1])-8
170print"\ndns body length is "+str(bodylen)
171 dnsbody = buf[42:(42+bodylen)]
172if (ord(dstport[0]) == 0x00 and ord(dstport[1]) == 0x35):
173print"this is a DNS Request"
174elif (ord(srcport[0]) == 0x00 and ord(srcport[1]) == 0x35):
175print"this is a DNS Response"
176 fw.writelines(dns_response_body_parse(dnsbody)+"\n") # wirte result to file
177else:
178print ord(srcport[0]),ord(srcport[0])
179elif (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)+"\tdstport:"+str(ord(dstport[1])+ord(dstport[0])*16*16)+"\n\n") 184 f.close()
185print ("process %s has finished, the result was in file %s"%(sys.argv[2],sys.argv[1]))
186if__name__ == "__main__":
187 main()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论