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:
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 plainpkg install tcpdumpon a stock setup fails until you add the repo — and even then, capture requirestsu/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:
- Install PCAPdroid from F-Droid (or GitHub releases).
- Open the app → Start capture → grant the VPN permission when Android asks.
- Use the phone normally — every app's traffic lands in the dump, not just yours.
- 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
SSLKEYLOGFILEexport 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:
# 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
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
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-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
| Capability | Root | Non-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:
ip link show
ip -br addr
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 Ethernetany— 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:
# Capture on Wi-Fi, write PCAP to shared storage
tcpdump -i wlan0 -w ~/storage/shared/Download/capture.pcap
Flags explained:
-i wlan0— interface (useanyif 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:
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:
^C
47 packets captured
52 packets received by filter
0 packets dropped by kernel
Verify the file, then read it back:
ls -lh ~/storage/shared/Download/capture.pcap
file ~/storage/shared/Download/capture.pcap
# Output: PCAP file, version 2.4, little-endian, 65535 snaplen
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:
# 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:
# 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-wfilename should contain astrftime(3)format.
# 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:
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:
# 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:
# 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):
# 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:
pkg install termux-api
termux-share ~/storage/shared/Download/capture.pcap
Option D — rsync via SSH:
rsync -avz -e "ssh -p 8022" u0_a123@192.168.1.50:~/storage/shared/Download/*.pcap ./captures/
Wireshark Display-Filter Cheatsheet
| Goal | Display Filter |
|---|---|
| HTTP only | http |
| HTTPS/TLS | tls or ssl |
| DNS queries | dns.flags.response == 0 |
| DNS responses | dns.flags.response == 1 |
| Specific IP | ip.addr == 192.168.1.50 |
| Specific port | tcp.port == 443 or udp.port == 53 |
| TCP retransmissions | tcp.analysis.retransmission |
| TLS handshake | tls.handshake |
| Plaintext creds | http 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:
pkg install -y proot-distro
proot-distro install kali
proot-distro login kali
# 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:
# 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-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:
#!/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
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
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
pkg install -y cronie
crond
crontab -e
# 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 0does 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.-ttttis 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:
# 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:
# -z gzip compresses each rotated file after it closes
tcpdump -i wlan0 -G 3600 -W 24 -z gzip -w ~/storage/shared/Download/rot.pcap
# Read compressed captures back
zcat ~/storage/shared/Download/rot.pcap1.gz | tcpdump -r - -n | head
Troubleshooting the Mobile Sniffer
| Issue | Cause | Fix |
|---|---|---|
tcpdump: wlan0: No such device | Wrong interface name | ip 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 apps | Use PCAPdroid (VPN mode) for non-root capture, or tsu/root |
Permission denied writing PCAP | Scoped storage / missing symlink | Run termux-setup-storage; write to ~/storage/shared/Download/, not /sdcard/ |
packets dropped by kernel | Capture buffer overflow | Enlarge the kernel buffer: tcpdump -B 65535 (≈64 MiB) |
tcpdump: unknown interface | Interface down | ip link set wlan0 up (may need root) |
| Capture file empty/0 packets | Killed with kill -9 | Always stop with Ctrl+C (SIGINT) for a clean PCAP close |
tshark: command not found | Not in Termux main repo | Add root-repo (capture needs root) or install inside proot-distro |
| SSH drops mid-capture | Battery optimization | Set all Termux apps to "Unrestricted"; hold termux-wake-lock |
| PCAPdroid VPN won't start | Another VPN is active | Disable 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 withOperation not permitted. Install it anyway:tcpdump -rand 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/-Wfor size,-Gfor time,-z gzipto 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)
- Termux on Android (Non-Root): Complete Setup & Optimization Guide — Foundation: install, storage, SSH, proot-distro, zram
- Android Pentesting Without Root: Network Recon & MITM — Turn captures into assessments: nmap, bettercap, mitmproxy workflows
- Kali Linux in Termux: proot-distro vs. Nethunter vs. chroot — Choose the right Kali setup for full toolchains (tshark, zeek, suricata)
- SSH Hardening for Exposed Services — Secure the remote control channel for your mobile lab
Last verified: August 14, 2026 | Termux v0.119+ | tcpdump 4.99.x (Termux root repo) | Android 10–14 tested | PCAPdroid 1.9.x
