Code a network packet sniffer in python for Linux

Basic Sniffer

Sniffers are programs that can capture/sniff/detect network traffic packet by packet and analyse them for various reasons. Commonly used in the field of network security. Wireshark is a very common packet sniffer/protocol analyzer. Packet sniffers can be written in python too. In this article we are going to write a few very simple sniffers in python for the linux platform. Linux because, although python is a portable, the programs wont run or give similar results on windows for example. This is due to difference in the implementation of the socket api.

Sniffers shown here dont use any extra libraries like libpcap. They just use raw sockets. So lets start coding them

I’m creating a raw socket using socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)). I’m reading the socket with s.recvfrom(65536) but since this should be layer 2, I don’t ever expect more than 9k read (max jumbo frame) right? Is it possible I’m getting two packets in one request? Should this always return 1 packet only, and if so how can it ever be larger than a 9k jumbo frame? MTU on the interface is set to 9001

The unpack() function makes sure iph[0] got the first byte of the packet. Looking back in the diagram, you could see that the first byte (8 bit) consists of the first 4 bit which is the version of the ip protocol, and the latter 4 bit which is the internet header length.

By >> or right-shifting the value by 4, it means that you push all the bits in the variable to the right by 4, in order to get the first 4 bit, which is the version section.
Also, if you AND or & the value by 0xF which in binary means 00001111, you get the last 4 bit, which is the internet header length.

Thanks for your code SilverMoon.
I have a fix to propose:
In the second example (‘Sniff all data with ethernet header’):
– The Ethernet type is unpacked in line 32. Since it’s BigEndian in the packet, unpack does the appropriate job.
– Line 33 is superfluous.
– In lines 36 and 37, the constant should be 0x800 (https://en.wikipedia.org/wiki/EtherType)

I’m trying very hard to find how to convert the line below to something in Windows that will capture the ethernet header. Do you have any ideas? I have looked at the Python docs and been searching forums but haven’t seen anything….
s = socket.socket( socket.AF_PACKET , socket.SOCK_RAW , socket.ntohs(0x0003))

So I tried to convert this code to python 3. But I am running into problems with the unpacking part, specifically the line “eth = unpack(‘!6s6sH’, eth_header)”. What is this line doing and why in python3 does it seem to do something else?

unpack(..) is part of the pack module which provides functionality to pack binary data into strings objects. Since the Python3 socket functions no longer work with string objects but with bytes objects instead, you don’t need (un)packing anymore.

It’s really difficult to find the detailed program you have provided in
any other site. Thank you. If you also give the description for your
programs, it would become the great website for learning socket
programming.

Thanks for very useful info. I’m novice to socket programming. Please help me with this. Is it possible to receive both TCP and ICMP packets in a single code. Is it something like creating a socket with this type: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP_TCP)

One question– despite putting eth0 in promiscuous mode, I seem to be able to sniff ONLY packets destined to the Pi. I am trying to connect the Pi to a Layer2 switch, and using port mirroring/spanning, trying to sniff
packets going to/from another port (on the Layer 2 switch).

Any hints on why the Pi does not seem to be “see” or sniff packets with destination addresses other than its own?

Thanks for the post. My question is how can you know that which format specifier is to be used to unpack a particular header? For an example in case of a ethernet header we use unpack(!6s!6s!2s). How can I know that I have to use strings and not any other format specifier to get ethernet addresses? Is there any documentation for it?

Hello sir, i’m really enjoying your articles about python and sockets; I’m also translating it in my language and is a very educational exercise. The unpack header is a bit over my knowledge but, for what i can understand and read, you are using 20 bytes as standard tcp header; Am i right? if so, is this a typical simplified construct to not bother with the [options] flag in the tcp header? i’m a real beginner in programming and in networking, but i would like to understand if i’m parsing the right way your code. Thanks for the precious articles

Helpful post. What would you recommend if we’d want to sniff outgoing packets too? Maybe need to run sniffer on a machine that’s set as a router/proxy where the endpoints of interest (to sniff) pass data through?

hi sir..
it this source code available when running on window,
for your information, i want to create a packet sniffer program using python on windows platfrom..
and the worse thing is, i’m the beginner on python.

Thanks for this script. I was looking for something to use in black box testing. I am doing some work testing an embedded linux system which has python but we don’t have a compiler to build stuff like tcpdump that isn’t installed

In the last, improved script there is a typo/slip at line 121, it should be

I had a problem with empty TCP packets. This program said the TCP data size would be 6, while it was 0.
But I can’t find the problem, since
data_size = len(packet) – eth_length + iph_length + tcph_length * 4
should be equal to
data_size = iph[2] – iph_length – tcph_length * 4

Follow us

This site, binarytides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.