python之分解以太幀


  通過了解socket(int domain, int type, int protocol)接口,我們知道利用socket的AF_PACKET

或者PF_PACKET域,和類型SOCK_RAW再加上協議就可以監聽獲得指定協議的以太幀。

      1.獲得各個協議的頭部

  以太協議類型有很多,僅貼上一部分,如下圖:

                                  圖一

更多以太類型見:http://en.wikipedia.org/wiki/EtherType

   本文僅介紹0x0800(IPV4)的監聽與拆分。現在我們就可以利用:

s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))

獲得ipv4協議的以太幀。然后就是接收,並根據協議格式拆分了。先看以太幀格式部分,如下:

                                                                          圖二

  我們接收的數據沒有Preamble部分,此部分被以太網硬件過濾掉了。這里說一下,上圖Type/Length

部分是Ethernet-II才有的type,在原始的IEEE 802.3幀此部分是負載的數據長度,怎樣區分的呢,數值小於

1500表示幀負載數據長度,而>=1536(十六進制0x0600)表示Ethernet-II的type(見圖一ethertype的值)。

  另外提一下vlan類型大小是0x8100,此類型的協議現在使用比較廣泛,格式如下:

                                                                         圖三

vlan tag中有12bit用來表示vlan id的。此處和本文沒有多少關系,主要是應用廣泛介紹一下。繼續正文。

  我們用pkt表示接受的數據,pkt為str類型,通過圖二可知用pkt[:14]包含了目的mac(6 bytes)、

源mac(6 bytes)和Type(2 bytes)。ipv4數據包封裝在以太幀中,下一步看ipv4頭格式:

 

                                                                   圖四

了解更詳細IPv4:http://en.wikipedia.org/wiki/IPv4

從圖四可以知道ipv4最小長度20bytes(每行四字節,共5行),所以通過pkt[14:34]得到其頭部。

由於ipv4之上有Tcp、UDP等協議,這里介紹獲取的TCP數據,在ipv4頭部的protocol為6時即是tcp包。

TCP header如下:

                                                                     圖五

Tcp頭部最小也是20bytes,所以tcp_header=pkt[34:54]

  2.獲得每個協議的每個字段

  在此之前,要說一個問題。比如要把4存進int型的低8位,在python中這個還好說,再去取來也

沒什么難度。但是如果把4存進2bytes的數中或者從保存4的2bytes str類型中獲得4,就沒有c等語言

簡單。這里介紹struct模塊,有了它,一切就簡單了!我們通過如下:

tcp_h=struct.unpack("<HHIIbbHHH", tcp_header)

此方法就得到了tcp頭部的個部分信息。

  首先"<HHIIbbHHH"中的'<'表示開始部分,還可以是 '>'、'!' 或者 '='。H表示無符號16位,

I表示unsigned int,b表示signed char。所以HHII分別是source port(16bits)、Destination port(16bits)、

Sequence number(32bits)、Ack number(32bits)(看圖五),bbHHH同理。

  根據你設置的格式化字符串unpack()返回對應長度的數組,比如上面的“HHIIbbHHH”(9個字符)

就會返回長度為9的數組,並且每個元素都是int型。

  同理,對於以太幀頭部和ipv4頭部處理與tcp header類似。

  更詳細的格式化字符對照如下:

  3.代碼實現

  通過上面講述實現主體代碼如下:

 

 1 ipv4=0x0800
 2 udptype=0x11
 3 tcptype=0x06
 4 bufsize=1500
 5 s=socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(ipv4))
 6 
 7 while True:
 8     pkt=s.recv(bufsize)
 9     if len(pkt)<=0:
10         break
11     elif len(pkt)>54:
12         ether_header = pkt[0:14]
13         ip_header  = pkt[14:34]        
14         ether_h = struct.unpack("!6s6s2s",ether_header)
15         ip_h  = struct.unpack("<bbHHHbbHII",ip_header)        
16         ip  = IPv4Parser(ip_h) #做位運算等處理 17         if ip.protocol==tcptype: #判斷是否為tcp包
18             tcp_header = pkt[34:54]
19             tcp_h = struct.unpack("<HHIIbbHHH", tcp_header)
20             tcp = TCPParser(tcp_h)
21             print ip.sourceip()+':'+str(tcp.sport)+'-->'+ip.destinationip()+\
22                 ':'+str(tcp.dport)

 16、17行用了兩個類對ip和tcp頭部解析,如下:

 1 import os,socket
 2 import struct
 3 class IPv4Parser:
 4     def __init__(self,ip):
 5         self.ip=ip
 6     @property
 7     def version(self):
 8         v=self.ip[0]>>4
 9         return v
10     @property
11     def headerLen(self):
12         l=(self.ip[0]&0x000f)*4
13         return l
    @property
    def protocol(self):
      return self.ip[6]
14 def sourceip(self): 15 sip=self.__getstrip(self.ip[8]) 16 return sip 17 def destinationip(self): 18 dip=self.__getstrip(self.ip[9]) 19 return dip 20 def totalLen(self): 21 return ((self.ip[2]&0xff)<<8)|((self.ip[2]>>8)&0xff)
22 def checksum(self): 23 pass 24 def __getstrip(self,intip): 25 strip=str(intip&0xff)+'.'+str((intip>>8)&0xff)+'.'+\ 26 str((intip>>16)&0xff)+'.'+str((intip>>24)&0xff) 27 return strip 28 class TCPParser: 29 def __init__(self,tcp): 30 self.tcp=tcp 31 @property 32 def sport(self): 33 sp=self.tcp[0] 34 return ((sp&0xff)<<8)|(sp>>8) 35 @property 36 def dport(self): 37 return ((self.tcp[1]&0xff)<<8)|(self.tcp[1]>>8)
38 @property 39 def headerLen(self): 40 return ((self.tcp[4]>>4)&0x0f)*4

  上面並沒有解析ip和tcp header的所有部分,當然你可以補全,解析頭部注意字節序

  把上面兩處代碼放在一個文件中沒意外就可以運行了,注意需要root權限。運行輸出的

信息如下,當然也可以輸出更詳細的信息。

  我們完全可以更進一步,對於tcp上層的協議比如http繼續解包。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM