Adjacent Node
Networking, explained. No BS.

Scapy

What It Is

Scapy is a Python packet crafting, sending, sniffing, and decoding toolkit. It is useful for labs, protocol learning, validation, reproducing packet behavior, and controlled troubleshooting. It is also sharp enough to cause problems if you spray traffic at production networks without permission.

Use Scapy in a lab first. Be explicit about interface, destination, count, and rate.

Setup

python3 -m venv .venv
source .venv/bin/activate
python -m pip install scapy
python

Inside Python:

from scapy.all import *

Watch out: Sending and sniffing often require elevated privileges. On macOS and Linux, that usually means running the Python process with permissions that can open raw sockets or capture interfaces.

Basic Discovery

Command Purpose
ls() List available protocol layers
ls(IP) Show fields for a layer
lsc() List Scapy command helpers
conf Show or set Scapy configuration
ifaces List interfaces known to Scapy
hexdump(pkt) Show packet bytes
pkt.show() Decode packet fields
pkt.summary() One-line packet summary

Packet Building

pkt = IP(dst="192.0.2.10") / ICMP()
pkt.show()

Layer 2 packet:

frame = Ether(dst="ff:ff:ff:ff:ff:ff") / IP(dst="192.0.2.10") / UDP(dport=53)

Set fields after creation:

pkt = IP(src="10.0.0.10", dst="10.0.0.20") / TCP(dport=443, flags="S")
pkt.ttl = 5

Ranges and random values:

IP(dst="192.0.2.0/30")
IP(ttl=(1, 30))
Ether(dst=RandMAC())
IP(id=RandShort())

Sending

Function Layer Use
send(pkt) Layer 3 Send IP packet and let OS handle Layer 2
sendp(pkt) Layer 2 Send full Ethernet frame
sr(pkt) Layer 3 Send and receive replies
sr1(pkt) Layer 3 Return first reply
srp(pkt) Layer 2 Send and receive Ethernet frames
srloop(pkt) Layer 3 Repeat send and receive

Examples:

send(IP(dst="192.0.2.10") / ICMP(), count=3)
reply = sr1(IP(dst="192.0.2.10") / ICMP(), timeout=2)
ans, unans = sr(IP(dst="192.0.2.10") / TCP(dport=[22, 80, 443], flags="S"), timeout=2)

Watch out: Always set count, timeout, and iface when testing outside a disposable lab.

Sniffing

pkts = sniff(iface="en0", count=10, filter="tcp port 443")
pkts.summary()

Process packets as they arrive:

def seen(pkt):
    print(pkt.summary())

sniff(iface="en0", filter="icmp", prn=seen, store=False, count=5)

Modern note: Scapy capture filters use libpcap syntax. Display-style filters from Wireshark are different.

Useful Patterns

Traceroute-style TTL test:

ans, unans = sr(IP(dst="192.0.2.10", ttl=(1, 8)) / ICMP(), timeout=2)
ans.summary()

TCP SYN check:

syn = IP(dst="192.0.2.10") / TCP(dport=443, flags="S")
reply = sr1(syn, timeout=2)
reply.summary() if reply else "no reply"

Read and write packet captures:

pkts = rdpcap("capture.pcap")
wrpcap("filtered.pcap", [p for p in pkts if TCP in p])

Troubleshooting

Symptom Check Likely Cause
Nothing sends Privileges, route, interface Raw socket or interface issue
No replies Firewall, wrong source, timeout, return path Packet sent but response blocked
Sniff sees nothing Interface, filter, permissions, offload Capture setup issue
Packet malformed Field types, checksums, layer order Bad packet construction
Unexpected source IP OS route selection Layer 3 send uses routing table
Too much traffic Count, loop, inter, rate Missing limits

Safety

  • Use documentation prefixes like 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in examples.
  • Get authorization before sending crafted packets on any network you do not own.
  • Prefer a lab VLAN, isolated namespace, or packet capture file for learning.
  • Avoid fuzzing production services.
  • Rate-limit tests and keep packet counts explicit.

Watch Out

  • Do not confuse Scapy's Python object model with packets already on the wire.
  • Do not assume checksums and lengths are final until the packet is built.
  • Do not run infinite send loops by accident.
  • Do not use Wireshark display filters in Scapy sniff filters.
  • Do not test spoofed traffic on production networks without approval.

References