If you have rooted phone, go for nethogs
(for live monitoring) or iptables
(to get statistics) commandline tools. Using VPN or Android stats based apps is the only possible non-root solution. Or refer to this answer for a logcat
/dumpsys
based solution.
First of all, tracking a UID or PID of a network stream isn't straight forward because these aren't network related but OS related parameters. Proposals and abandoned projects do exist.
Android assigns a unique UID to every installed app just like every human user on Linux has a UID. So we can capture packets sent by a specific UID over the network interfaces to track the usage.
TCPDUMP:
Now how we can capture network traffic? Most of the network sniffers use libpcap family of system-independent libraries for this purpose. It supports BSD Packet Filter (BPF) for in-kernel packet filtering. Some popular utilities that use libpcap
include tcpdump
, nmap
, tshark/wireshark
, dumpcap
, nethogs
etc. Android app Network Utilities and others also make use of tcpdump
.
However UID info is not propagated through the AF_PACKET
/PF_PACKET
channel that pcap
uses at OSI Layer 2. So what we can do here is to make use of network sockets (combination of IP and port) being created and used by an app. netstat -tup
or ss -tup
will show all network sockets with active/established connections. Both tools are available on Android (or you can get a static binary), ss
is the newer one. Socket vs. UID information can also be directly read from /proc/net/{tcp,udp}
. Android app Netstat Plus works on same principle. This will provide Local Address (socket) being used by a process.
Once we know what sockets are being used by an app (UID), tcpdump -i wlan0 src <IP> and port <PORT>
will dump the whole traffic originated from that process.
Similarly a remote socket (if not connected to by multiple apps) can also be used for filtering results.
LIMITATIONS:
However there are some issues with this approach:
- Android apps usually launch more than one process at a time in parallel i.e. multiple PIDs working under same UID. So we have to capture traffic from all processes.
- Apps keep on creating and deleting sockets. Keeping track of continuously changing sockets is almost impossible particularly when there are a large number of apps accessing network simultaneously.
- There is - though rare - possibility that local sockets are being shared by multiple processes on UNIX-like OS's. Remote shared sockets such as UDP/53 which is used for DNS resolution cannot be tracked for a single process. This further weakens the approach.
NetHogs traverses procfs
and copes with the above limitations (though not always very successful):
IPTABLES:
The above described shortcomings of a Layer 2 tool can be mitigated using iptables LOG
or NFLOG
. Layer 2 is just above the Physical Layer i.e. it's the last thing packets encounter before leaving the device. That's why, being at Data Link Layer and working at lower level of net stack, BPF is a kind of stateless packet filtering mechanism as compared to netfilter
/ iptables
which works at OSI Layer 3 (nearer to userspace programs). So iptables
can also get information from TCP/IP stack (Layer 4). It filters packets based on their creator UIDs using module owner
that interacts with sockets to find packet ownership.
iptables
writes to kernel log which can be read using dmesg
or logcat
. UID of an app can be obtained using some app or read from /data/system/packages.list
or pm list packages -U
.
# iptables -I OUTPUT -m owner --uid-owner <UID> -j LOG --log-level 7 --log-prefix 'SNIFFER: ' --log-uid
# dmesg -w | grep SNIFFER
Output can be saved to a file and formatted using tools like grep
, awk
, printf
etc. Network Log - though very outdated - works in similar way. AFWall+ is a firewall based on iptables
that can log / notify an app's network activity when the app is blocked.
The only downside with this approach is that it cannot be used to sniff traffic from one process when there are multiple processes running with same UID. iptables
can't capture packets based on PIDs. They decided not to use iptables
with processes because the process is started before it is blocked/sniffed, and program could easily spawn a child process with new PID which would not be blocked / sniffed. Also PIDs are created and destroyed as quick as sockets are. So there is always room for traffic being leaked.
QTAGUID:
owner
module won't work for incoming or forwarded traffic because IP packets carry no ownership information. To measure per-app incoming / outgoing network usage, Android patched kernel to include qtaguid
module. We can read statistics from /proc/net/xt_qtaguid/stats
. With some shell scripting get live data usage since reboot:
However on Android 9+, qtaguid
is being replaced with extended BPF (which is also planned to replace netfilter
framework in Linux kernel). Related: Which process is responsible for capturing data usage?
IPTABLES + TCPDUMP:
An alternate is to put the outgoing traffic from an app in an NFLOG
group and later tcpdump captures packets from that group:
# iptables -I OUTPUT -m owner --uid-owner 1000 -j NFLOG --nflog-group 30
# tcpdump -i nflog:30
This is to ensure that we get closer to physical layer when sniffing outgoing traffic. But it can still give false positives e.g. if packets are dropped / lost in routing tables. That's why sniffers work at OSI layer 2. Or even better is to watch from outside e.g. using a proxy / VPN server or on a tethered PC or at router. But this won't capture traffic on per UID/PID basis.
OTHER OPTIONS:
- Use diagnostic tools like
strace
to track syscalls
related to network activity of a process. force_bind and tracedump also work on same principle. Linux kernel's audit subsystem can be used for the same.
- Use Network classifier cgroup with
iptables
NETFILTER_XT_MATCH_CGROUP
to sniff traffic from certain process(es).
- Use
Network Namespaces
to isolate processes and read data usage on per interface basis. nstrace works on same principle.
- If the intention is entirely to block traffic originating from certain processes,
SELinux
and seccomp
can be used to restrict the processes' ability to create sockets by defining restricted policies
and suppressing syscalls
respectively.
Most of these are not straightforwardly viable options for Android and require advanced configurations.
ANDROID'S APIs (NON-ROOT OPTIONS):
Some apps like NetGuard use VpnService API of Android to block traffic at Layer 3 (TUN interface). The app can "notify when an application accesses the internet". Per app capturing and tracking (1, 2) is possible using VPN API as Android makes use of UIDs
and SOcket_MARKs
(1, 2) to control traffic in network Routing Policy (RPDB), just before leaving the device.
Some apps like NetLive make use of NetworkStatsManager, but it lags the real-time usage and "does not update quickly enough", it's "meant to provide historical data".
NOTE: I've no affiliation with any app referenced.
RELATED: