The Android project includes libpcap as an external library as can be seen from the source here on kernel.org and Github
My project for Google Summer of Code - The mobile network scanner requires the use of libpcap or tcpdump. I was successful in compiling libpcap from its source and loading the library to use the native functions in JNI. But since an Android application does not run with Root privileges, it is a challenge to get the native functions to work in the same process.
The native code and the Java code for an android application runs in the same process. So the native code does not have root privileges. So as of now, it is not possible to get libpcap functions to work using the NDK. But there are alternatives which I will be suggesting in this blog post.
First of all, here are the instructions to successfully compile the libpcap.so library for use in the JNI code.
Create a folder called jni in the application root.
Android.mk
LOCAL_PATH := ./jni
include $(CLEAR_VARS)
LOCAL_MODULE := pcaptest
LOCAL_SRC_FILES := libpcap-native.c
LOCAL_C_INCLUDES := $(NDK_ROOT)/external/libpcap
LOCAL_STATIC_LIBRARIES := libpcap
LOCAL_LDLIBS := -ldl -llog
include $(BUILD_SHARED_LIBRARY)
include $(NDK_ROOT)/external/libpcap/Android.mk
Libpcap for android is built as a static library and its functions are then used as a shared library.
A shared library build specifications are defined in the Android.mk make file in the JNI folder of the project. The JNI folder contains the make files for the library. It also contains the native C code with function definitions according to the Java package.
This is a sample JNI code for getting the list of available network interfaces by using the pcap_lookupdevs function
#include
#include
#include
#include
#define DEBUG_TAG "Sample_LIBPCAP_DEBUGGING"
void Java_org_umit_android_libpcaptest_libpcaptest_testLog(JNIEnv *env, jclass clazz, jstring message)
{
char errbuf[1024];
errbuf[0] = '\0';
char *szLogThis;
char *dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
szLogThis = "Couldn't find default device";
}
else szLogThis = dev;
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "Device status: [%s]", szLogThis);
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "errbuf [%s]", errbuf);
(*env)->ReleaseStringUTFChars(env, message, szLogThis);
}
The C code can now be called as native functions from inside Java code by loading the shared librarystatic{
System.loadLibrary("pcaptest");
}
private native void testLog(String logThis);
The native code needs to compiled with ndk-build command and requires the android-ndk to be downloaded from the official website.
For now, I am getting the error
D/Sample_LIBPCAP_DEBUGGING( 364): Device status: [Couldn't open device]
D/Sample_LIBPCAP_DEBUGGING( 364): errbuf [socket: Operation not permitted]
And when I try and use the pcap_open_live function, I get the following error
D/Sample_LIBPCAP_DEBUGGING( 310): errbuf [socket: Operation not permitted]
The reason for this error is that the native code and the application both lie in the same process. Invoking a "su" here would not work because an "su" just forks a new process that has root privileges but that process would not contain our native code.
So a work around for this is that a binary or a unix library should be compiled before hand and then supplied with the apk. The binary can be extracted from the apk. The binary may require root privileges but it would be as easy as forking another process with "su" command.
Here is a blog post explaining that http://nerdposts.blogspot.com/2010/11/android-superuser-shared-jni-libs.html
For now, I am just sticking to tcpdump for the requirements of this project. If we need a specific implementation of packet sniffing from libpcap, the plan is to compile a binary or a unix shared library and supply it with the apk.
8 comments: