Languages

Analyzing Network Traffic with Scapy: A Powerful Python Library

JGJaya Gupta21 Mar 2023 Β· Updated 04 Oct 2026 Β· 7 min read
Analyzing Network Traffic with Scapy: A Powerful Python Library

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

  1. Running without privileges. You get an empty capture or a PermissionError. Use sudo, Npcap, or setcap as shown above.
  2. Wrong interface name. eth0 may be ens33, en0 or Wi-Fi. Check conf.ifaces.
  3. Filtering in Python instead of BPF. On a busy link Scapy will drop packets. Push the filter to the kernel with filter="...".
  4. No timeout on sr1(). Default behaviour can block indefinitely if nothing answers.
  5. Using send() for layer-2 frames. Anything starting with Ether() needs sendp() or srp().
  6. 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

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 a prn callback for live traffic; rdpcap() for offline files.
  • sr1(), sr(), srp() and send() 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.

JG
Written byJaya Gupta

Part of the Techknowledgehub team of industry mentors, writing practical guides to help you build a job-ready tech career.

More articles by Jaya Gupta β†’
Keep reading

Related articles

Leave a Reply