Thursday, June 2, 2011

Run TcpDump from Android application and read output

Few month ago I start to write an Android application for an academic project, the aim is to build a network management tool for Android.


The first step to build this application is to intercept packets. To achieve that we use TcpDump. Run TcpDump seems easy at first, but actualy it's not. I will demonstrate in this post how we achieve that.

Before I start my explanation please note two important things :
  1. TcpDump requires root privilege, so you need a rooted phone or a rooted emulator.
  2. We need to launch TcpDump in a new process, and create process inside Java is absolutely not standard, so this method is only appropriate to write an experimental application.
TcpDump binary
TcpDump is a command line tool written in C, to use it on Android it has to be compile for ARM architecture, you can find this binary here. You have to push this file on the device, you can do that via adb :
 ./adb push ./tcpdump-arm /data/local/  
TcpDump needs the correct permission to be executed :
 ./adb shell chmod 777 /data/local/tcpdump-arm  
Now you can try to run TcpDump on the device :
 ./adb shell /data/local/tcpdump-arm -l > /data/local/output.txt  
The -l option is useful if you want to see data while capturing. We redirect stdout to a file. At this step you should see the captured packets listed in /data/local/output.txt as well as displayed on your terminal. You may have to specify your network device name, use the netcfg command to display all interfaces. With my Galaxy S the command is :
 ./adb shell /data/local/tcpdump-arm -l -i eth0 > /data/local/output.txt  

Start and stop TcpDump
If you want to start TcpDump in an application you need to do that in Java, here is the code I use :
1:  String commande="/data/local/tcpdump-arm -l -i eth0 > /data/local/output.txt\n";  
2:  //create a process with root privilege, tcpdump require root  
3:   process = Runtime.getRuntime().exec("su");  
4:   DataOutputStream os = new DataOutputStream(process.getOutputStream());  
5:   os.writeBytes(commande);  
6:   os.flush();  
7:   os.writeBytes("exit\n");  
8:   os.flush();  
9:   os.close();  
10:         
As you can notice the process in which TcpDump run will never stop, the only way to stop it is to kill it, to do that we need the pid of the process.
1:  //sleep 1 second to ensure that the new process is listed by the system  
2:   Thread.sleep(1000);  
3:         
4:   /* get the pid of the process in which we exec tcpdump  
5:   * to do that we use the ps command, so we need to launch another process to achieve that  
6:   */  
7:   Process process2 = Runtime.getRuntime().exec("ps tcpdump-arm");  
8:   //read the output of ps  
9:   DataInputStream in = new DataInputStream(process2.getInputStream());  
10:   String temp= in.readLine();  
11:   temp = in.readLine();  
12:   //We apply a regexp to the second line of the ps output to get the pid  
13:   temp = temp.replaceAll("^root *([0-9]*).*","$1");  
14:   pid = Integer.parseInt(temp);  
15:           
16:   //the ps process is no more needed  
17:   process2.destroy();  
As I said we stop TcpDump by killing the process :
1:  //to kill tcpdump process we create a new process to run the kill command  
2:  //this process terminate immediately so we doesn't need to kill it  
3:  String killCommand = "kill "+pid;  
4:  Process process2 = Runtime.getRuntime().exec("su");  
5:  DataOutputStream os = new DataOutputStream(process2.getOutputStream());  
6:  os.writeBytes(killCommand);  
7:  os.flush();  
8:  os.writeBytes("exit\n");  
9:  os.flush();  
10:  os.close();  

Read TcpDump output
Here the main problem is to read data in real time. If you read on stdout of the TcpDump's process, data are buffered until the process is destroy. To fix this the output is redirected to a file and another thread read in this file. Here is the content of the run method :
1:  dumpedFile = new File("/data/local/output.txt");  
2:  //open a reader on the tcpdump output file  
3:  BufferedReader reader = new BufferedReader(new FileReader(dumpedFile));  
4:  String temp = new String();  
5:  //The while loop is broken if the thread is interrupted    
6:  while (!Thread.interrupted()) {    
7:       temp = reader.readLine();  
8:       if (temp!=null) {  
9:            Log.e("READER",new String(temp));  
10:            buffer.put(new String(temp));   
11:       }  
12:  }            

This method works for TcpDump but it can be use for another programs. If you want to use this method in your application you should have a look at the complete source code available here.
If you have any suggestion or comment feel free to comment this post.

11 comments:

  1. Great information here. thanks for providing this android output. let me try this. joomla developer

    ReplyDelete
  2. My program failed, the command didn't work. I've emailed you. Please help me.

    ReplyDelete
    Replies
    1. I copy your question here, so that everybody can benefit from it :

      "I want to capture web packages in Android mobile. The shell code for tcpdump is similar to yours. However, nothing happens in my emulator. It seems that the shell code doesn't work. So my question is whether it works on the real mobile? Does the mobile need to be rooted?"

      Yes you need a routed phone or at least a rooted emulator. It was test on a Samsung Galaxy S running Android 2.2.
      How you test the shell code ? Have you copy my Java code inside your application or you try in command line ?
      If you try it in command line, the "> /data/local/output.txt" make the output to be redirected in a file. To display the result you have to open it.

      I hope this help :)

      Delete
  3. how can i filter the output of tcpdump?
    for example if i want to apply a filter based on an application.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
  4. I don't think you can filter by application directly with tcpdump (by adding some options to the tcpdump command), here is the : tcpdump manpage. But tcpdump is a very advance tool and the Android version has the same features than the normal version. Maybe ask on tcpdump mailing list or forums...

    ReplyDelete
  5. hi thr...
    i m developing a packet sniffer for android and ur code is great for that.
    nw i am trying to implement ur code.all seems fine.tcpdump works well and output.txt contains the output.hw to display tht out put in txtview?

    ReplyDelete
  6. Thanks for the great post.

    --------------------------------------------------------------------------------------------------------------
    iPhone App Development & iOS App Development & Android Application Development

    ReplyDelete
  7. I’m really lucky and so glad that after surfing the web for a long time I have found out this information.
    Us Technical Support

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Hello, I'm trying to kill a TcpDump process which is exectuted in a Service in the background.
    I get the PID of the process, but when I try to kill the process, it doesn't work. It aslo sends a signal for killing the process like this:
    I/Process: Sending signal. PID: 7193 SIG: 9

    Thanks

    ReplyDelete