python raw sockets achieve a simple sniffer

what:

raw socket, i.e. raw socket, the data may be received on the machine frame or packet network card, for listening to the network traffic analysis and is useful effect.


where:

This may have created a total of socket 4 ways:

1.socket (PF_INET, SOCK_RAW, IPPROTO_TCP | IPPROTO_UDP | IPPROTO_ICMP) transmits and receives data packets ip

socket (AF_INET, SOCK_RAW, IPPROTO_UDP)

The sockets to receive the protocol type (tcp udp icmp, etc.) destined for the machine ip packets, destined for the local not receive non-ip packets (ip soft filter discards data which is not addressed to the local ip package), is transmitted from the unit can not receive the data packet out.

Need to organize tcp udp icmp and other head when you send yourself, you can own packaging to setsockopt ip header.

Suitable for ping program

2.socket (PF_PACKET, SOCK_RAW, htons (ETH_P_IP | ETH_P_ARP | ETH_P_ALL)) transmits the received Ethernet data frames

socket(AF_PACKET, SOCK_RAW, htons(x))

Creating such a socket can monitor all data frames on the network card.

ETH_P_IP 0x800 A receives the machine type mac ip to the data frame

ETH_P_ARP 0x806 only accept the type of the machine destined arp mac data frame

ETH_P_RARP 0x8035 rarp destined only accept the type of the machine frame data mac

ETH_P_ALL 0x3 receiving sent to all types ip arp rarp native mac data frame, receiving all types of data frames sent from the machine. (Case promiscuous mode is enabled, will receive a non destined for the local mac data frame)

3.socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP | ETH_P_ARP | ETH_P_ALL)) transmits the received Ethernet data frames (not including the Ethernet header)

socket(AF_PACKET, SOCK_DGRAM, htons(x))

Function and the second function is similar, but does not include the Ethernet header

He packets may charge non-IP protocols

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))

Generally used for packet capture program


why:

The difference between raw sockets and standard sockets that:

Original socket can not read IP packet processing cores, but can only read data TCP stream socket protocol, a datagram socket can only read data protocol UDP. So, if you want to access additional protocol to send data you must use raw sockets.

Here Insert Picture Description

Here Insert Picture Description

Here Insert Picture Description


how:

Here Insert Picture Description

Here Insert Picture Description

python achieve simple sniffer

  1. NIC in promiscuous mode;
  2. Capture packets;
  3. Analyze packets.
  4. Close promiscuous mode
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)

Analytical ip packet:

Here Insert Picture Description

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)

So far, the light version has been achieved:

Here Insert Picture Description

Published 40 original articles · won praise 2 · Views 2383

Guess you like

Origin blog.csdn.net/qq_42404383/article/details/105219001