python原始套接字实现简单的sniffer

what:

raw socket,即原始套接字,可以接收本机网卡上的数据帧或者数据包,对于监听网络的流量和分析是很有作用的。


where:

一共可以有4种方式创建这种socket:

1.socket(PF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包

socket(AF_INET, SOCK_RAW, IPPROTO_UDP);

该套接字可以接收协议类型为(tcp udp icmp等)发往本机的ip数据包、不能收到非发往本地ip的数据包(ip软过滤会丢弃这些不是发往本机ip的数据包)、不能收到从本机发送出去的数据包。

发送时需要自己组织tcp udp icmp等头部、可以setsockopt来自己包装ip头部。

适用于ping程序

2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧

socket(AF_PACKET, SOCK_RAW, htons(x))

创建这种套接字可以监听网卡上的所有数据帧。

ETH_P_IP 0x800 只接收发往本机mac的ip类型的数据帧

ETH_P_ARP 0x806 只接受发往本机mac的arp类型的数据帧

ETH_P_RARP 0x8035 只接受发往本机mac的rarp类型的数据帧

ETH_P_ALL 0x3 接收发往本机mac的所有类型ip arp rarp的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)

3.socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧(不包括以太网头部)

socket(AF_PACKET, SOCK_DGRAM, htons(x))

功能与第二种功能类似,但是不包括以太网头部

他可以收取非IP协议的数据包

4.socket(PF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))

socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))

一般用于抓包程序


why:

原始套接字与标准套接字的区别在于:

原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


how:

在这里插入图片描述

在这里插入图片描述

python实现简易的sniffer

  1. 把网卡置于混杂模式;
  2. 捕获数据包;
  3. 分析数据包.
  4. 关闭混杂模式
import socket

# the public network interface
HOST = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print(s.recvfrom(65565))

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

解析ip数据包:

在这里插入图片描述

import socket

#抓捕
def sniffIpData():
    host_ip = socket.gethostbyname(socket.gethostname())            #获取IP
    sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)       #创建套接字、可接受协议类型为UDP、TCP、ICMP、IP
    sniffer.bind((host_ip, 0))
    sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)         #设置套接字options、包装ip头部
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)          #receive all package
    recv_data, addr = sniffer.recvfrom(1500)
	s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)			# disabled promiscuous mode
    sniffer.close()
    return recv_data

#解析
def decodeIpData(package):
    ip_data = {}
    #RFC791
    ip_data['version'] = package[0] >> 4
    ip_data['headLength'] = package[0] & 0x0f           #& 按位与操作
    ip_data['DSField'] = package[1]
    ip_data['totalLength'] = (package[2] << 8) + package[3]
    ip_data['identification'] = (package[4] << 8) + package[5]
    ip_data['flag'] = package[6] >> 5
    ip_data['moreFragment'] = ip_data['flag'] & 1
    ip_data['dontFragment'] = (ip_data['flag'] >> 1) & 1
    ip_data['fragmentOffset'] = ((package[6] & 0x1f) << 8) + package[7]
    ip_data['TTL'] = package[8]
    ip_data['protocol'] = package[9]
    ip_data['headerCheckSum'] = (package[10] << 8) + package[11]
    #以IP地址形式存储
    ip_data['sourceAddress'] = "%d.%d.%d.%d" % (package[12], package[13], package[14], package[15])
    ip_data['destinationAddress'] = "%d.%d.%d.%d" % (package[16], package[17], package[18], package[19])
    ip_data['options'] = []
    #根据headerLength求出options
    if ip_data['headLength'] > 5:           #一般来说此处的值为0101,表示头长度为20字节、若超出则大于5(0101)
        temp = 5
        while temp < ip_data['headLength']:
            ip_data['options'].append(package[temp * 4] + 0)
            ip_data['options'].append(package[temp * 4] + 1)
            ip_data['options'].append(package[temp * 4] + 2)
            ip_data['options'].append(package[temp * 4] + 3)
            temp += 1
    #根据totalLength求出data
    ip_data['data'] = []
    temp = ip_data['headLength'] * 4
    while temp < ip_data['totalLength']:
        ip_data['data'].append(package[temp])
        temp += 1
    return ip_data

package = sniffIpData()
data_decode = decodeIpData(package)
# for i, k in data_decode:
#     print("%d:%d" % (i, k))
for key in data_decode.items():
    print(key)

至此、简易版本的已经实现:

在这里插入图片描述

发布了40 篇原创文章 · 获赞 2 · 访问量 2383

猜你喜欢

转载自blog.csdn.net/qq_42404383/article/details/105219001