使用底層套接字解碼底層流量,是這次做的重點工作。
首先來捕獲第乙個包
#coding:utf-8
import
socket
#監聽的主機ip
host = "
192.168.1.100
"socket_protocol =socket.ipproto_icmp
sniffer =socket.socket(socket.af_inet, socket.sock_raw, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.ipproto_ip, socket.ip_hdrincl, 1)
raw_buffer = sniffer.recvfrom(65535)
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兩個庫實現這一點。
#coding:utf-8
import
socket
import
struct
from ctypes import *
#監聽的主機ip
host = "192.168.1.100"
#ip頭定義
class
ip(structure):
_fields_ =[
("ihl
", c_ubyte, 4),
("version
", c_ubyte, 4),
("tos
", c_ubyte),
("len
", c_ushort),
("id
", c_ushort),
("offset
", c_ushort),
("ttl
", c_ubyte),
("protocol_num
", c_ubyte),
("sum
", c_ushort),
("src
", c_uint),
("dst
", c_uint),
]def__new__(self, socket_buffer=none):
return
self.from_buffer_copy(socket_buffer)
def__init__(self, socket_buffer=none):
self.protocol_map =
#readable ip address
self.src_address = socket.inet_ntoa(struct.pack("
", self.src))
self.dst_address = socket.inet_ntoa(struct.pack("
", self.dst))
#type of protocol
try:
self.protocol =self.protocol_map[self.protocol_num]
except
: self.protocol =str(self.protocol_num)
socket_protocol =socket.ipproto_icmp
sniffer =socket.socket(socket.af_inet, socket.sock_raw, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.ipproto_ip, socket.ip_hdrincl, 1)
try:
while
true:
raw_buffer = sniffer.recvfrom(65535)[0]
ip_header = ip(raw_buffer[:20])
"protocol: %s %s -> %s
" %(ip_header.protocol, ip_header.src_address, ip_header.dst_address)
except
keyboardinterrupt:
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 address
self.src_address = socket.inet_ntoa(struct.pack("
", self.src))
self.dst_address = socket.inet_ntoa(struct.pack("
", self.dst))
7. 乙個接收icmp包的伺服器,沒什麼說的。
8. 無限迴圈監聽指定埠,將recvfrom收到的資料的第一部分 也就是不要ip位址的部分傳遞給raw_buffer
9. ip頭raw_buffer的前20個位元組傳遞給結構體進行解碼。
10. 然後列印。
可以看到大致思路就是,將原型socket資料拿過來,然後通過模擬c語言的結構體,使用python的庫對這個格式的包進行一一對應的解碼,將解碼之後的資料列印出來。
到此為止可以看到,在ip層已經可以解析出資料報從哪兒去哪兒的資訊。
python使用原始套接字 解析原始ip頭資料
使用底層套接字解碼底層流量,是這次做的重點工作。首先來捕獲第乙個包 1 coding utf 8import socket23 監聽的主機ip 4 host 192.168.1.100 5 6 socket protocol socket.ipproto icmp 78 sniffer socket...
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 而這些資料報都是由系統提供的協議棧實現,使用者只需要填充應用層報文即可,由系統完成底層報文頭的填充並傳送。然而在某些情況下需...