Python之原始套接字流量嗅探

windows 和linux单个包嗅探

#-*-coding:utf-8-*-
import socket
import os
 
#监听的主机
host = "192.168.2.249"
 
#创建原始套接字,并绑定
if os.name == "nt":#判断系统平台
    socket_protocol = socket.IPPROTO_IP
else:
    socket_protocol = socket.IPPROTO_ICMP
 
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 
 
sniffer.bind((host, 0))
#捕获的时候包含IP头
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
 
#win下开启IOCTL启用混杂模式
if os.name  == "nt":
    sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
 
print sniffer.recvfrom(65565)
 
#对应关闭
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF

 

IP头结构

后面使用CTYPES模块创建类C结构
然后使用PYTHON套接字对IP头解密。
先简单了解下IP头结构

IP头部,总长度20字节

typedef struct _ip_hdr
{
#if LITTLE_ENDIAN
unsigned char ihl:4;    //首部长度
unsigned char version:4, //版本
unsigned char version:4, //版本
unsigned char ihl:4;    //首部长度
unsigned char tos;    //服务类型
unsigned short tot_len; //总长度
unsigned short id;     //标志
unsigned short frag_off; //分片偏移
unsigned char ttl;    //生存时间
unsigned char protocol; //协议
unsigned short chk_sum; //检验和
struct in_addr srcaddr; //源IP地址
struct in_addr dstaddr; //目的IP地址
}ip_hdr;

PYTHON代码

#-*-coding:utf-8-*-
import socket
import os
import struct
from ctypes import *
 
 
#监听主机
host = "192.168.2.249"
 
#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_ulong),
        ("dst",     c_ulong)
    ]
 
    def __new__(self,socket_buffer=None):
        return self.from_buffer_copy(socket_buffer)
 
    def __init__(self,socket_buffer=None):
 
        #协议字段跟协议名对应,常见的有如:
        #1 ICMP 
        #2 IGMP 
        #6 TCP 
        #17 UDP 
        #88 IGRP 
        #89 OSPF
        self.protocol_map = {1:"ICMP",6:"TCP",17:"UDP"}
        #转换下可读性更强的IP地址
        self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
        #协议类型
        try:
            self.protocol = self.protocol_map[self.protocol_num]
        except:
            self.protocol = str(self.protocol_num)
 
#创建原始套接字,并绑定,跟之前的代码差不多
if os.name == "nt":
    socket_protocol = socket.IPPROTO_IP
else:
    socket_protocol = socket.IPPROTO_ICMP
 
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 
 
sniffer.bind((host, 0))
#捕获的时候包含IP头
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
 
if os.name  == "nt":
    sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
 
try:
    while True:
        #读取数据包
        raw_buffer = sniffer.recvfrom(65565)[0]
        #将缓冲数据的前20字节按IP头格式解析
        ip_header = IP(raw_buffer[0:20])
        #输出双方IP
        print "Protocol:%s %s -> %s" % (ip_header.protocol,
                                        ip_header.src_address,
                                        ip_header.dst_address)
except KeyboardInterrupt:
    if os.name == "nt":
        sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

开启上面代码,另一个终端随便PING一个地址,
WINDOWS下可以捕获TCP跟UDP,linux下只能捕获ICMP

效果:

ping www.baidu.com
PING www.a.shifen.com (14.215.177.38) 56(84) bytes of data.
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=1 ttl=56 time=13.2 ms
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=2 ttl=56 time=14.0 ms
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=3 ttl=56 time=13.4 ms
64 bytes from 14.215.177.38 (14.215.177.38): icmp_seq=4 ttl=56 time=13.4 ms
root@myspuerkali:~/python# python '/root/python/sniffer_ip_haader_decode.py' 
Protocol:ICMP 14.215.177.38 -> 192.168.2.249
Protocol:ICMP 14.215.177.38 -> 192.168.2.249
Protocol:ICMP 14.215.177.38 -> 192.168.2.249
Protocol:ICMP 14.215.177.38 -> 192.168.2.249
Protocol:ICMP 14.215.177.38 -> 192.168.2.249

总结

具体IP头结构详细解析自行百度,
后面会根据这前提来解析ICMP,跟制作一个扫描主机存活的工具

发表评论

邮箱地址不会被公开。 必填项已用*标注