Show nDPI information

NOTE: the code is still buggy and crashes randomly due to
unaligned accesses
This commit is contained in:
emanuele-f 2019-11-10 00:30:31 +01:00
parent 03b6a391c1
commit 4e25aac8e6
10 changed files with 164 additions and 21 deletions

View File

@ -66,5 +66,6 @@ In order to run without root, the app takes advantage of the Android VPNService
2. Clone https://github.com/emanuele-f/zdtun beside this repository
3. Clone https://github.com/ntop/nDPI beside this repository
4. Link the cmake file into nDPI: from this repo execute: `ln -s $(readlink -f nDPI/CMakeLists.txt) ../nDPI`
5. Build the `zdtun` and `ndpi` modules first
6. Then build the `app` module
4. Inside the nDPI directory, run `./autogen.sh`
6. Build the `zdtun` and `ndpi` modules first
7. Then build the `app` module

View File

@ -36,4 +36,5 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':zdtun')
implementation 'cat.ereza:customactivityoncrash:2.2.0'
implementation project(path: ':ndpi')
}

View File

@ -19,13 +19,15 @@ class ConnDescriptor implements Serializable {
int sent_pkts;
int rcvd_pkts;
String info;
String l7proto;
int uid;
int incr_id;
/* Invoked by native code */
public void setData(int _ipproto, String _src_ip, String _dst_ip, int _src_port, int _dst_port,
long _first_seen, long _last_seen, long _sent_bytes, long _rcvd_bytes,
int _sent_pkts, int _rcvd_pkts, String _info, int _uid, int _incr_id) {
int _sent_pkts, int _rcvd_pkts, String _info, String _l7proto, int _uid,
int _incr_id) {
/* Metadata */
ipproto = _ipproto;
src_ip = _src_ip;
@ -41,6 +43,7 @@ class ConnDescriptor implements Serializable {
sent_pkts = _sent_pkts;
rcvd_pkts = _rcvd_pkts;
info = _info;
l7proto = _l7proto;
uid = _uid;
incr_id = _incr_id;
}

View File

@ -43,19 +43,21 @@ public class ConnectionsAdapter extends BaseAdapter {
assert conn != null;
ImageView icon = convertView.findViewById(R.id.icon);
TextView remote = convertView.findViewById(R.id.remote);
TextView l7proto = convertView.findViewById(R.id.l7proto);
TextView traffic = convertView.findViewById(R.id.traffic);
AppDescriptor app = mActivity.findAppByUid(conn.uid);
Drawable appIcon;
if(app != null)
appIcon = Objects.requireNonNull(app.getIcon().getConstantState()).newDrawable();
else
appIcon = mUnknownIcon;
appIcon = (app != null) ? Objects.requireNonNull(app.getIcon().getConstantState()).newDrawable() : mUnknownIcon;
icon.setImageDrawable(appIcon);
remote.setText(String.format(mActivity.getResources().getString(R.string.ip_and_port),
conn.dst_ip, conn.dst_port));
if(conn.info.length() > 0)
remote.setText(conn.info);
else
remote.setText(String.format(mActivity.getResources().getString(R.string.ip_and_port),
conn.dst_ip, conn.dst_port));
l7proto.setText(conn.l7proto);
traffic.setText(Utils.formatBytes(conn.sent_bytes + conn.rcvd_bytes));
return(convertView);

View File

@ -154,7 +154,8 @@ public class MainActivity extends AppCompatActivity implements LoaderManager.Loa
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "ConnectionsFragment", mConnectionsFragment);
if(mConnectionsFragment != null)
getSupportFragmentManager().putFragment(outState, "ConnectionsFragment", mConnectionsFragment);
}
@Override

View File

@ -8,7 +8,8 @@ add_library(vpnproxy-jni
pcap)
include_directories(../../../..)
include_directories(../../../../../../../src/zdtun)
include_directories(../../../../../../zdtun)
include_directories(../../../../../../nDPI/src/include)
find_library( log-lib
log)
@ -24,6 +25,13 @@ if (NOT zdtun-lib)
message(FATAL_ERROR "zdtun not found!")
endif()
set(ndpi-lib ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../ndpi/build/intermediates/library_and_local_jars_jni/debug/${ANDROID_ABI}/libndpi.so)
if (NOT ndpi-lib)
message(FATAL_ERROR "nDPI not found!")
endif()
target_link_libraries( vpnproxy-jni
${zdtun-lib}
${ndpi-lib}
${log-lib})

View File

@ -21,10 +21,12 @@
#include <netinet/ip.h>
#include "vpnproxy.h"
#include "pcap.h"
#include "../../../../../../nDPI/src/include/ndpi_protocol_ids.h"
#define VPN_TAG "VPNProxy"
#define CAPTURE_STATS_UPDATE_FREQUENCY_MS 300
#define CONNECTION_DUMP_UPDATE_FREQUENCY_MS 3000
#define MAX_DPI_PACKETS 12
/* ******************************************************* */
@ -41,12 +43,18 @@ typedef struct dns_packet {
uint16_t additional_rrs;
uint8_t initial_dot; // just skip
uint8_t queries[];
} dns_packet_t __attribute__((packed));
} __attribute__((packed)) dns_packet_t;
/* ******************************************************* */
typedef struct conn_data {
int incr_id; /* an incremental identifier */
/* nDPI */
struct ndpi_flow_struct *ndpi_flow;
struct ndpi_id_struct *src_id, *dst_id;
ndpi_protocol l7proto;
time_t first_seen;
time_t last_seen;
u_int64_t sent_bytes;
@ -198,6 +206,84 @@ static char* getApplicationByUid(vpnproxy_data_t *proxy, int uid, char *buf, siz
/* ******************************************************* */
struct ndpi_detection_module_struct* init_ndpi() {
struct ndpi_detection_module_struct *ndpi = ndpi_init_detection_module();
NDPI_PROTOCOL_BITMASK protocols;
if(!ndpi)
return(NULL);
// enable all the protocols
NDPI_BITMASK_SET_ALL(protocols);
ndpi_set_protocol_detection_bitmask2(ndpi, &protocols);
ndpi_finalize_initalization(ndpi);
return(ndpi);
}
/* ******************************************************* */
void free_ndpi(conn_data_t *data) {
if(data->ndpi_flow) {
ndpi_free_flow(data->ndpi_flow);
data->ndpi_flow = NULL;
}
if(data->src_id) {
ndpi_free(data->src_id);
data->src_id = NULL;
}
if(data->dst_id) {
ndpi_free(data->dst_id);
data->dst_id = NULL;
}
}
/* ******************************************************* */
const char *getL7ProtoName(struct ndpi_detection_module_struct *mod, ndpi_protocol l7proto) {
return ndpi_get_proto_name(mod, l7proto.master_protocol);
}
/* ******************************************************* */
static void process_ndpi_packet(conn_data_t *data, vpnproxy_data_t *proxy, const char *packet,
ssize_t size, uint8_t from_tap) {
bool giveup = ((data->sent_pkts + data->rcvd_pkts) >= MAX_DPI_PACKETS);
data->l7proto = ndpi_detection_process_packet(proxy->ndpi, data->ndpi_flow, packet, size, data->last_seen,
from_tap ? data->src_id : data->dst_id,
from_tap ? data->dst_id : data->src_id);
if(giveup || ((data->l7proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) &&
(!ndpi_extra_dissection_possible(proxy->ndpi, data->ndpi_flow)))) {
if (data->l7proto.app_protocol == NDPI_PROTOCOL_UNKNOWN) {
uint8_t proto_guessed;
data->l7proto = ndpi_detection_giveup(proxy->ndpi, data->ndpi_flow, 1 /* Guess */,
&proto_guessed);
}
__android_log_print(ANDROID_LOG_DEBUG, VPN_TAG, "l7proto: app=%d, master=%d",
data->l7proto.app_protocol, data->l7proto.master_protocol);
switch (data->l7proto.master_protocol) {
case NDPI_PROTOCOL_DNS:
case NDPI_PROTOCOL_HTTP:
case NDPI_PROTOCOL_TLS:
if (data->ndpi_flow->host_server_name[0]) {
data->info = strdup(data->ndpi_flow->host_server_name);
__android_log_print(ANDROID_LOG_DEBUG, VPN_TAG, "info: %s", data->info);
}
break;
}
free_ndpi(data);
}
}
/* ******************************************************* */
static void account_packet(zdtun_t *tun, const char *packet, ssize_t size, uint8_t from_tap, const zdtun_conn_t *conn_info) {
struct sockaddr_in servaddr = {0};
conn_data_t *data = (conn_data_t*)conn_info->user_data;
@ -232,6 +318,9 @@ static void account_packet(zdtun_t *tun, const char *packet, ssize_t size, uint8
data->last_seen = time(NULL);
if(data->ndpi_flow)
process_ndpi_packet(data, proxy, packet, size, from_tap);
if(((proxy->pcap_dump.uid_filter != -1) && (proxy->pcap_dump.uid_filter != uid))
&& (!is_unknown_app || !proxy->pcap_dump.capture_unknown_app_traffic)) {
//__android_log_print(ANDROID_LOG_DEBUG, VPN_TAG, "Discarding connection: UID=%d [filter=%d]", uid, proxy->pcap_dump.uid_filter);
@ -323,6 +412,22 @@ static int handle_new_connection(zdtun_t *tun, const zdtun_conn_t *conn_info, vo
return(1);
}
/* nDPI */
if((data->ndpi_flow = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT)) == NULL) {
__android_log_print(ANDROID_LOG_ERROR, VPN_TAG, "ndpi_flow_malloc failed");
free_ndpi(data);
}
if((data->src_id = ndpi_malloc(SIZEOF_ID_STRUCT)) == NULL) {
__android_log_print(ANDROID_LOG_ERROR, VPN_TAG, "ndpi_malloc(src_id) failed");
free_ndpi(data);
}
if((data->dst_id = ndpi_malloc(SIZEOF_ID_STRUCT)) == NULL) {
__android_log_print(ANDROID_LOG_ERROR, VPN_TAG, "ndpi_malloc(dst_id) failed");
free_ndpi(data);
}
data->incr_id = proxy->incr_id++;
data->first_seen = data->last_seen = time(NULL);
data->uid = resolve_uid(proxy, conn_info);
@ -342,6 +447,8 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) {
return;
}
free_ndpi(data);
if(data->info)
free(data->info);
@ -497,6 +604,7 @@ static int connection_dumper(zdtun_t *tun, const zdtun_conn_t *conn_info, void *
}
jobject info_string = (*env)->NewStringUTF(env, data->info ? data->info : "");
jobject proto_string = (*env)->NewStringUTF(env, getL7ProtoName(proxy->ndpi, data->l7proto));
jobject src_string = (*env)->NewStringUTF(env, srcip);
jobject dst_string = (*env)->NewStringUTF(env, dstip);
jobject conn_descriptor = (*env)->NewObject(env, dump_data->conn_cls, dump_data->conn_constructor);
@ -513,7 +621,7 @@ static int connection_dumper(zdtun_t *tun, const zdtun_conn_t *conn_info, void *
(*env)->CallVoidMethod(env, conn_descriptor, dump_data->conn_set_data,
conn_info->ipproto, src_string, dst_string, ntohs(conn_info->src_port), ntohs(conn_info->dst_port),
data->first_seen, data->last_seen, data->sent_bytes, data->rcvd_bytes,
data->sent_pkts, data->rcvd_pkts, info_string, data->uid, data->incr_id);
data->sent_pkts, data->rcvd_pkts, info_string, proto_string, data->uid, data->incr_id);
/* Add the connection to the array */
(*env)->SetObjectArrayElement(env, dump_data->connections, dump_data->idx++, conn_descriptor);
@ -551,7 +659,7 @@ static void sendConnectionsDump(zdtun_t *tun, vpnproxy_data_t *proxy) {
/* NOTE: must match ConnDescriptor::setData */
dump_data.conn_set_data = (*env)->GetMethodID(env, dump_data.conn_cls, "setData",
"(ILjava/lang/String;Ljava/lang/String;IIJJJJIILjava/lang/String;II)V");
"(ILjava/lang/String;Ljava/lang/String;IIJJJJIILjava/lang/String;Ljava/lang/String;II)V");
if(dump_data.conn_set_data == NULL) {
__android_log_print(ANDROID_LOG_ERROR, VPN_TAG, "GetMethodID(conn_set_data) failed");
return;
@ -613,7 +721,7 @@ static int connect_dumper(vpnproxy_data_t *proxy) {
servaddr.sin_port = proxy->pcap_dump.collector_port;
servaddr.sin_addr.s_addr = proxy->pcap_dump.collector_addr;
if(connect(dumper_socket, &servaddr, sizeof(servaddr)) < 0) {
if(connect(dumper_socket, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
__android_log_print(ANDROID_LOG_ERROR, VPN_TAG,
"connection to the PCAP receiver failed [%d]: %s", errno,
strerror(errno));
@ -665,6 +773,14 @@ static int run_tun(JNIEnv *env, jclass vpn, int tapfd, jint sdk) {
send_header = true;
running = 1;
/* nDPI */
proxy.ndpi = init_ndpi();
if(proxy.ndpi == NULL) {
__android_log_print(ANDROID_LOG_FATAL, VPN_TAG, "nDPI initialization failed");
return(-1);
}
signal(SIGPIPE, SIG_IGN);
// Set blocking
@ -750,6 +866,7 @@ static int run_tun(JNIEnv *env, jclass vpn, int tapfd, jint sdk) {
__android_log_print(ANDROID_LOG_DEBUG, VPN_TAG, "Stopped packet loop");
ztdun_finalize(tun);
ndpi_exit_detection_module(proxy.ndpi);
if(dumper_socket > 0) {
close(dumper_socket);

View File

@ -20,6 +20,7 @@
#include <jni.h>
#include <android/log.h>
#include "zdtun.h"
#include "ndpi_api.h"
#ifndef REMOTE_CAPTURE_VPNPROXY_H
#define REMOTE_CAPTURE_VPNPROXY_H
@ -39,12 +40,12 @@ typedef struct vpnproxy_data {
int incr_id;
jint sdk;
JNIEnv *env;
jobject handler_cls; // TODO remove?
jobject vpn_service;
u_int32_t vpn_dns;
u_int32_t public_dns;
u_int32_t vpn_ipv4;
bool dns_changed;
struct ndpi_detection_module_struct *ndpi;
struct {
u_int32_t collector_addr;

View File

@ -1,19 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:paddingHorizontal="10dp"
android:paddingHorizontal="5dp"
android:layout_height="40dp">
<ImageView
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_marginEnd="10dp"
android:layout_marginEnd="5dp"
android:id="@+id/icon"/>
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="0.7"
android:layout_weight="0.2"
android:text="HTTP"
android:gravity="center_vertical"
android:layout_marginEnd="5dp"
android:id="@+id/l7proto"/>
<TextView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="0.5"
android:text="example.org:80"
android:gravity="center_vertical"
android:id="@+id/remote"/>

View File

@ -9,9 +9,9 @@ add_definitions(-DNDPI_LIB_COMPILATION)
include_directories(./src/include ./src/lib/third_party/include)
AUX_SOURCE_DIRECTORY(./src/lib AllSources)
AUX_SOURCE_DIRECTORY(./src/lib/third_party/src AllSources)
AUX_SOURCE_DIRECTORY(./src/lib/protocols AllSources)
AUX_SOURCE_DIRECTORY(./src/lib AllSources)
# libndpi.so target
ADD_LIBRARY(ndpi SHARED ${AllSources})