Introduction to scapy

By stretch | Monday, May 23, 2011 at 2:15 a.m. UTC

scapy is a Python framework for crafting and transmitting arbitrary packets. I've used scapy in labs for my articles a few times before, but today we'll be looking at scapy itself and why it's an invaluable component of every networker's virtual toolbox.

To run scapy, you'll need to have Python installed. The latest version of scapy is available for download here. The most recent version of scapy at the time of writing is 2.1.0, and that's what the examples provided in this article use. scapy is installed per the typical Python package installation mechanism on Linux:

$ sudo ./ install

scapy is typically used as an interactive Python interpreter, but its libraries can also be imported for use in your own code. The examples here use scapy's shell, which is essentially a pre-configured Python environment. For a quick introduction to Python you can check out the official tutorial, but building packets with scapy requires only minimal Python knowledge.

Launch the scapy executable to get started. Note that you'll need to invoke scapy with root or administrative rights in order to send or sniff packets.

$ sudo scapy
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
Welcome to Scapy (2.1.0)

You may see some warnings like the two above regarding absent optional dependencies or missing routes; don't worry about them.

The two most important commands to remember for scapy are ls() and lsc(). These commands are actually Python functions, which is why they must be called with the ending parentheses. ls() displays all of the available protocols and lsc() lists all of the scapy command functions.

>>> ls()
ARP        : ARP
ASN1_Packet : None
CookedLinux : cooked linux
DHCP       : DHCP options
DHCP6      : DHCPv6 Generic Message)
>>> lsc()
arpcachepoison      : Poison target's cache with (your MAC,victim's IP) couple
arping              : Send ARP who-has requests to determine which hosts are up
bind_layers         : Bind 2 layers on some specific fields' values
corrupt_bits        : Flip a given percentage or number of bits from a string

scapy's primary purpose is to build and transmit arbitrary packets, so let's get started!

Packets are constructed as layers of protocols, loosely analogous to the OSI model, which can be manipulated independently or glued together. For example, the IP() object represents an IPv4 header. Use the show() method of an object to display all of its fields.

>>> IP().show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  frag= 0
  ttl= 64
  proto= ip
  chksum= None

This should look familiar. We can see that all of the fields have default values set. We can modify these fields by passing them as arguments when the IP() object is created, or after saving it as a variable.

>>> ip=IP(src="")
>>> ip.dst=""
>>> ip
<IP  src= dst= |>

Of course, an IP packet by itself isn't very useful. We can add a layer four protocol like TCP or UDP by using the division operator to attach it to our IP packet.

>>> ip/TCP()
<IP  frag=0 proto=tcp src= dst= |<TCP  |>>

Notice that when we did this, the protocol ("proto") field in the IPv4 header was automatically set to TCP. scapy conveniently takes care of such housekeeping so that we can focus on the fun stuff (these automatic configurations can always be overridden manually if need be).

We can manipulate the TCP header fields just as we did with our IP header.

>>> tcp=TCP(sport=1025, dport=80)
>>> (tcp/ip).show()
###[ TCP ]###
  sport= 1025
  dport= www
  seq= 0
  ack= 0
  dataofs= None
  reserved= 0
  flags= S
  window= 8192
  chksum= None
  urgptr= 0
  options= {}
###[ IP ]###
     version= 4
     ihl= None
     tos= 0x0
     len= None
     id= 1
     frag= 0
     ttl= 64
     proto= ip
     chksum= None

Remember to enclose combined headers in a pair of parentheses when using methods like show() on the entire packet.

scapy also supports Ethernet and IEEE 802.11 at layer two:

>>> Ether()/Dot1Q()/IP()
<Ether  type=0x8100 |<Dot1Q  type=0x800 |<IP  |>>>
>>> Dot11()/IP()
<Dot11  |<IP  |>>

Try combining different protocols to form a variety of packets. To send packets onto the wire, use the send() function if transmitting at layer three (i.e. without a layer two header) or the sendp() function if transmitting at layer two.

>>> send(ip/tcp)
Sent 1 packets.
>>> sendp(Ether()/ip/tcp)
Sent 1 packets.

Values for blank fields, such as the source and destination addresses in the Ethernet header, are populated automatically by scapy where possible.

scapy also has the ability to listen for responses to packets it sends, such as ICMP echo requests (pings). We can build an IP packet carrying an ICMP header, which has a default type of echo request, and use the sr() (send/receive) function to transmit the packet and record any response.

>>> sr(IP(dst="")/ICMP())
Begin emission:
Finished to send 1 packets.
Received 1 packets, got 1 answers, remaining 0 packets
(<Results: TCP:0 UDP:0 ICMP:1 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)

What if we want to send and listen for responses to multiple copies of the same packet? We can use the srloop() function and specify a count of packets to send.

>>> srloop(IP(dst="")/ICMP(), count=3)
RECV 1: IP / ICMP > echo-reply 0 / Padding
RECV 1: IP / ICMP > echo-reply 0 / Padding
RECV 1: IP / ICMP > echo-reply 0 / Padding

Sent 3 packets, received 3 packets. 100.0% hits.
(<Results: TCP:0 UDP:0 ICMP:3 Other:0>, <PacketList: TCP:0 UDP:0 ICMP:0 Other:0>)

There's plenty more to scapy that we haven't touched on yet, but hopefully this article will encourage you to play with it a bit on your own and see what kind of crazy packets you can come up with!

About the Author

Jeremy Stretch is a network engineer living in the Raleigh-Durham, North Carolina area. He is known for his blog and cheat sheets here at Packet Life. You can reach him by email or follow him on Twitter.

Posted in Packet Analysis


jgitau (guest)
May 23, 2011 at 5:27 p.m. UTC

Im glad to see someone else uses it.

May 24, 2011 at 7:52 a.m. UTC

Hey, Great Site you got here. Visit Daily as I am Packet Fanatic. :)
Check out my post on Scapy on

Have a good day.

lc471 (guest)
May 24, 2011 at 10:47 p.m. UTC

Take a look also at Mausezahn, it's really flexible (you can specify every single bit in the ethernet frame if you want, or construct a packet with other methods and put dot1q tags and/or mpls labels around it).

Pedro (guest)
May 25, 2011 at 7:54 a.m. UTC

If you are interested by scapy, and want to analyse HSRP with MD5 authent, I advise to read this article from a friend

May 25, 2011 at 2:32 p.m. UTC

Mac users that have MacPorts installed can install scapy with

$ sudo port install scapy

May 27, 2011 at 12:22 p.m. UTC

Excellent tool and great article stretch!

Greetings from Puerto Rico!

May 27, 2011 at 1:50 p.m. UTC

If you want to read more about scapy (installation, usage, troubleshooting,...) you can go here-->


paul (guest)
August 3, 2011 at 1:55 p.m. UTC

Hello people!
Am a MSC. student and want to use packets generated by scapy in Opnet. I am modifying the Simple_source process model of OPNET to add new attributes i.e file location, data rate etc. i want to use the traffic as malware traffic in a M/M/1 queue OPNET model and analyse the impact (queue delay, size). anybody with ideas on how i can go about this. your quick response will be highly appreciated.


A guest
October 3, 2011 at 5:09 p.m. UTC

Another Scapy user here - just thought I'd throw that out there since I jgitau (guest) comment in the same light.

al (guest)
November 26, 2011 at 4:01 a.m. UTC

On fedora 14/15/16 for scapy , python libraries and wifi

sudo yum install scapy libdnet libpcap aircrack-ng scipy numpy PyX gnuplot tcpdump ImageMagick doxygen graphviz python-crypto python-setuptools iw

optional ipython

Then with setup tools installed - package manager (sort of) for python

sudo easy_install gnuplot-py

using python scapy , aircrack, iw, its easy to detect individual wifi users

Datta (guest)
July 16, 2012 at 1:25 p.m. UTC

Hey really great site to absorb knowledge

sHoM (guest)
September 25, 2012 at 9:10 a.m. UTC

I am trying to sniff packets from one interface and send it on another, but when I try to send the packets using srp() I get an OSError no 9 Bad File Descriptor and shows two lines as erroneous, line 358 in and line431 in

Malhar Vora (guest)
April 29, 2014 at 11:17 a.m. UTC

Really informative article. Thanks Jeremy.

ste (guest)
October 20, 2014 at 12:55 p.m. UTC

Hi, great post. Wondering if with this tool you can generate a packet of arbitrary size and send it on the wire bypassing MTU check. I need to send on the wire a packet over 20000, so I guess bigger than the allowed max MTU on Linux. And I need the packet not to get fragmented. Any ideas? Thanks, Ste

Comments have closed for this article due to its age.