Packet sniffing in Python (Windows)
Asked Answered
N

6

16

What is the best way to sniff network packets using Python?

I've heard from several places that the best module for this is a module called Scapy, unfortunately, it makes python.exe crash on my system. I would assume that it's just a problem with how I installed it, except that many other people have told me that it doesn't work particularly well on Windows. (If anyone is interested, I'm running Windows Vista, which might affect things).

Does anyone know of a better solution?

UPD:

After reading the answer telling me to install PyPcap, I messed around with it a bit and found out that Scapy, which I had tried using, was telling me to install PyPcap as well, except that it's a modified version for it's use. It was this modified PyPcap that was causing the problem, apparently, since the example in the answer also caused a hang.

I installed the original version of PyPcap (from Google's site), and Scapy started working fine (I didn't try many things, but at least it didn't crash as soon as I started sniffing). I sent a new defect ticket to the Scapy developers: http://trac.secdev.org/scapy/ticket/166, hope they can do something with it.

Anyways, just thought I'd let y'all know.

Necessity answered 20/1, 2009 at 18:18 Comment(1)
FTR this is a very outdated post. Scapy does not require such outdated libraries anymore, have a look at scapy.readthedocs.ioSniffy
B
16

Using pypcap:

import dpkt, pcap
pc = pcap.pcap()     # construct pcap object
pc.setfilter('icmp') # filter out unwanted packets
for timestamp, packet in pc:
    print dpkt.ethernet.Ethernet(packet)

output sample:

Ethernet(src='\x00\x03G\xb2M\xe4', dst='\x00\x03G\x06h\x18', data=IP(src='\n\x00\x01\x1c',
dst='\n\x00\x01\x10', sum=39799, len=60, p=1, ttl=128, id=35102, data=ICMP(sum=24667,
type=8, data=Echo(id=512, seq=60160, data='abcdefghijklmnopqrstuvwabcdefghi'))))

Ethernet(src='\x00\x03G\x06h\x18', dst='\x00\x03G\xb2M\xe4', data=IP(src='\n\x00\x01\x10',
dst='\n\x00\x01\x1c', sum=43697, len=60, p=1, ttl=255, id=64227, data=ICMP(sum=26715,
data=Echo(id=512, seq=60160, data='abcdefghijklmnopqrstuvwabcdefghi'))))
Breannabreanne answered 20/1, 2009 at 18:31 Comment(2)
The most convenient tool indeedCallaway
It hasn't been officially updated since 2008 though. Alternatives such as Scapy are probably more up to date..Sniffy
C
20

The hard way

You can sniff all of the IP packets using a raw socket.
Raw socket is a socket the sends and receives data in binary.
Binary in python is represented in a string which looks like this \x00\xff... every \x.. is a byte.
To read an IP packet you need to analyze the received packet in binary according to the IP protocol.

This is and image of the format of the IP protocol with the sized in bits of every header.

IP protocol format

This tutorial might help you understand the proccess of understanding a raw packet and splitting it to headers: http://www.binarytides.com/python-packet-sniffer-code-linux/

The easy way

Another method to sniff IP packets very easily is to use the scapy module.

from scapy.all import *
sniff(filter="ip", prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}"))

This code will print for you the source IP and the destination IP for every IP packet. You can do much more with scapy by reading it's documentation here: http://www.secdev.org/projects/scapy/doc/usage.html

It depends on the goal you are trying to achieve but if you need to build a project the one it's features is sniffing IP packets then I recommend to use scapy for more stable scripts.

Cobby answered 30/8, 2015 at 21:19 Comment(1)
you lack a parentheses sniff(filter="ip", prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}"))Mercaptide
B
16

Using pypcap:

import dpkt, pcap
pc = pcap.pcap()     # construct pcap object
pc.setfilter('icmp') # filter out unwanted packets
for timestamp, packet in pc:
    print dpkt.ethernet.Ethernet(packet)

output sample:

Ethernet(src='\x00\x03G\xb2M\xe4', dst='\x00\x03G\x06h\x18', data=IP(src='\n\x00\x01\x1c',
dst='\n\x00\x01\x10', sum=39799, len=60, p=1, ttl=128, id=35102, data=ICMP(sum=24667,
type=8, data=Echo(id=512, seq=60160, data='abcdefghijklmnopqrstuvwabcdefghi'))))

Ethernet(src='\x00\x03G\x06h\x18', dst='\x00\x03G\xb2M\xe4', data=IP(src='\n\x00\x01\x10',
dst='\n\x00\x01\x1c', sum=43697, len=60, p=1, ttl=255, id=64227, data=ICMP(sum=26715,
data=Echo(id=512, seq=60160, data='abcdefghijklmnopqrstuvwabcdefghi'))))
Breannabreanne answered 20/1, 2009 at 18:31 Comment(2)
The most convenient tool indeedCallaway
It hasn't been officially updated since 2008 though. Alternatives such as Scapy are probably more up to date..Sniffy
B
8

Use python-libpcap.

import pcap

p = pcap.pcapObject()
dev = pcap.lookupdev()
p.open_live(dev, 1600, 0, 100)
#p.setnonblock(1)
try:
    for pktlen, data, timestamp in p:
        print "[%s] Got data: %s" % (time.strftime('%H:%M', 
                                                   time.localtime(timestamp)),
                                     data)
except KeyboardInterrupt:
    print '%s' % sys.exc_type
    print 'shutting down'
    print ('%d packets received, %d packets dropped'
           ' %d packets dropped by interface') % p.stats()
Breannabreanne answered 20/1, 2009 at 18:20 Comment(0)
E
3

you can use raw sockets, with your interface ip address (in admin mode),

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_IP)
s.bind(("YOUR_INTERFACE_IP",0))
s.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1)
s.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
while True:
   data = s.recvfrom(10000)
   print data
Evanston answered 8/12, 2015 at 14:45 Comment(0)
W
2

If scapy, pleae try the following method. (It works on Windows 10)

# -*- coding: utf-8 -*-

# pip install scapy

"""
[{'name': 'Intel(R) 82574L Gigabit Network Connection',
  'win_index': '4',
  'description': 'Ethernet0',
  'guid': '{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}',
  'mac': '00:0C:29:5C:EE:6D',
  'netid': 'Ethernet0'}]
"""

from pprint import pprint
from scapy.arch.windows import get_windows_if_list
from scapy.all import *


# disable verbose mode
conf.verb = 0


def parse_packet(packet):
    """sniff callback function.
    """
    if packet and packet.haslayer('UDP'):
        udp = packet.getlayer('UDP')
        udp.show()


def udp_sniffer():
    """start a sniffer.
    """
    interfaces = get_windows_if_list()
    pprint(interfaces)

    print('\n[*] start udp sniffer')
    sniff(
        filter="udp port 53",
        iface=r'Intel(R) 82574L Gigabit Network Connection', prn=parse_packet
    )


if __name__ == '__main__':
    udp_sniffer()
Westmorland answered 9/10, 2018 at 14:22 Comment(0)
H
1

Another option is pypcap.

To parse the results, Construct is very slick.

Hoagy answered 20/1, 2009 at 18:26 Comment(2)
is construct dead? it doesn't look like there have been any new releases in over a year...Jamie
While the Construct home page mentions ethereal, all the tutorials are about using Construct to build parsers, not to use it to parse network packets.Hudibrastic

© 2022 - 2024 — McMap. All rights reserved.