使用底層套接字解碼底層流量,是這次做的重點工作。
首先來捕獲第乙個包
1#coding:utf-8import socket23
#監聽的主機ip
4 host = "
192.168.1.100"5
6 socket_protocol =socket.ipproto_icmp
78 sniffer =socket.socket(socket.af_inet, socket.sock_raw, socket_protocol)
9sniffer.bind((host, 0))
10 sniffer.setsockopt(socket.ipproto_ip, socket.ip_hdrincl, 1)
1112 raw_buffer = sniffer.recvfrom(65535)
13print 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
2import
struct
3from ctypes import *45
#監聽的主機iphost = "192.168.1.100"67
#ip頭定義
8class
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]
2223
def__new__(self, socket_buffer=none):
24return
self.from_buffer_copy(socket_buffer)
2526
def__init__(self, socket_buffer=none):
27 self.protocol_map =
2829
#readable ip address
30 self.src_address = socket.inet_ntoa(struct.pack("
", self.src))
31 self.dst_address = socket.inet_ntoa(struct.pack("
", self.dst))
3233
#type of protocol
34try
:35 self.protocol =self.protocol_map[self.protocol_num]
36except
:37 self.protocol =str(self.protocol_num)
3839 socket_protocol =socket.ipproto_icmp
4041 sniffer =socket.socket(socket.af_inet, socket.sock_raw, socket_protocol)
42sniffer.bind((host, 0))
43 sniffer.setsockopt(socket.ipproto_ip, socket.ip_hdrincl, 1)
4445
try:
46while
true:
47 raw_buffer = sniffer.recvfrom(65535)[0]
4849 ip_header = ip(raw_buffer[:20])
5051
"protocol: %s %s -> %s
" %(ip_header.protocol, ip_header.src_address, ip_header.dst_address)
5253
except
keyboardinterrupt:
54pass
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 address
self.src_address = socket.inet_ntoa(struct.pack("7. 乙個接收icmp包的伺服器,沒什麼說的。
8. 無限迴圈監聽指定埠,將recvfrom收到的資料的第一部分 也就是不要ip位址的部分傳遞給raw_buffer
9. ip頭raw_buffer的前20個位元組傳遞給結構體進行解碼。
10. 然後列印。
可以看到大致思路就是,將原型socket資料拿過來,然後通過模擬c語言的結構體,使用python的庫對這個格式的包進行一一對應的解碼,將解碼之後的資料列印出來。
到此為止可以看到,在ip層已經可以解析出資料報從哪兒去哪兒的資訊。
python使用原始套接字 解析原始ip頭資料
使用底層套接字解碼底層流量,是這次做的重點工作。首先來捕獲第乙個包 coding utf 8 import socket 監聽的主機ip host 192.168.1.100 socket protocol socket.ipproto icmp sniffer socket.socket sock...
python使用原始套接字 解析原始ip頭資料
使用底層套接字解碼底層流量,是這次做的重點工作。首先來捕獲第乙個包 coding utf 8 import socket 監聽的主機ip host 192.168.1.100 socket protocol socket.ipproto icmp sniffer socket.socket sock...
原始套接字
資料出處 實際上,我們常用的網路程式設計都是在應用層的報文的收發操作,也就是大多數程式設計師接觸到的流式套接字 sock stream 和資料報式套接字 sock dgram 而這些資料報都是由系統提供的協議棧實現,使用者只需要填充應用層報文即可,由系統完成底層報文頭的填充並傳送。然而在某些情況下需...