Guide to Capturing PCAP Files on Android Devices

PCAP on Android Without Root: PCAPdroid vs. tcpdump in Termux

TL;DR: Non-root tcpdump in Termux cannot capture anything on stock Android — the SELinux policy for non-system apps (untrusted_app) hard-blocks packet sockets, so tcpdump dies with socket: Operation not permitted. The real non-root capture path is PCAPdroid (local VPN mode, exports standard PCAP). tcpdump is still worth installing from Termux's root repo: it's the perfect -r reader, filter engine, and capture tool if you have root (tsu) or run it in a proot-distro container for analysis. You'll need Termux from F-Droid, Android 7+, and 2 GB+ RAM.

The first time I ran tcpdump -i wlan0 in Termux on a stock, non-rooted Pixel, it died in under a second. No filter, no warning, no courtesy:

termux
tcpdump: any: You don't have permission to capture on that device
(socket: Operation not permitted)

Every blog post I'd read promised the same thing: "Termux + tcpdump, no root, just your own app's traffic." That premise is a myth on modern Android, and I'd rather you learn it from one command here than after an hour of setup. The good news: the story doesn't end at the wall — it just moves to better tools. Here's the full, honest map of what captures PCAP on Android in 2026 and what doesn't.

⚠ Non-root tcpdump capture does not work on stock Android — the kernel SELinux policy forbids non-system apps from creating packet sockets. If someone's tutorial says otherwise, it was written for rooted devices, custom ROMs, or pre-Android-10 kernels. Double-check before building a workflow on it.

Why Non-Root tcpdump Fails on Android: The SELinux Neverallow

This isn't a Termux bug and no package update will fix it. Android's SELinux policy (untrusted_app.te in AOSP system/sepolicy) contains a hard neverallow rule: non-system apps may never create packet_socket (AF_PACKET) sockets — the raw-socket family every sniffer depends on. Termux runs in the untrusted_app domain (UID 101xx), so it gets exactly zero packet visibility. The Termux maintainers have been blunt about it since 2017: "Raw sockets is just not allowed without rooting — nothing we can do in Termux unfortunately."

Three things compound it:

  • tcpdump moved to the root repo. Since 2019, the package lives in Termux's root-packages/ channel (tcpdump 4.99.4), not the main repo. A plain pkg install tcpdump on a stock setup fails until you add the repo — and even then, capture requires tsu/su.
  • proot doesn't change the domain. proot-distro is a syscall translator, not a privilege escalator. Processes inside it keep the same UID and SELinux domain, so tcpdump in a "rooted" Kali container hits the same Operation not permitted.
  • There's no "own traffic only" loophole. Some posts claim non-root tcpdump sees the Termux UID's traffic. It doesn't — you can't create the socket in the first place.

What does work without root is Android's VpnService API, which gives an app access to packets through a local virtual interface. That's exactly how PCAPdroid captures — and it's the path the rest of this guide builds on.

Ethical/legal reminder: Only capture on networks you own or have explicit written authorization for. Unauthorized packet capture violates wiretap laws in most jurisdictions, and captures can contain credentials and PII — redact them before sharing. We use these techniques in our lab against our own devices and targets.

The Non-Root Capture Path: PCAPdroid in VPN Mode

PCAPdroid is the de facto non-root sniffer: open-source, F-Droid-friendly (v1.9.x as of 2026), and it dumps standard PCAP you can open anywhere. It works by creating a local VPN interface and routing every app's traffic through it — no remote server, all processing on-device.

Setup:

  1. Install PCAPdroid from F-Droid (or GitHub releases).
  2. Open the app → Start capture → grant the VPN permission when Android asks.
  3. Use the phone normally — every app's traffic lands in the dump, not just yours.
  4. Export PCAP to ~/storage/shared/Download/, then pull it into Termux for filtering, rotation, or transfer.

What you get:

  • Full-device capture (all apps) with app-level filters, protocol filters, and a PCAP filter field that accepts BPF-style expressions.
  • Standard PCAP export plus an SSLKEYLOGFILE export for decrypting TLS later in Wireshark — no MITM proxy needed for your own keys.
  • No root, no ADB for the core workflow.

The catches: PCAPdroid occupies Android's single VPN slot (conflicts with any other VPN), it drains battery while capturing, and start/stop is UI-driven — though you can script it via the app's CaptureCtrl intent with a one-time ADB grant:

bash
# From a PC with ADB over USB or Wi-Fi
adb shell am start -e action start -e pcap_dump_mode pcap_file -e pcap_name traffic.pcap -n com.emanuelef.remote_capture/.activities.CaptureCtrl
adb shell am start -e action stop -n com.emanuelef.remote_capture/.activities.CaptureCtrl

tcpdump in Termux: Install, Verify, and the Root Requirement

Still install it. tcpdump is the best pcap reader on the phone, its BPF syntax transfers everywhere, and it's your capture engine the day you root the device. Here's the correct 2026 install — root repo included:

1. Update, Add the Root Repo, Install

termux
pkg update && pkg upgrade -y
pkg install -y root-repo
pkg install -y tcpdump

root-repo subscribes Termux to the termux-root channel (where tcpdump and tshark live since 2019). The packages install fine on non-rooted phones — they just can't capture until you're root.

2. Verify the Install

termux
tcpdump --version
# Expected: tcpdump version 4.99.x (libpcap version 1.10.x)
which tcpdump
# /data/data/com.termux/files/usr/bin/tcpdump

3. Grant Storage Access

termux
termux-setup-storage
# Tap "Allow" — creates ~/storage/shared, a symlink to /storage/emulated/0

Android 11+ scoped storage note: ~/storage/shared still works on Android 11+ — writing to Download/ is fine. Two gotchas: you can't read other apps' private dirs under Android/data (that's by design), and on some ROMs you must re-run termux-setup-storage after an OS update, or grant "All files access" under Settings → Apps → Termux → Special app access.

4. The Honest Capability Table

CapabilityRootNon-Root (Termux)
See all interface traffic
See Termux's own traffic❌ (packet sockets blocked by SELinux)
Promiscuous mode / monitor mode Wi-Fi
Read & filter PCAP files (tcpdump -r)✅ — no root needed to read
Write PCAP to shared storage✅ (via ~/storage/shared)
Full-device non-root capture✅ via PCAPdroid (VPN mode)

Interfaces, First Capture, and the Flags That Matter

Interface discovery works fine non-root with iproute2 — no raw sockets needed to list:

termux
ip link show
ip -br addr
termux
tcpdump -D
# Typical output (root/tsu):
# 1. wlan0 [Up, Running]
# 2. eth0 [Up, Running]  (USB tether / ethernet dongle)
# 3. any [Up, Running]   (pseudo-device: all interfaces)
# 4. lo [Up, Running, Loopback]

Interface cheat sheet:

  • wlan0 — primary Wi-Fi (most common)
  • eth0 — USB Ethernet, tethering, or docked Ethernet
  • any — kernel merges all interfaces (use when unsure)
  • lo — loopback only

Your first capture — run under tsu on a rooted device, or in a root shell; on non-root devices this is where PCAPdroid takes over:

root
# Capture on Wi-Fi, write PCAP to shared storage
tcpdump -i wlan0 -w ~/storage/shared/Download/capture.pcap

Flags explained:

  • -i wlan0 — interface (use any if wlan0 is missing)
  • -w file.pcap — write raw packets to binary PCAP, not stdout
  • Add -n — skip DNS hostname resolution: faster, cleaner, no accidental DNS leaks about what you're capturing

Generate some traffic in a second Termux session to make the file interesting:

termux
curl -I https://openlinuxlab.com
ping -c 3 1.1.1.1
dig @1.1.1.1 example.com

Stop with Ctrl+C (SIGINT) — never kill -9, or the PCAP header never closes and the file looks empty. Clean exits show the classic summary:

termux
^C
47 packets captured
52 packets received by filter
0 packets dropped by kernel

Verify the file, then read it back:

termux
ls -lh ~/storage/shared/Download/capture.pcap
file ~/storage/shared/Download/capture.pcap
# Output: PCAP file, version 2.4, little-endian, 65535 snaplen
termux
tcpdump -r ~/storage/shared/Download/capture.pcap -n
# -r = read from file, -n = no DNS resolution

BPF Filters: Your Capture Scalpel

Berkeley Packet Filter syntax is identical everywhere — tcpdump, PCAPdroid's filter field, Wireshark. Learn it once and it pays for itself on every platform:

termux
# Single host (IP or hostname)
tcpdump -i wlan0 host 192.168.1.50 -w ~/storage/shared/Download/host-50.pcap

# Single port (e.g., HTTP)
tcpdump -i wlan0 port 80 -w ~/storage/shared/Download/http.pcap

# Host + port combination
tcpdump -i wlan0 host 192.168.1.50 and port 443 -w ~/storage/shared/Download/https-50.pcap

# Subnet (CIDR)
tcpdump -i wlan0 net 192.168.1.0/24 -w ~/storage/shared/Download/subnet.pcap

# Protocol specific
tcpdump -i wlan0 tcp -w ~/storage/shared/Download/tcp-only.pcap
tcpdump -i wlan0 udp -w ~/storage/shared/Download/udp-only.pcap
tcpdump -i wlan0 icmp -w ~/storage/shared/Download/icmp.pcap

# Complex: HTTP/HTTPS to one host, exclude SSH
tcpdump -i wlan0 "host 192.168.1.50 and (port 80 or port 443) and not port 22" -w ~/storage/shared/Download/web-50.pcap

Operator precedence: not > and > or. Group with parentheses or the filter silently means something else.

Want the actual HTTP method bytes? This is the classic GET/POST probe — note the canonical data-offset math (tcp[12] & 0xf0) >> 2, which many copy-pasted variants get subtly wrong:

termux
# ASCII output, matches "GET " (0x47455420) or "POST" (0x504f5354) at TCP payload start
tcpdump -i wlan0 -A -s 0 'port 80 and (tcp[((tcp[12] & 0xf0) >> 2):4] = 0x47455420 or tcp[((tcp[12] & 0xf0) >> 2):4] = 0x504f5354)'

Note on HTTPS: capture gives you Client Hello, Server Hello, certificates, and encrypted application data — not plaintext. For decryption you need session keys (Wireshark + SSLKEYLOGFILE from PCAPdroid or your browser) or a MITM proxy. That's its own rabbit hole, covered below.

File Rotation: -C, -W, and -G Without Filling the Phone

Long captures fill mobile storage fast. Rotation is your disk-saver. Three flags, verified against the tcpdump man page:

  • -C 100 — rotate every 100 million bytes (1,000,000 bytes, not 1,048,576 — man page confirmed). Files get numbers appended: rotate.pcap1, rotate.pcap2
  • -W 10 — with -C: keep 10 files max, overwrite the oldest (circular buffer). With -G: limit rotated files and exit cleanly when reached.
  • -G 3600 — rotate every 3600 seconds (time-based); the -w filename should contain a strftime(3) format.
termux
# Size-based: 100 MB files, 10-file circular buffer
tcpdump -i wlan0 -C 100 -W 10 -w ~/storage/shared/Download/rotate.pcap

⚠ Gotcha I hit first: tcpdump does not expand %Y%m%d-%H%M%S in the -w name for -C — it writes the literal string and appends a counter. Time-stamped names need a shell wrapper (below) or -G with a strftime format.

Time-based rotation wrapper — 30-minute segments by default:

termux
cat > ~/capture-rotate.sh << 'EOF'
#!/data/data/com.termux/files/usr/bin/bash
# Time-based rotation wrapper for tcpdump
INTERFACE="${1:-wlan0}"
DURATION_MIN="${2:-30}"
OUTPUT_DIR="${3:-~/storage/shared/Download}"
PREFIX="capture"

mkdir -p "$OUTPUT_DIR"
cd "$OUTPUT_DIR"

while true; do
  TIMESTAMP=$(date +%Y%m%d-%H%M%S)
  tcpdump -i "$INTERFACE" -w "${PREFIX}-${TIMESTAMP}.pcap" -G $((DURATION_MIN * 60)) -W 1
  # -G rotates every N seconds, -W 1 exits after one file; the loop opens the next segment
done
EOF
chmod +x ~/capture-rotate.sh

# Run: 30-min segments on wlan0
~/capture-rotate.sh wlan0 30

Analyzing PCAPs On-Device and in Wireshark

Readback with tcpdump -r (No Root Needed)

Reading is where non-root tcpdump shines — -r only touches the file, so no socket permissions involved:

termux
# Basic read
tcpdump -r ~/storage/shared/Download/capture.pcap -n

# Verbose packet details
tcpdump -r ~/storage/shared/Download/capture.pcap -vvv -n

# Filter while reading (same BPF syntax)
tcpdump -r ~/storage/shared/Download/capture.pcap -n "port 443"

# Count packets
tcpdump -r ~/storage/shared/Download/capture.pcap -n | wc -l

# Top talkers (IP pairs)
tcpdump -r ~/storage/shared/Download/capture.pcap -n -tttt | awk '{print $3}' | sort | uniq -c | sort -rn | head -20

tshark for Serious Analysis (root-repo or proot-distro)

tshark isn't in Termux's main repo — it lives in the root channel alongside tcpdump (v4.6.x). Analyzing existing pcaps doesn't need root; capturing does. Easiest path: install it inside a proot-distro container where the full toolchain already exists:

termux
# Inside a proot-distro Ubuntu/Kali container
apt update && apt install -y tshark

# Top talkers
tshark -r capture.pcap -z conv,ip -q

# HTTP objects export
tshark -r capture.pcap --export-objects http,./http_objects/

# Follow a TCP stream
tshark -r capture.pcap -z "follow,tcp,ascii,0"

Recommendation: mobile screens and on-screen keyboards make deep dissection painful. Capture on the phone, analyze on a workstation — next section.

Transfer to Your PC for Wireshark

Option A — USB (MTP): the file is already in ~/storage/shared/Download/; mount the phone and copy it out. Zero setup, fine for one-off grabs.

Option B — SSH/SCP (recommended):

termux
# On the phone (Termux): start sshd and find the IP
sshd
whoami   # e.g., u0_a123
termux-wifi-connectioninfo | grep '"ip"'    # requires termux-api
# Or: ip route get 1.1.1.1 | awk '{print $7}'

# On the PC:
scp -P 8022 u0_a123@192.168.1.50:~/storage/shared/Download/capture.pcap .

Option C — Termux:API share sheet:

termux
pkg install termux-api
termux-share ~/storage/shared/Download/capture.pcap

Option D — rsync via SSH:

bash
rsync -avz -e "ssh -p 8022" u0_a123@192.168.1.50:~/storage/shared/Download/*.pcap ./captures/

Wireshark Display-Filter Cheatsheet

GoalDisplay Filter
HTTP onlyhttp
HTTPS/TLStls or ssl
DNS queriesdns.flags.response == 0
DNS responsesdns.flags.response == 1
Specific IPip.addr == 192.168.1.50
Specific porttcp.port == 443 or udp.port == 53
TCP retransmissionstcp.analysis.retransmission
TLS handshaketls.handshake
Plaintext credshttp contains "password" or http contains "Authorization"

Pro tip: right-click a packet → Follow → TCP Stream reconstructs the full conversation.

Beyond the Ceiling: proot-distro, MITM, and Root

proot-distro: Full Toolchain, Same SELinux Wall

proot-distro gives you a complete Linux userspace — the analysis stack (tshark, zeek, suricata, bettercap, mitmproxy) runs great inside it:

termux
pkg install -y proot-distro
proot-distro install kali
proot-distro login kali
termux
# Inside Kali
apt update && apt install -y tcpdump tshark wireshark-common
tcpdump -i any -w /home/kali/capture.pcap

⚠ Don't expect capture magic inside proot: the container shares Termux's UID and SELinux domain, so tcpdump -i any here hits the same socket: Operation not permitted on a non-rooted phone. proot is for analysis tooling, not for bypassing the sandbox. (Some guides hint at experimental --isolated networking; treat it as unsupported for capture.)

MITM Proxy for HTTPS Decryption

For your own Termux traffic, run a local MITM proxy and route clients through it — plaintext on your screen, PCAP-able after conversion:

termux
# In proot-distro Ubuntu/Kali
apt install -y mitmproxy

# Run the proxy
mitmproxy --mode regular --listen-port 8080 --set block_global=false

# In another Termux session, route traffic through it:
export http_proxy=http://127.0.0.1:8080
export https_proxy=http://127.0.0.1:8080
curl -I https://httpbin.org/get   # now visible in the mitmproxy UI

mitmproxy can export flows, and mitmproxy2pcap converts them to PCAP for Wireshark. Remember: this decrypts only traffic you explicitly route through the proxy — it's for labbing, not for others' traffic.

Root: The Honest Answer

If you need full packet capture — all apps, promiscuous mode, monitor-mode Wi-Fi — root is the only complete solution: Magisk + a tcpdump binary, or Termux with tsu. That's the difference between a sensor node and a proper sniffer, and this guide assumes the former. Choose your path by threat model, not by what's easiest to type.

Pro Tips: Production-Grade Captures

1. Battery Exemption + Wake Lock (Critical)

Android kills background Termux processes within minutes. Exempt every app in the chain:

  • Settings → Apps → Termux → Battery → Unrestricted
  • Settings → Apps → Termux:API → Battery → Unrestricted
  • Settings → Apps → Termux:Boot → Battery → Unrestricted
  • Settings → Apps → PCAPdroid → Battery → Unrestricted
termux
termux-wake-lock      # prevent CPU sleep (needs termux-api)
termux-wake-unlock    # release when done

Wrap capture scripts so the lock always releases, even on failure:

termux
#!/data/data/com.termux/files/usr/bin/bash
termux-wake-lock
trap 'termux-wake-unlock' EXIT
tcpdump -i wlan0 -w ~/storage/shared/Download/capture.pcap

2. Termux:Boot for Auto-Start on Device Boot

termux
pkg install termux-api

mkdir -p ~/.termux/boot
cat > ~/.termux/boot/start-capture << 'EOF'
#!/data/data/com.termux/files/usr/bin/bash
# Auto-start rotated capture on boot (caution: fills disk!)
termux-wake-lock
sleep 30
~/capture-rotate.sh wlan0 60 > ~/capture.log 2>&1 &
EOF
chmod +x ~/.termux/boot/start-capture

Reboot and the capture starts itself — as long as Termux:Boot survived the battery optimizers. Verify with tail -f ~/capture.log.

3. Remote Control Over SSH

bash
sshd   # listens on port 8022

# From the laptop: 1-hour rotations, 24 files max, fully headless
ssh -p 8022 u0_a123@192.168.1.50 "tcpdump -i wlan0 -w ~/storage/shared/Download/remote.pcap -G 3600 -W 24"

4. Cron for Scheduled Captures

termux
pkg install -y cronie
crond
crontab -e
termux
# Example: 9-17 on weekdays, 1-hour files
# 0 9-17 * * 1-5 ~/capture-rotate.sh wlan0 60 >> ~/cron-capture.log 2>&1

# Example: daily 2 AM capture for 2 hours (note % escaping in crontab)
# 0 2 * * * timeout 7200 tcpdump -i wlan0 -w ~/storage/shared/Download/daily-$(date +\%Y\%m\%d).pcap

Gotcha: Termux's crond runs only while the Termux process lives. Pair cron with Termux:Boot and battery exemption for true persistence — and set the crontab PATH header, or cron can't find your tools.

5. Snaplen and Timestamp Precision

Two flags I had wrong for years, corrected against the current man page:

  • -s 0 does not mean "unlimited" in tcpdump 4.99.x — it resets snaplen to the default 262144 bytes. For any real-world frame that's effectively full-packet capture, so use it freely, just don't expect literal infinity.
  • -tttt is a print-time flag (date + time on output lines). It does nothing to the bytes written by -w. For nanosecond timestamps in the file, use --time-stamp-precision=nano:
termux
# Nanosecond-resolution timestamps written into the PCAP
tcpdump -i wlan0 --time-stamp-precision=nano -w ~/storage/shared/Download/hires.pcap

# Read back with full date + time
tcpdump -r ~/storage/shared/Download/hires.pcap -tttt -n | head

6. Compress PCAPs On Rotation

Skip the fragile -w - | gzip pipe — tcpdump has a built-in post-rotation hook:

termux
# -z gzip compresses each rotated file after it closes
tcpdump -i wlan0 -G 3600 -W 24 -z gzip -w ~/storage/shared/Download/rot.pcap
termux
# Read compressed captures back
zcat ~/storage/shared/Download/rot.pcap1.gz | tcpdump -r - -n | head

Troubleshooting the Mobile Sniffer

IssueCauseFix
tcpdump: wlan0: No such deviceWrong interface nameip link show; try any
You don't have permission to capture on that device (socket: Operation not permitted)SELinux blocks packet sockets for non-root appsUse PCAPdroid (VPN mode) for non-root capture, or tsu/root
Permission denied writing PCAPScoped storage / missing symlinkRun termux-setup-storage; write to ~/storage/shared/Download/, not /sdcard/
packets dropped by kernelCapture buffer overflowEnlarge the kernel buffer: tcpdump -B 65535 (≈64 MiB)
tcpdump: unknown interfaceInterface downip link set wlan0 up (may need root)
Capture file empty/0 packetsKilled with kill -9Always stop with Ctrl+C (SIGINT) for a clean PCAP close
tshark: command not foundNot in Termux main repoAdd root-repo (capture needs root) or install inside proot-distro
SSH drops mid-captureBattery optimizationSet all Termux apps to "Unrestricted"; hold termux-wake-lock
PCAPdroid VPN won't startAnother VPN is activeDisable other VPN apps — Android allows one VPN slot

Takeaways

  • Non-root tcpdump is a reader, not a sniffer — SELinux neverallows packet sockets for untrusted_app, so capture fails with Operation not permitted. Install it anyway: tcpdump -r and BPF filtering work perfectly without root.
  • PCAPdroid is the non-root capture engine — local VPN mode sees every app's traffic, exports standard PCAP and SSLKEYLOGFILE, and costs you only the VPN slot and some battery.
  • proot-distro buys tooling, not privilege — tshark, zeek, mitmproxy all run inside it for analysis, but capture stays blocked by the same SELinux wall.
  • Rotation is non-negotiable on mobile-C/-W for size, -G for time, -z gzip to shrink everything; otherwise a long capture eats the phone's storage.
  • Transfer to Wireshark for real analysis — phones capture, laptops dissect. SSH/SCP is the cleanest pipeline, and battery exemption + wake lock keep the sensor alive.

Anchor Insight

Android hands you a packet-capture engine in your pocket — then locks it behind SELinux for non-root apps. Treat tcpdump as your reader and filter engine, PCAPdroid as your non-root sniffer, proot-distro as your analysis lab, and root as the only way past the wall. Capture locally, analyze centrally, automate via SSH.


Related Articles (Internal Linking)


Last verified: August 14, 2026 | Termux v0.119+ | tcpdump 4.99.x (Termux root repo) | Android 10–14 tested | PCAPdroid 1.9.x