Master Scapy: Build, Send, and Analyze Packets with Python
This guide introduces Scapy, a powerful interactive Python packet manipulation tool, covering installation, basic usage, packet creation, sending and receiving functions, layer inspection, packet export formats, sniffing, and advanced features such as sprintf and custom packet handlers, enabling network testing, analysis, and security tasks.
What is Scapy
Scapy is a powerful interactive packet manipulation program that can forge, decode, send, capture, match requests and responses for a wide range of protocols. It replaces tools such as hping, arpspoof, nmap, tcpdump, and can perform tasks like scanning, tracerouting, probing, unit testing, attacks, and network discovery.
Installation
Install directly with pip (Python 3):
pip3 install scapyBasic Usage
Enter the Scapy shell by typing scapy. Use ls() to list supported protocols and lsc() to list functions. ls() can also show protocol fields.
Sending and Receiving Packets
send
Sends packets at layer 3 (Scapy creates layer 2 headers) without receiving any response. Parameters: loop – if non‑zero, packets are sent repeatedly until Ctrl‑C. count – exact number of packets to send. inter – interval in seconds between packets.
>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'))
Sent 1 packets.
>>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), count=10)
Sent 10 packets.
>>> send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), loop=1)
Sent 1503 packets.sendp
Sends at layer 2; you must provide a layer 2 header. Use the iface argument to select the interface (defaults to conf.iface).
>> sendp(Ether()/IP(dst='1.2.3.4', ttl=(1,4)), iface='eth0')
Sent 4 packets.
>>> sendp('I’m travelling on Ethernet', iface='eth0', loop=1, inter=0.2)
Sent 11 packets.
>>> sendp(rdpcap('/tmp/pcapfile'))
Sent 11 packets.sr
Sends packets and receives responses, returning a tuple of answered and unanswered lists.
>> sr(IP(dst='60.205.177.168')/TCP(dport=[21,22,23]))
Begin emission:
Finished sending 3 packets.
Received 36 packets, got 2 answers, remaining 1 packets
(<Results: TCP:2 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:1>)sr1
Sends packets and returns only the first response.
>> p = sr1(IP(dst='www.baidu.com')/ICMP()/"asdqwe")
Received 2 packets, got 1 answer.srloop
Continuously sends packets, receives responses, and displays them.
>> packet = IP(dst='60.205.177.168')/ICMP()
>>> srloop(packet)
RECV 1: IP / ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0
Sent 4 packets, received 4 packets. 100.0% hits.Creating Packets
Scapy builds packets by stacking layers, mirroring the OSI model.
Basic packet can be created in one line:
>> packet = Ether()/IP(dst='8.8.8.8')/TCP(dport=53, flags='S')Or create each layer separately and combine with the '/' operator:
>> l2 = Ether()
>>> l3 = IP(dst='8.8.8.8/30')
>>> l4 = TCP(dport=53, flags='S')
>>> packet = l2/l3/l4Inspecting Packets
Use ls(packet) to list field definitions and packet.show() for a detailed view. packet.show2() also assembles the packet and computes checksums and IHL.
>> packet = IP()/TCP()
>>> ls(packet)
version : BitField = 4 (4)
... (snipped) ...
>>> packet.show()
###[ IP ]###
version= 4
ttl= 64
src= 127.0.0.1
dst= 127.0.0.1
###[ TCP ]###
sport= ftp_data
dport= http
flags= S
...
>>> packet.summary()
'IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:http S'Layer Interaction
Access fields directly (e.g., packet.dst) or via layer name ( packet[IP].dst). Check for a layer with haslayer() or the in operator.
>> if packet.haslayer(IP):
... print(packet[IP].dst)
8.8.8.8
>>> DNS in pkt
Truesprintf
The sprintf() method fills format strings with packet field values, similar to C's sprintf.
>> packet.sprintf("Ethernet source is %Ether.src% and IP proto is %IP.proto%")
'Ethernet source is 00:16:3e:0c:d1:ad and IP proto is tcp'
>>> a.sprintf("%dst% %IP.dst% vlan=%Dot1Q.vlan%")
'00:00:d4:ae:3f:71 192.168.0.1 vlan=42'Packet Handlers
Define a lambda to process TCP packets:
>> f = lambda x: x.sprintf("%IP.dst%:%TCP.dport%")
>>> f(IP(dst='8.8.8.8')/TCP())
'8.8.8.8:http'
>>> f(IP(dst='8.8.8.8')/UDP())
'8.8.8.8:??'Conditional substrings in sprintf() allow handling of different layers.
>> f = lambda x: x.sprintf("=> {IP:ip=%IP.dst% {UDP:dport=%UDP.dport%}
... {TCP:%TCP.dport%/%TCP.flags%}{ICMP:type=%ICMP.type%}} {!IP:not an IP packet}")
>>> f(IP()/TCP())
'=> ip=127.0.0.1 http/S'
>>> f(Ether()/ARP())
'=> not an IP packet'Import and Export
PCAP format: pkts = rdpcap('temp.cap') or sniff(offline='temp.cap'). Export with wrpcap('temp.cap', pkts).
Hexdump: hexdump(s) displays packet bytes.
Hex string: str(s) returns a hexadecimal representation.
Base64: export_object(s) returns a base64‑encoded packet.
Sniffing
The sniff() function captures traffic with options such as count, filter, iface, lfilter, prn, and timeout.
>> sniff(count=4, iface='eth0')
<Sniffed: TCP:1 UDP:3 Other:0>
>>> pkts = sniff(count=1, filter="tcp and host 60.205.177.168 and port 80")
>>> pkts.summary()
Ether / IP / TCP 172.17.51.80:54578 > 60.205.177.168:http S
>>> pkts = sniff(offline='test.pcap')
>>> pkts.nsummary()
0000 Ether / IP / TCP 172.16.16.128:1606 > 74.125.95.104:http S
...These capabilities make Scapy a versatile tool for network testing, security analysis, and protocol research.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
