Quick answer: Scapy is a Python library that lets you capture, dissect, build and send network packets at any layer β Ethernet, IP, TCP, UDP, ICMP, DNS, ARP and hundreds more β using plain Python objects. A packet is just IP(dst="8.8.8.8")/ICMP(); sniff() captures live traffic, sr1() sends a packet and waits for the reply. That makes Scapy the go-to tool for network troubleshooting, protocol learning, security testing and building custom scanners.
This guide shows how to install Scapy correctly, read and filter live traffic, analyse .pcap files, craft packets for reachability and port checks, and avoid the mistakes that make beginners think the library is “not working”. Everything runs on Python 3.9+ and Scapy 2.5+.
What Scapy is and when to use it
Wireshark shows you packets; Scapy lets you program them. Each protocol layer is a Python class with named fields, stacked with the / operator, so you can loop, filter and compute statistics without leaving Python.
Typical uses in a network or security role:
- Troubleshooting β confirm whether a VLAN is passing DHCP, or whether a firewall is dropping a specific TCP flag combination.
- Protocol learning β build a TCP handshake by hand and watch every field.
- Security testing β ARP discovery, SYN scans, detecting rogue DHCP servers (only on networks you are authorised to test).
- Automation β a 20-line script that sniffs for broadcast storms and raises an alert.
Installation and permissions
Install with pip install scapy. Capturing and sending raw packets needs elevated privileges: run with sudo on Linux and macOS, or as Administrator with Npcap installed on Windows. On Linux you can avoid sudo by granting the interpreter raw-socket capabilities once with sudo setcap cap_net_raw,cap_net_admin+eip $(readlink -f $(which python3)).
Find your interface names with ip link (Linux), ifconfig (macOS) or Scapy’s own conf.ifaces. Scapy also ships an interactive shell (scapy command) that is excellent for experiments; use ls(IP) to list every field of a layer and pkt.show() to print a decoded packet.
Hands-on 1: sniffing and summarising live traffic
The sniff() function captures packets. Use a BPF filter (the same syntax as tcpdump) so the kernel discards what you do not need, and a prn callback to process packets as they arrive rather than waiting for the capture to finish.
from collections import Counter
from scapy.all import sniff, IP, TCP, UDP, DNS, DNSQR
talkers = Counter()
def handle(pkt):
if IP in pkt:
talkers[pkt[IP].src] += len(pkt)
if pkt.haslayer(DNS) and pkt[DNS].qr == 0: # DNS query
print("DNS query:", pkt[DNSQR].qname.decode().rstrip("."))
elif pkt.haslayer(TCP) and pkt[TCP].flags == "S": # TCP SYN only
print(f"SYN {pkt[IP].src} -> {pkt[IP].dst}:{pkt[TCP].dport}")
# Capture 30 seconds of IP traffic, excluding SSH so we don't see our own session
packets = sniff(iface="eth0", filter="ip and not port 22", prn=handle, timeout=30)
print(f"\nCaptured {len(packets)} packets. Top talkers by bytes:")
for src, size in talkers.most_common(5):
print(f" {src:<16} {size / 1024:8.1f} KB")
packets.summary() # one line per packet
Two habits from day one: always add a timeout or count so the script ends, and filter in BPF rather than Python on busy links.
Hands-on 2: analysing a pcap file
You do not need live access to use Scapy. Export a capture from Wireshark or tcpdump -w and analyse it offline:
from collections import Counter
from scapy.all import rdpcap, IP, TCP, UDP
pkts = rdpcap("office-capture.pcap")
protocols = Counter()
conversations = Counter()
retransmissions = 0
seen_seq = set()
for p in pkts:
if IP not in p:
continue
key = tuple(sorted([p[IP].src, p[IP].dst]))
conversations[key] += 1
if TCP in p:
protocols["TCP"] += 1
sig = (p[IP].src, p[TCP].sport, p[IP].dst, p[TCP].dport, p[TCP].seq)
if sig in seen_seq and len(p[TCP].payload) > 0:
retransmissions += 1
seen_seq.add(sig)
elif UDP in p:
protocols["UDP"] += 1
else:
protocols[p[IP].proto] += 1
print("Packets:", len(pkts))
print("By protocol:", dict(protocols))
print("Possible TCP retransmissions:", retransmissions)
print("Busiest conversations:")
for (a, b), n in conversations.most_common(3):
print(f" {a} <-> {b}: {n} packets")
Because the result is ordinary Python data, you can push it straight into a pandas DataFrame or draw the conversation graph with NetworkX β see Network Visualization with Matplotlib and NetworkX for that next step.
Hands-on 3: crafting packets for reachability and port checks
Building packets is where Scapy outshines every other tool. sr1() sends one packet and returns the first reply; sr() handles many; send() and sendp() fire-and-forget at layer 3 and layer 2 respectively.
from scapy.all import IP, ICMP, TCP, ARP, Ether, sr1, srp, conf
conf.verb = 0 # quiet Scapy's own progress output
def ping(host, timeout=2):
reply = sr1(IP(dst=host) / ICMP(), timeout=timeout)
if reply is None:
return "no reply"
return f"alive, ttl={reply[IP].ttl}, rtt={(reply.time - reply.sent_time) * 1000:.1f} ms"
def tcp_port_open(host, port, timeout=2):
reply = sr1(IP(dst=host) / TCP(dport=port, flags="S"), timeout=timeout)
if reply is None:
return "filtered" # no answer at all
if reply.haslayer(TCP) and reply[TCP].flags == "SA":
# Politely close the half-open connection
sr1(IP(dst=host) / TCP(dport=port, sport=reply[TCP].dport, flags="R"), timeout=1)
return "open"
return "closed"
def arp_scan(cidr):
answered, _ = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=cidr), timeout=2)
return sorted((r[ARP].psrc, r[ARP].hwsrc) for _, r in answered)
print("Gateway:", ping("192.168.1.1"))
for port in (22, 80, 443, 3389):
print(f"Port {port}: {tcp_port_open('192.168.1.1', port)}")
for ip, mac in arp_scan("192.168.1.0/24"):
print(f"{ip:<16} {mac}")
The ARP scan finds every live host on your LAN segment in about two seconds, including devices that block ICMP. Only run scans like this against networks you own or are explicitly permitted to test.
Scapy compared with other packet tools
| Tool | Capture | Craft and send | Programmable | Best for |
|---|---|---|---|---|
| Scapy | Yes | Yes, any layer | Full Python | Custom analysis, testing, learning protocols |
| Wireshark / tshark | Yes, very fast | No | Lua, display filters | Deep interactive inspection of large captures |
| tcpdump | Yes | No | Shell only | Quick captures on servers |
| Nmap | No | Yes, scanning only | NSE (Lua) | Fast production-grade host and port discovery |
Six Scapy mistakes that waste hours
- Running without privileges. You get an empty capture or a
PermissionError. Usesudo, Npcap, orsetcapas shown above. - Wrong interface name.
eth0may beens33,en0orWi-Fi. Checkconf.ifaces. - Filtering in Python instead of BPF. On a busy link Scapy will drop packets. Push the filter to the kernel with
filter="...". - No
timeoutonsr1(). Default behaviour can block indefinitely if nothing answers. - Using
send()for layer-2 frames. Anything starting withEther()needssendp()orsrp(). - Scanning networks you do not own. Unauthorised scanning is illegal in most countries, including India under the IT Act. Use your lab, GNS3, EVE-NG or Containerlab.
Frequently asked questions
Is Scapy fast enough for high-traffic links?
Scapy is pure Python and will drop packets above a few thousand per second. For line-rate capture, record with tcpdump or Wireshark and analyse the pcap with Scapy afterwards, or use BPF filters to capture only what matters.
Can Scapy decode protocols it does not know?
Unknown payloads appear as Raw. You can define your own layer with a few lines by subclassing Packet and listing its fields, then bind it to a port β handy for proprietary or industrial protocols.
Does Scapy work on Windows and macOS?
Yes. Windows needs Npcap; macOS works out of the box with sudo. Some layer-2 features behave differently on Windows, so Linux (or WSL2) is the smoothest environment.
Key takeaways
- Scapy turns packets into Python objects you can capture, inspect, build and send at any layer.
- Use
sniff()with BPF filters and aprncallback for live traffic;rdpcap()for offline files. sr1(),sr(),srp()andsend()cover every craft-and-send scenario, from ping to ARP discovery.- Run with the right privileges, always set timeouts, and only test networks you are allowed to.
Want to pair packet-level skills with data analysis and visualisation? The Techknowledgehub Python & Data Science course teaches Python, pandas and visualisation through hands-on projects with mentor support and placement assistance. For free tutorials and demos, subscribe to our YouTube channel.



