I am developing an android application to monitor network usage in android devices.
One of the application requirements is to provide a “.pcap” file created by tcpdump command. When I try to execute tcpdum command from adb shell, everything works fine and I am able to create this file. But when I try to execute this command from the device itself, using a java code, I get permission denied error.
It should be mentioned that my java code works fine for other commands that do not demand a special privilege.
It also should be mentioned that I used two of the following rooted devices (first Samsung – running android 4.4, second samsung - running android 5.1.1)
Moreover, I tried to install another tcpdump binary and gave it execution privilege and also tried a different variations of tcpdump command in order to obtain a privilege with “su”. From what I understand, this is the behavior of the kernel and it’s for security reasons, but despite this, I would like to know If is there a way to get around this / give my application the permissions it need in order to run the mentioned commands. Below, the commands I tried to run and the responses that I was given.
Command: tcpdump -l -i eth1 -w /sdcard/output.pcap Response: tcpdump: eth1: You don't have permission to capture on that device (socket: Operation not permitted)
Command: tcpdump -w /sdcard/output.pcap Response: tcpdump: Can't open netlink socket 13:Permission denied
Response: tcpdump: rmnet0: You don't have permission to capture on that device.
my manifest permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
the relevant code:
public static boolean executeCommandViaShell(String sCmd) {
DataInputStream isErr = null, isRes = null;
BufferedReader brErr = null, brRes = null;
try {
Process process = Runtime.getRuntime().exec(sCmd);
isErr = new DataInputStream(process .getErrorStream());
brErr = new BufferedReader(new InputStreamReader(isErr));
isRes = new DataInputStream(process .getInputStream());
brRes = new BufferedReader(new InputStreamReader(isRes));
// errors:
while ((m_sMessage = brErr.readLine()) != null) {
if (m_sMessage.equalsIgnoreCase("INVALID"))
{
return false;
}
}
while ((m_sMessage = brRes.readLine()) != null) {
if (m_sMessage.equals("SUCCESS")) {
Log.d(TAG, "SUCCESS m_sMessage: " + m_sMessage);
}
else {
return false;
}
}
return true;
}
catch (Exception e) {
e.printStackTrace();
return false;
}
finally {
try {
isErr.close();
isRes.close();
brErr.close();
brRes.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}