標籤:while 一點 net port 並且 version try pass read
使用底層通訊端解碼底層流量,是這次做的重點工作。
首先來捕獲第一個包
1 # coding:utf-8import socket 2 3 # 監聽的主機IP 4 host = "192.168.1.100" 5 6 socket_protocol = socket.IPPROTO_ICMP 7 8 sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 9 sniffer.bind((host, 0))10 sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)11 12 raw_buffer = sniffer.recvfrom(65535)13 print raw_buffer
下面一行一行解釋上面代碼的意思。
1. 匯入socket包
2. 需要監聽的本機ip地址
3. 給socket_protocol變數賦值icmp變數
4. 為sniffer變數建立一個soket對象,該對象為ipv4 原始通訊端並指定其協議為icmp
5. 綁定到指定地址和連接埠進行監聽
6. 為sniffer通訊端設定選項參數,使其攜帶ip頭
7. 將監聽連接埠的通訊端收到的未經處理資料賦值給raw_buffer
8. 列印raw_buffer的值
這個時候,我們使用root許可權運行這個指令碼,並且開啟另外一個terminal對任意一個地址發送icmp包,我們監聽的介面的recvfrom 會收到回監聽回包到指定地址。recvfrom與recv不同的是 recvfrom會同時接收回包地址。(string, address)的格式
這個時候我們可以看到列印出來的值,是一堆完全看不懂的東西,因為是沒有解碼的狀態,下面我們將對ip頭進行解碼。
使用python的struct和ctypes兩個庫實現這一點。
1 # coding:utf-8import socket 2 import struct 3 from ctypes import * 4 5 # 監聽的主機IPhost = "192.168.1.100" 6 7 # IP頭定義 8 class IP(Structure): 9 _fields_ = [10 ("ihl", c_ubyte, 4),11 ("version", c_ubyte, 4),12 ("tos", c_ubyte),13 ("len", c_ushort),14 ("id", c_ushort),15 ("offset", c_ushort),16 ("ttl", c_ubyte),17 ("protocol_num", c_ubyte),18 ("sum", c_ushort),19 ("src", c_uint),20 ("dst", c_uint),21 ]22 23 def __new__(self, socket_buffer=None):24 return self.from_buffer_copy(socket_buffer)25 26 def __init__(self, socket_buffer=None):27 self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"}28 29 # readable ip address30 self.src_address = socket.inet_ntoa(struct.pack("<I", self.src))31 self.dst_address = socket.inet_ntoa(struct.pack("<I", self.dst))32 33 # type of protocol34 try:35 self.protocol = self.protocol_map[self.protocol_num]36 except:37 self.protocol = str(self.protocol_num)38 39 socket_protocol = socket.IPPROTO_ICMP40 41 sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)42 sniffer.bind((host, 0))43 sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)44 45 try:46 while True:47 raw_buffer = sniffer.recvfrom(65535)[0]48 49 ip_header = IP(raw_buffer[:20])50 51 print "Protocol: %s %s -> %s " % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)52 53 except KeyboardInterrupt:54 pass
1. 匯入各模組
2. 監聽的本機ip地址
3. 使用ctypes 構造一個解析ip頭的結構體(structure) IP
4. 使用from_buffer_copy方法在__new__方法將收到的資料產生一個IP class的執行個體
5. __init__方法初始化一部分資料儲存到對應的執行個體屬性值中。
6. 特別說明下面代碼, 使用了python struct庫的pack方法 用指定的格式化參數將src 和dst的long型數值轉換為字串,然後使用socket.inet_ntoa方法將字串的一串數字轉換為對應的ip格式。最後賦值給對應的src或者dst變數
# readable ip addressself.src_address = socket.inet_ntoa(struct.pack("<I", self.src))self.dst_address = socket.inet_ntoa(struct.pack("<I", self.dst))
7. 一個接收icmp包的伺服器,沒什麼說的。
8. 無限迴圈監聽指定連接埠,將recvfrom收到的資料的第一部分 也就是不要ip地址的部分傳遞給raw_buffer
9. ip頭raw_buffer的前20個位元組傳遞給結構體進行解碼。
10. 然後列印。
可以看到大致思路就是,將原型socket資料拿過來,然後通過類比c語言的結構體,使用python的庫對這個格式的包進行一一對應的解碼,將解碼之後的資料列印出來。
到此為止可以看到,在ip層已經可以解析出資料包從哪兒去哪兒的資訊。
python使用原始通訊端 解析原始ip頭資料