Packet sniffer in Python

2019-07-19 09:09发布

问题:

I want to do a packet sniffer in Python 3.5 which captures UDP, TCP and ICMP. This is a short example of it:

 import socket
 import struct

# 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
n=1
while(n<=400):
    print('Number ', n)
    data=s.recvfrom(65565)
    packet=data[0]
    address= data[1]
    header=struct.unpack('!BBHHHBBHBBBBBBBB', packet[:20])
    if(header[6]==6): #header[6] is the field of the Protocol
        print("Protocol = TCP")
    elif(header[6]==17):
        print("Protocol = UDP")
    elif(header[5]==1):
        print("Protocol = ICMP") 
    n=n+1

The problem is that it only captures UDP packets :( Output:

Number  1 Protocol = UDP Number  2 Protocol = UDP Number  3 Protocol = UDP Number  4 Protocol = UDP Number  5 Protocol = UDP Number  6 Protocol = UDP Number  7

There are 2 options:

  • The sniffer can only capture UDP packets.
  • I'm just receiving UDP packets.

I think that the most logical answer is my sniffer doesn't work correctly and it's just capturing UDP. Any idea?

回答1:

I myself am in the stage of creating a python packet parser/sniffer and in my research I found that, to be able parse all the incoming packets like TCP, ICMP, UDP, ARP ..etc., you must not use the below socket type because socket.IPPROTO_IP gives out only IP packets and is a dummy protocol

s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)

rather you must use this and works best with Linux systems

s = socket.socket( socket.AF_PACKET , socket.SOCK_RAW , socket.ntohs(0x0003))


回答2:

You are using "gethostbyname" and this method obtains one between all ip adresses in your computer. In place of this method you must use "gethostbyname_ex" that obtains a list with several addreses. You must select the address used for the browser, and you will capure TCP, UDP and ICMP packets.