From c0794749176b1be80c0c814fc8cd84db79f2e0aa Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Mon, 6 Dec 2021 16:29:37 +0100 Subject: [PATCH] Rename vpnproxy to pcapdroid --- .../remote_capture/CaptureService.java | 2 +- .../model/ConnectionDescriptor.java | 2 +- app/src/main/jni/CMakeLists.txt | 2 +- app/src/main/jni/common/utils.c | 4 +- .../jni/{vpnproxy-jni => core}/CMakeLists.txt | 10 +- .../jni/{vpnproxy-jni => core}/blacklist.c | 2 +- .../jni/{vpnproxy-jni => core}/blacklist.h | 16 + .../jni/{vpnproxy-jni => core}/capture_root.c | 132 ++-- .../capture_proxy.c => core/capture_vpn.c} | 192 +++--- .../main/jni/{vpnproxy-jni => core}/crc32.c | 0 .../main/jni/{vpnproxy-jni => core}/ip_lru.c | 0 .../main/jni/{vpnproxy-jni => core}/ip_lru.h | 0 .../ndpi_master_protos.c | 0 .../jni/{vpnproxy-jni => core}/pcap_utils.c | 12 +- .../jni/{vpnproxy-jni => core}/pcap_utils.h | 2 +- .../vpnproxy.c => core/pcapdroid.c} | 652 +++++++++--------- .../vpnproxy.h => core/pcapdroid.h} | 77 +-- app/src/main/jni/pcapd/README.md | 2 +- 18 files changed, 558 insertions(+), 549 deletions(-) rename app/src/main/jni/{vpnproxy-jni => core}/CMakeLists.txt (87%) rename app/src/main/jni/{vpnproxy-jni => core}/blacklist.c (99%) rename app/src/main/jni/{vpnproxy-jni => core}/blacklist.h (89%) rename app/src/main/jni/{vpnproxy-jni => core}/capture_root.c (79%) rename app/src/main/jni/{vpnproxy-jni/capture_proxy.c => core/capture_vpn.c} (68%) rename app/src/main/jni/{vpnproxy-jni => core}/crc32.c (100%) rename app/src/main/jni/{vpnproxy-jni => core}/ip_lru.c (100%) rename app/src/main/jni/{vpnproxy-jni => core}/ip_lru.h (100%) rename app/src/main/jni/{vpnproxy-jni => core}/ndpi_master_protos.c (100%) rename app/src/main/jni/{vpnproxy-jni => core}/pcap_utils.c (92%) rename app/src/main/jni/{vpnproxy-jni => core}/pcap_utils.h (96%) rename app/src/main/jni/{vpnproxy-jni/vpnproxy.c => core/pcapdroid.c} (70%) rename app/src/main/jni/{vpnproxy-jni/vpnproxy.h => core/pcapdroid.h} (79%) diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index d30e4f8d..b3d52eb1 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -142,7 +142,7 @@ public class CaptureService extends VpnService implements Runnable { static { /* Load native library */ - System.loadLibrary("vpnproxy-jni"); + System.loadLibrary("capture"); } @Override diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java b/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java index d2f0f9e6..936e30db 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java @@ -30,7 +30,7 @@ import java.io.Serializable; import java.net.InetAddress; import java.net.UnknownHostException; -/* Equivalent of zdtun_conn_t from zdtun and conn_data_t from vpnproxy.c */ +/* Equivalent of zdtun_conn_t from zdtun and pd_conn_t from pcapdroid.c */ public class ConnectionDescriptor implements Serializable { // sync with zdtun_conn_status_t diff --git a/app/src/main/jni/CMakeLists.txt b/app/src/main/jni/CMakeLists.txt index e6211f13..18cdc2fd 100644 --- a/app/src/main/jni/CMakeLists.txt +++ b/app/src/main/jni/CMakeLists.txt @@ -18,4 +18,4 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(common) add_subdirectory(pcapd) -add_subdirectory(vpnproxy-jni) +add_subdirectory(core) diff --git a/app/src/main/jni/common/utils.c b/app/src/main/jni/common/utils.c index c960d0ff..f3574beb 100644 --- a/app/src/main/jni/common/utils.c +++ b/app/src/main/jni/common/utils.c @@ -24,7 +24,7 @@ memtrack_t memtrack = {0}; int loglevel = 0; -const char *logtag = "VPNProxy"; +const char *logtag = "pcapdroid-native"; void (*logcallback)(int lvl, const char *msg) = NULL; /* ******************************************************* */ @@ -211,4 +211,4 @@ char* humanSize(char *buf, int bufsize, double bytes) { snprintf(buf, bufsize, "%.02f %s", bytes, suffix[i]); return buf; -} \ No newline at end of file +} diff --git a/app/src/main/jni/vpnproxy-jni/CMakeLists.txt b/app/src/main/jni/core/CMakeLists.txt similarity index 87% rename from app/src/main/jni/vpnproxy-jni/CMakeLists.txt rename to app/src/main/jni/core/CMakeLists.txt index b62f10e8..8a28f543 100644 --- a/app/src/main/jni/vpnproxy-jni/CMakeLists.txt +++ b/app/src/main/jni/core/CMakeLists.txt @@ -1,8 +1,8 @@ -project(vpnproxy-jni) +project(core) -add_library(vpnproxy-jni SHARED - vpnproxy.c - capture_proxy.c +add_library(capture SHARED + pcapdroid.c + capture_vpn.c capture_root.c ip_lru.c ndpi_master_protos.c @@ -27,7 +27,7 @@ ADD_LIBRARY(ndpi SHARED ${ndpiSources} ${NDPI_ROOT}/src/include/ndpi_api.h) find_library(log-lib log) -target_link_libraries(vpnproxy-jni +target_link_libraries(capture zdtun ndpi common diff --git a/app/src/main/jni/vpnproxy-jni/blacklist.c b/app/src/main/jni/core/blacklist.c similarity index 99% rename from app/src/main/jni/vpnproxy-jni/blacklist.c rename to app/src/main/jni/core/blacklist.c index 0ec8b916..25ba852e 100644 --- a/app/src/main/jni/vpnproxy-jni/blacklist.c +++ b/app/src/main/jni/core/blacklist.c @@ -17,7 +17,7 @@ * Copyright 2020-21 - Emanuele Faranda */ -#include "vpnproxy.h" +#include "pcapdroid.h" #include "common/utils.h" typedef struct { diff --git a/app/src/main/jni/vpnproxy-jni/blacklist.h b/app/src/main/jni/core/blacklist.h similarity index 89% rename from app/src/main/jni/vpnproxy-jni/blacklist.h rename to app/src/main/jni/core/blacklist.h index a98f0c78..ce87fad0 100644 --- a/app/src/main/jni/vpnproxy-jni/blacklist.h +++ b/app/src/main/jni/core/blacklist.h @@ -45,6 +45,22 @@ typedef enum { UID_BLACKLIST } blacklist_type; +typedef struct { + char *fname; + blacklist_type type; +} bl_info_t; + +typedef struct { + char *fname; + int num_rules; +} bl_status_t; + +typedef struct { + bl_status_t *items; + int size; + int cur_items; +} bl_status_arr_t; + blacklist_t* blacklist_init(); void blacklist_destroy(blacklist_t *bl); int blacklist_add_domain(blacklist_t *bl, const char *domain); diff --git a/app/src/main/jni/vpnproxy-jni/capture_root.c b/app/src/main/jni/core/capture_root.c similarity index 79% rename from app/src/main/jni/vpnproxy-jni/capture_root.c rename to app/src/main/jni/core/capture_root.c index b001e20d..b5ff28b0 100644 --- a/app/src/main/jni/vpnproxy-jni/capture_root.c +++ b/app/src/main/jni/core/capture_root.c @@ -21,7 +21,7 @@ #include #include #include -#include "vpnproxy.h" +#include "pcapdroid.h" #include "pcapd/pcapd.h" #include "common/utils.h" #include "third_party/uthash.h" @@ -35,7 +35,7 @@ struct pcap_conn { zdtun_5tuple_t tuple; - conn_data_t *data; + pd_conn_t *data; UT_hash_handle hh; }; @@ -117,8 +117,8 @@ static int su_cmd(const char *prog, const char *args, bool check_error) { /* ******************************************************* */ -static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char *buf, int bufsize) { - JNIEnv *env = proxy->env; +static void get_libprog_path(pcapdroid_t *pd, const char *prog_name, char *buf, int bufsize) { + JNIEnv *env = pd->env; jobject prog_str = (*env)->NewStringUTF(env, prog_name); buf[0] = '\0'; @@ -128,7 +128,7 @@ static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char return; } - jstring obj = (*env)->CallObjectMethod(env, proxy->vpn_service, mids.getLibprogPath, prog_str); + jstring obj = (*env)->CallObjectMethod(env, pd->vpn_service, mids.getLibprogPath, prog_str); if(!jniCheckException(env)) { const char *value = (*env)->GetStringUTFChars(env, obj, 0); @@ -144,7 +144,7 @@ static void get_libprog_path(vpnproxy_data_t *proxy, const char *prog_name, char /* ******************************************************* */ -static void kill_pcapd(vpnproxy_data_t *proxy) { +static void kill_pcapd(pcapdroid_t *nc) { int pid; char pid_s[8]; FILE *f = fopen(PCAPD_PID, "r"); @@ -165,16 +165,16 @@ static void kill_pcapd(vpnproxy_data_t *proxy) { /* ******************************************************* */ -static int connectPcapd(vpnproxy_data_t *proxy) { +static int connectPcapd(pcapdroid_t *pd) { int sock; int client = -1; char bpf[256]; char pcapd[PATH_MAX]; char capture_interface[16]; - getStringPref(proxy, "getPcapDumperBpf", bpf, sizeof(bpf)); - getStringPref(proxy, "getCaptureInterface", capture_interface, sizeof(capture_interface)); - get_libprog_path(proxy, "pcapd", pcapd, sizeof(pcapd)); + getStringPref(pd, "getPcapDumperBpf", bpf, sizeof(bpf)); + getStringPref(pd, "getCaptureInterface", capture_interface, sizeof(capture_interface)); + get_libprog_path(pd, "pcapd", pcapd, sizeof(pcapd)); if(!pcapd[0]) return(-1); @@ -198,7 +198,7 @@ static int connectPcapd(vpnproxy_data_t *proxy) { addr.sun_family = AF_UNIX; strcpy(addr.sun_path, PCAPD_SOCKET_PATH); - kill_pcapd(proxy); + kill_pcapd(pd); unlink(PCAPD_PID); unlink(PCAPD_SOCKET_PATH); @@ -217,7 +217,7 @@ static int connectPcapd(vpnproxy_data_t *proxy) { // Start the daemon char args[256]; - snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -b \"%s\"", capture_interface, proxy->app_filter, bpf); + snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -b \"%s\"", capture_interface, pd->app_filter, bpf); if(su_cmd(pcapd, args, true) != 0) goto cleanup; @@ -250,27 +250,27 @@ cleanup: /* ******************************************************* */ -static void remove_connection(vpnproxy_data_t *proxy, pcap_conn_t *conn) { +static void remove_connection(pcapdroid_t *pd, pcap_conn_t *conn) { switch (conn->tuple.ipproto) { case IPPROTO_TCP: - proxy->stats.num_tcp_conn--; + pd->stats.num_tcp_conn--; break; case IPPROTO_UDP: - proxy->stats.num_udp_conn--; + pd->stats.num_udp_conn--; break; case IPPROTO_ICMP: - proxy->stats.num_icmp_conn--; + pd->stats.num_icmp_conn--; break; } - HASH_DELETE(hh, proxy->connections, conn); + HASH_DELETE(hh, pd->connections, conn); pd_free(conn); } /* ******************************************************* */ // Determines when a connection gets closed -static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn, zdtun_pkt_t *pkt, uint8_t dir) { +static void update_connection_status(pcapdroid_t *nc, pcap_conn_t *conn, zdtun_pkt_t *pkt, uint8_t dir) { if((conn->data->status >= CONN_STATUS_CLOSED) || (pkt->flags & ZDTUN_PKT_IS_FRAGMENT)) return; @@ -322,7 +322,7 @@ static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn, // reused for a new query, it will generated a new connection, to properly // extract and handle the new DNS query. This also happens for AAAA + A queries. conn->data->to_purge = true; - remove_connection(proxy, conn); + remove_connection(nc, conn); } } } @@ -330,24 +330,24 @@ static void update_connection_status(vpnproxy_data_t *proxy, pcap_conn_t *conn, if(old_status != conn->data->status) { conn->data->update_type |= CONN_UPDATE_STATS; - notify_connection(&proxy->conns_updates, &conn->tuple, conn->data); + pd_notify_connection_update(nc, &conn->tuple, conn->data); } } /* ******************************************************* */ -static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char *buffer) { +static void handle_packet(pcapdroid_t *pd, pcapd_hdr_t *hdr, const char *buffer) { zdtun_pkt_t pkt; pcap_conn_t *conn = NULL; uint8_t is_tx = (hdr->flags & PCAPD_FLAG_TX); // NOTE: the direction uses an heuristic so it may be wrong - if(zdtun_parse_pkt(proxy->tun, buffer, hdr->len, &pkt) != 0) { + if(zdtun_parse_pkt(pd->tun, buffer, hdr->len, &pkt) != 0) { log_d("zdtun_parse_pkt failed"); return; } struct timeval tv = hdr->ts; - set_current_packet(proxy, &pkt, is_tx, &tv); + pd_set_current_packet(pd, &pkt, is_tx, &tv); if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) && (pkt.tuple.src_port == 0) && (pkt.tuple.dst_port == 0)) { @@ -356,7 +356,7 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char * // In such a case, we can only ignore the packet as we cannot determine the connection it belongs to. //log_d("unmatched IP fragment (ID = 0x%04x)", pkt.ip4->id); - proxy->num_discarded_fragments++; + pd->num_discarded_fragments++; return; } @@ -365,19 +365,19 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char * tupleSwapPeers(&pkt.tuple); } - HASH_FIND(hh, proxy->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn); + HASH_FIND(hh, pd->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn); if(!conn) { // is_tx may be wrong, search in the other direction is_tx = !is_tx; tupleSwapPeers(&pkt.tuple); - HASH_FIND(hh, proxy->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn); + HASH_FIND(hh, pd->connections, &pkt.tuple, sizeof(zdtun_5tuple_t), conn); if(!conn) { if((pkt.flags & ZDTUN_PKT_IS_FRAGMENT) && !(pkt.flags & ZDTUN_PKT_IS_FIRST_FRAGMENT)) { log_d("ignoring fragment as it cannot start a connection"); - proxy->num_discarded_fragments++; + pd->num_discarded_fragments++; return; } @@ -385,56 +385,52 @@ static void handle_packet(vpnproxy_data_t *proxy, pcapd_hdr_t *hdr, const char * is_tx = !is_tx; tupleSwapPeers(&pkt.tuple); - conn_data_t *data = new_connection(proxy, &pkt.tuple, hdr->uid); - - if (!data) - return; - conn = pd_malloc(sizeof(pcap_conn_t)); - - if (!conn) { + if(!conn) { log_e("malloc(pcap_conn_t) failed with code %d/%s", errno, strerror(errno)); return; } + pd_conn_t *data = pd_new_connection(pd, &pkt.tuple, hdr->uid); + if(!data) { + pd_free(conn); + return; + } + conn->tuple = pkt.tuple; conn->data = data; - - HASH_ADD(hh, proxy->connections, tuple, sizeof(zdtun_5tuple_t), conn); - - data->incr_id = proxy->incr_id++; - notify_connection(&proxy->new_conns, &pkt.tuple, data); + HASH_ADD(hh, pd->connections, tuple, sizeof(zdtun_5tuple_t), conn); switch (conn->tuple.ipproto) { case IPPROTO_TCP: - proxy->stats.num_tcp_conn++; - proxy->stats.num_tcp_opened++; + pd->stats.num_tcp_conn++; + pd->stats.num_tcp_opened++; break; case IPPROTO_UDP: - proxy->stats.num_udp_conn++; - proxy->stats.num_udp_opened++; + pd->stats.num_udp_conn++; + pd->stats.num_udp_opened++; break; case IPPROTO_ICMP: - proxy->stats.num_icmp_conn++; - proxy->stats.num_icmp_opened++; + pd->stats.num_icmp_conn++; + pd->stats.num_icmp_opened++; break; } } } - conn->data->last_update_ms = proxy->now_ms; + conn->data->last_update_ms = pd->now_ms; - account_stats(proxy, &conn->tuple, conn->data); - update_connection_status(proxy, conn, &pkt, !is_tx); + pd_account_stats(pd, &conn->tuple, conn->data); + update_connection_status(pd, conn, &pkt, !is_tx); } /* ******************************************************* */ -static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all) { +static void purge_expired_connections(pcapdroid_t *pd, uint8_t purge_all) { pcap_conn_t *conn, *tmp; - HASH_ITER(hh, proxy->connections, conn, tmp) { + HASH_ITER(hh, pd->connections, conn, tmp) { uint64_t timeout = 0; switch(conn->tuple.ipproto) { @@ -449,7 +445,7 @@ static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all) break; } - if(purge_all || (proxy->now_ms >= (conn->data->last_update_ms + timeout))) { + if(purge_all || (pd->now_ms >= (conn->data->last_update_ms + timeout))) { //log_d("IDLE (type=%d)", conn->tuple.ipproto); // The connection data will be purged @@ -462,34 +458,34 @@ static void purge_expired_connections(vpnproxy_data_t *proxy, uint8_t purge_all) if(conn->data->update_type != 0) { // Will free the data in sendConnectionsDump - notify_connection(&proxy->conns_updates, &conn->tuple, conn->data); + pd_notify_connection_update(pd, &conn->tuple, conn->data); } else - conn_free_data(conn->data); + pd_destroy_connection(conn->data); - remove_connection(proxy, conn); + remove_connection(pd, conn); } } } /* ******************************************************* */ -int run_root(vpnproxy_data_t *proxy) { +int run_root(pcapdroid_t *pd) { int sock = -1; int rv = -1; char buffer[65535]; u_int64_t next_purge_ms; zdtun_callbacks_t callbacks = {.send_client = (void*)1}; - if((proxy->tun = zdtun_init(&callbacks, NULL)) == NULL) + if((pd->tun = zdtun_init(&callbacks, NULL)) == NULL) return(-1); - if((sock = connectPcapd(proxy)) < 0) { + if((sock = connectPcapd(pd)) < 0) { rv = -1; goto cleanup; } - refresh_time(proxy); - next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS; + pd_refresh_time(pd); + next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS; log_d("Starting packet loop"); @@ -506,7 +502,7 @@ int run_root(vpnproxy_data_t *proxy) { goto cleanup; } - refresh_time(proxy); + pd_refresh_time(pd); if(!running) break; @@ -527,24 +523,24 @@ int run_root(vpnproxy_data_t *proxy) { goto cleanup; } - proxy->num_dropped_pkts = hdr.pkt_drops; - handle_packet(proxy, &hdr, buffer); + pd->num_dropped_pkts = hdr.pkt_drops; + handle_packet(pd, &hdr, buffer); housekeeping: - run_housekeeping(proxy); + pd_housekeeping(pd); - if(proxy->now_ms >= next_purge_ms) { - purge_expired_connections(proxy, 0); - next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS; + if(pd->now_ms >= next_purge_ms) { + purge_expired_connections(pd, 0); + next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS; } } rv = 0; cleanup: - purge_expired_connections(proxy, 1 /* purge_all */); + purge_expired_connections(pd, 1 /* purge_all */); - if(proxy->tun) zdtun_finalize(proxy->tun); + if(pd->tun) zdtun_finalize(pd->tun); if(sock > 0) close(sock); return rv; diff --git a/app/src/main/jni/vpnproxy-jni/capture_proxy.c b/app/src/main/jni/core/capture_vpn.c similarity index 68% rename from app/src/main/jni/vpnproxy-jni/capture_proxy.c rename to app/src/main/jni/core/capture_vpn.c index ecad3047..50dff328 100644 --- a/app/src/main/jni/vpnproxy-jni/capture_proxy.c +++ b/app/src/main/jni/core/capture_vpn.c @@ -17,17 +17,54 @@ * Copyright 2021 - Emanuele Faranda */ -#include "vpnproxy.h" +#include "pcapdroid.h" #include "common/utils.h" -static void protectSocketCallback(zdtun_t *tun, socket_t sock) { - vpnproxy_data_t *proxy = ((vpnproxy_data_t*)zdtun_userdata(tun)); - vpn_protect_socket(proxy, sock); +static void vpn_protect_socket(pcapdroid_t *pd, socket_t sock) { + JNIEnv *env = pd->env; + + if(pd->root_capture) + return; + + /* Call VpnService protect */ + jboolean isProtected = (*env)->CallBooleanMethod( + env, pd->vpn_service, mids.protect, sock); + jniCheckException(env); + + if (!isProtected) + log_e("socket protect failed"); } /* ******************************************************* */ -static void add_known_dns_server(vpnproxy_data_t *proxy, const char *ip) { +static int resolve_uid(pcapdroid_t *pd, const zdtun_5tuple_t *conn_info) { + char buf[256]; + jint uid; + + zdtun_5tuple2str(conn_info, buf, sizeof(buf)); + uid = get_uid(pd->resolver, conn_info); + + if(uid >= 0) { + char appbuf[64]; + + get_appname_by_uid(pd, uid, appbuf, sizeof(appbuf)); + log_i( "%s [%d/%s]", buf, uid, appbuf); + } else { + uid = UID_UNKNOWN; + log_w("%s => UID not found!", buf); + } + + return(uid); +} + +static void protectSocketCallback(zdtun_t *tun, socket_t sock) { + pcapdroid_t *pd = ((pcapdroid_t*)zdtun_userdata(tun)); + vpn_protect_socket(pd, sock); +} + +/* ******************************************************* */ + +static void add_known_dns_server(pcapdroid_t *pd, const char *ip) { ndpi_ip_addr_t parsed; if(ndpi_parse_ip_string(ip, &parsed) < 0) { @@ -35,12 +72,12 @@ static void add_known_dns_server(vpnproxy_data_t *proxy, const char *ip) { return; } - ndpi_ptree_insert(proxy->known_dns_servers, &parsed, ndpi_is_ipv6(&parsed) ? 128 : 32, 1); + ndpi_ptree_insert(pd->known_dns_servers, &parsed, ndpi_is_ipv6(&parsed) ? 128 : 32, 1); } /* ******************************************************* */ -static struct timeval* get_pkt_timestamp(vpnproxy_data_t *proxy, struct timeval *tv) { +static struct timeval* get_pkt_timestamp(pcapdroid_t *pd, struct timeval *tv) { struct timespec ts; if(!clock_gettime(CLOCK_REALTIME, &ts)) { @@ -51,7 +88,7 @@ static struct timeval* get_pkt_timestamp(vpnproxy_data_t *proxy, struct timeval // use the last pkt timestamp log_w("clock_gettime failed[%d]: %s", errno, strerror(errno)); - return &proxy->cur_pkt.tv; + return &pd->cur_pkt.tv; } /* ******************************************************* */ @@ -60,17 +97,17 @@ static int net2tun(zdtun_t *tun, zdtun_pkt_t *pkt, const zdtun_conn_t *conn_info if(!running) return 0; - vpnproxy_data_t *proxy = (vpnproxy_data_t*) zdtun_userdata(tun); - conn_data_t *data = zdtun_conn_get_userdata(conn_info); + pcapdroid_t *pd = (pcapdroid_t*) zdtun_userdata(tun); + pd_conn_t *data = zdtun_conn_get_userdata(conn_info); struct timeval tv; - refresh_time(proxy); - set_current_packet(proxy, pkt, false, get_pkt_timestamp(proxy, &tv)); + pd_refresh_time(pd); + pd_set_current_packet(pd, pkt, false, get_pkt_timestamp(pd, &tv)); - if(data->to_block) // NOTE: blocked_pkts accounted in account_stats + if(data->to_block) // NOTE: blocked_pkts accounted in pd_account_stats return 0; - int rv = write(proxy->tunfd, pkt->buf, pkt->len); + int rv = write(pd->tunfd, pkt->buf, pkt->len); if(rv < 0) { if(errno == ENOBUFS) { @@ -96,8 +133,8 @@ static int net2tun(zdtun_t *tun, zdtun_pkt_t *pkt, const zdtun_conn_t *conn_info /* ******************************************************* */ -static void check_socks5_redirection(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, zdtun_conn_t *conn) { - conn_data_t *data = zdtun_conn_get_userdata(conn); +static void check_socks5_redirection(pcapdroid_t *pd, zdtun_pkt_t *pkt, zdtun_conn_t *conn) { + pd_conn_t *data = zdtun_conn_get_userdata(conn); if((pkt->tuple.ipproto == IPPROTO_TCP) && (((data->sent_pkts + data->rcvd_pkts) == 0))) zdtun_conn_proxy(conn); @@ -111,17 +148,17 @@ static void check_socks5_redirection(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, z * Moreover, if a private DNS connection is detected in opportunistic mode (block_private_dns true), * then block this connection to force the fallback to non-private DNS mode. */ -static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { +static bool check_dns_req_allowed(pcapdroid_t *pd, zdtun_conn_t *conn) { const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn); if(new_dns_server != 0) { // Reload DNS server - proxy->dns_server = new_dns_server; + pd->dns_server = new_dns_server; new_dns_server = 0; zdtun_ip_t ip = {0}; - ip.ip4 = proxy->dns_server; - zdtun_set_dnat_info(proxy->tun, &ip, htons(53), 4); + ip.ip4 = pd->dns_server; + zdtun_set_dnat_info(pd->tun, &ip, htons(53), 4); log_d("Using new DNS server"); } @@ -129,9 +166,9 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { if(zdtun_conn_get_5tuple(conn)->ipproto == IPPROTO_ICMP) return true; - bool is_internal_dns = (tuple->ipver == 4) && (tuple->dst_ip.ip4 == proxy->vpn_dns); + bool is_internal_dns = (tuple->ipver == 4) && (tuple->dst_ip.ip4 == pd->vpn_dns); bool is_dns_server = is_internal_dns - || ((tuple->ipver == 6) && (memcmp(&tuple->dst_ip.ip6, &proxy->ipv6.dns_server, 16) == 0)); + || ((tuple->ipver == 6) && (memcmp(&tuple->dst_ip.ip6, &pd->ipv6.dns_server, 16) == 0)); if(!is_dns_server) { // try with known DNS servers @@ -143,7 +180,7 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { else memcpy(&addr.ipv6, &tuple->dst_ip.ip6, 16); - ndpi_ptree_match_addr(proxy->known_dns_servers, &addr, &matched); + ndpi_ptree_match_addr(pd->known_dns_servers, &addr, &matched); if(matched) { char ip[INET6_ADDRSTRLEN]; @@ -161,7 +198,7 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { return(true); if((tuple->ipproto == IPPROTO_UDP) && (ntohs(tuple->dst_port) == 53)) { - zdtun_pkt_t *pkt = proxy->cur_pkt.pkt; + zdtun_pkt_t *pkt = pd->cur_pkt.pkt; int dns_length = pkt->l7_len; if(dns_length >= sizeof(dns_packet_t)) { @@ -171,12 +208,12 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { return(true); log_d("Detected DNS query[%u]", dns_length); - proxy->num_dns_requests++; + pd->num_dns_requests++; if(is_internal_dns) { /* * Direct the packet to the public DNS server. Checksum recalculation is not strictly necessary - * here as zdtun will proxy the connection. + * here as zdtun will pd the connection. */ zdtun_conn_dnat(conn); } @@ -197,20 +234,17 @@ static bool check_dns_req_allowed(vpnproxy_data_t *proxy, zdtun_conn_t *conn) { /* ******************************************************* */ static int handle_new_connection(zdtun_t *tun, zdtun_conn_t *conn_info) { - vpnproxy_data_t *proxy = ((vpnproxy_data_t *) zdtun_userdata(tun)); + pcapdroid_t *pd = ((pcapdroid_t *) zdtun_userdata(tun)); const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn_info); - conn_data_t *data = new_connection(proxy, tuple, resolve_uid(proxy, tuple)); + pd_conn_t *data = pd_new_connection(pd, tuple, resolve_uid(pd, tuple)); if(!data) { /* reject connection */ return (1); } zdtun_conn_set_userdata(conn_info, data); - data->to_block = !check_dns_req_allowed(proxy, conn_info); - - data->incr_id = proxy->incr_id++; - notify_connection(&proxy->new_conns, tuple, data); + data->to_block = !check_dns_req_allowed(pd, conn_info); /* accept connection */ return(0); @@ -219,8 +253,8 @@ static int handle_new_connection(zdtun_t *tun, zdtun_conn_t *conn_info) { /* ******************************************************* */ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) { - vpnproxy_data_t *proxy = (vpnproxy_data_t*) zdtun_userdata(tun); - conn_data_t *data = zdtun_conn_get_userdata(conn_info); + pcapdroid_t *pd = (pcapdroid_t*) zdtun_userdata(tun); + pd_conn_t *data = zdtun_conn_get_userdata(conn_info); if(!data) { log_e("Missing data in connection"); @@ -232,9 +266,9 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) { // Send last notification // Will free the data in sendConnectionsDump data->update_type |= CONN_UPDATE_STATS; - notify_connection(&proxy->conns_updates, tuple, data); + pd_notify_connection_update(pd, tuple, data); - conn_end_ndpi_detection(data, proxy, tuple); + pd_giveup_dpi(pd, data, tuple); data->status = zdtun_conn_get_status(conn_info); data->to_purge = true; } @@ -242,10 +276,10 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) { /* ******************************************************* */ static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, const zdtun_conn_t *conn_info) { - vpnproxy_data_t *proxy = ((vpnproxy_data_t*)zdtun_userdata(tun)); + pcapdroid_t *pd = ((pcapdroid_t*)zdtun_userdata(tun)); const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn_info); - conn_data_t *data = zdtun_conn_get_userdata(conn_info); + pd_conn_t *data = zdtun_conn_get_userdata(conn_info); if(!data) { log_e("Missing data in connection"); return; @@ -255,11 +289,11 @@ static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, co if(data->to_block) { data->blocked_pkts++; - data->last_seen = proxy->cur_pkt.ms; + data->last_seen = pd->cur_pkt.ms; return; } - account_stats(proxy, tuple, data); + pd_account_stats(pd, tuple, data); if(data->status >= CONN_STATUS_CLOSED) data->to_purge = true; @@ -267,13 +301,13 @@ static void on_packet(zdtun_t *tun, const zdtun_pkt_t *pkt, uint8_t from_tun, co /* ******************************************************* */ -int run_proxy(vpnproxy_data_t *proxy) { +int run_vpn(pcapdroid_t *pd) { zdtun_t *tun; char buffer[32768]; u_int64_t next_purge_ms; - int flags = fcntl(proxy->tunfd, F_GETFL, 0); - if (flags < 0 || fcntl(proxy->tunfd, F_SETFL, flags & ~O_NONBLOCK) < 0) { + int flags = fcntl(pd->tunfd, F_GETFL, 0); + if (flags < 0 || fcntl(pd->tunfd, F_SETFL, flags & ~O_NONBLOCK) < 0) { log_f("fcntl ~O_NONBLOCK error [%d]: %s", errno, strerror(errno)); return (-1); @@ -288,39 +322,39 @@ int run_proxy(vpnproxy_data_t *proxy) { }; // List of known DNS servers - add_known_dns_server(proxy, "8.8.8.8"); - add_known_dns_server(proxy, "8.8.4.4"); - add_known_dns_server(proxy, "1.1.1.1"); - add_known_dns_server(proxy, "1.0.0.1"); - add_known_dns_server(proxy, "2001:4860:4860::8888"); - add_known_dns_server(proxy, "2001:4860:4860::8844"); - add_known_dns_server(proxy, "2606:4700:4700::64"); - add_known_dns_server(proxy, "2606:4700:4700::6400"); + add_known_dns_server(pd, "8.8.8.8"); + add_known_dns_server(pd, "8.8.4.4"); + add_known_dns_server(pd, "1.1.1.1"); + add_known_dns_server(pd, "1.0.0.1"); + add_known_dns_server(pd, "2001:4860:4860::8888"); + add_known_dns_server(pd, "2001:4860:4860::8844"); + add_known_dns_server(pd, "2606:4700:4700::64"); + add_known_dns_server(pd, "2606:4700:4700::6400"); - tun = zdtun_init(&callbacks, proxy); + tun = zdtun_init(&callbacks, pd); if(tun == NULL) { log_f("zdtun_init failed"); return(-2); } - proxy->tun = tun; + pd->tun = tun; new_dns_server = 0; - if(proxy->socks5.enabled) { + if(pd->socks5.enabled) { zdtun_ip_t dnatip = {0}; - dnatip.ip4 = proxy->socks5.proxy_ip; - zdtun_set_socks5_proxy(tun, &dnatip, proxy->socks5.proxy_port, 4); + dnatip.ip4 = pd->socks5.proxy_ip; + zdtun_set_socks5_proxy(tun, &dnatip, pd->socks5.proxy_port, 4); } zdtun_ip_t ip = {0}; - ip.ip4 = proxy->dns_server; + ip.ip4 = pd->dns_server; zdtun_set_dnat_info(tun, &ip, ntohs(53), 4); - refresh_time(proxy); - next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS; + pd_refresh_time(pd); + next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS; - log_d("Starting packet loop [tunfd=%d]", proxy->tunfd); + log_d("Starting packet loop [tunfd=%d]", pd->tunfd); while(running) { int max_fd; @@ -331,8 +365,8 @@ int run_proxy(vpnproxy_data_t *proxy) { zdtun_fds(tun, &max_fd, &fdset, &wrfds); - FD_SET(proxy->tunfd, &fdset); - max_fd = max(max_fd, proxy->tunfd); + FD_SET(pd->tunfd, &fdset); + max_fd = max(max_fd, pd->tunfd); if(select(max_fd + 1, &fdset, &wrfds, NULL, &timeout) < 0) { log_e("select failed[%d]: %s", errno, strerror(errno)); @@ -342,12 +376,12 @@ int run_proxy(vpnproxy_data_t *proxy) { if(!running) break; - if(FD_ISSET(proxy->tunfd, &fdset)) { + if(FD_ISSET(pd->tunfd, &fdset)) { /* Packet from VPN */ - size = read(proxy->tunfd, buffer, sizeof(buffer)); + size = read(pd->tunfd, buffer, sizeof(buffer)); if(size > 0) { zdtun_pkt_t pkt; - refresh_time(proxy); + pd_refresh_time(pd); if(zdtun_parse_pkt(tun, buffer, size, &pkt) != 0) { log_d("zdtun_parse_pkt failed"); @@ -356,14 +390,14 @@ int run_proxy(vpnproxy_data_t *proxy) { if(pkt.flags & ZDTUN_PKT_IS_FRAGMENT) { log_d("discarding IP fragment"); - proxy->num_discarded_fragments++; + pd->num_discarded_fragments++; goto housekeeping; } struct timeval tv; - set_current_packet(proxy, &pkt, true, get_pkt_timestamp(proxy, &tv)); + pd_set_current_packet(pd, &pkt, true, get_pkt_timestamp(pd, &tv)); - if((pkt.tuple.ipver == 6) && (!proxy->ipv6.enabled)) { + if((pkt.tuple.ipver == 6) && (!pd->ipv6.enabled)) { char buf[512]; log_d("ignoring IPv6 packet: %s", @@ -380,7 +414,7 @@ int run_proxy(vpnproxy_data_t *proxy) { if(!is_tcp_established) { char buf[512]; - proxy->num_dropped_connections++; + pd->num_dropped_connections++; log_e("zdtun_lookup failed: %s", zdtun_5tuple2str(&pkt.tuple, buf, sizeof(buf))); } else { @@ -392,17 +426,17 @@ int run_proxy(vpnproxy_data_t *proxy) { goto housekeeping; } - conn_data_t *data = zdtun_conn_get_userdata(conn); + pd_conn_t *data = zdtun_conn_get_userdata(conn); if(data->to_block) { data->blocked_pkts++; - data->last_seen = proxy->cur_pkt.ms; + data->last_seen = pd->cur_pkt.ms; if(!data->first_seen) data->first_seen = data->last_seen; goto housekeeping; } - if(proxy->socks5.enabled) - check_socks5_redirection(proxy, &pkt, conn); + if(pd->socks5.enabled) + check_socks5_redirection(pd, &pkt, conn); if(zdtun_forward(tun, &pkt, conn) != 0) { char buf[512]; @@ -410,27 +444,27 @@ int run_proxy(vpnproxy_data_t *proxy) { log_e("zdtun_forward failed: %s", zdtun_5tuple2str(&pkt.tuple, buf, sizeof(buf))); - proxy->num_dropped_connections++; + pd->num_dropped_connections++; zdtun_destroy_conn(tun, conn); goto housekeeping; } } else { - refresh_time(proxy); + pd_refresh_time(pd); if(size < 0) log_e("recv(tunfd) returned error [%d]: %s", errno, strerror(errno)); } } else { - refresh_time(proxy); + pd_refresh_time(pd); zdtun_handle_fd(tun, &fdset, &wrfds); } housekeeping: - run_housekeeping(proxy); + pd_housekeeping(pd); - if(proxy->now_ms >= next_purge_ms) { + if(pd->now_ms >= next_purge_ms) { zdtun_purge_expired(tun); - next_purge_ms = proxy->now_ms + PERIODIC_PURGE_TIMEOUT_MS; + next_purge_ms = pd->now_ms + PERIODIC_PURGE_TIMEOUT_MS; } } diff --git a/app/src/main/jni/vpnproxy-jni/crc32.c b/app/src/main/jni/core/crc32.c similarity index 100% rename from app/src/main/jni/vpnproxy-jni/crc32.c rename to app/src/main/jni/core/crc32.c diff --git a/app/src/main/jni/vpnproxy-jni/ip_lru.c b/app/src/main/jni/core/ip_lru.c similarity index 100% rename from app/src/main/jni/vpnproxy-jni/ip_lru.c rename to app/src/main/jni/core/ip_lru.c diff --git a/app/src/main/jni/vpnproxy-jni/ip_lru.h b/app/src/main/jni/core/ip_lru.h similarity index 100% rename from app/src/main/jni/vpnproxy-jni/ip_lru.h rename to app/src/main/jni/core/ip_lru.h diff --git a/app/src/main/jni/vpnproxy-jni/ndpi_master_protos.c b/app/src/main/jni/core/ndpi_master_protos.c similarity index 100% rename from app/src/main/jni/vpnproxy-jni/ndpi_master_protos.c rename to app/src/main/jni/core/ndpi_master_protos.c diff --git a/app/src/main/jni/vpnproxy-jni/pcap_utils.c b/app/src/main/jni/core/pcap_utils.c similarity index 92% rename from app/src/main/jni/vpnproxy-jni/pcap_utils.c rename to app/src/main/jni/core/pcap_utils.c index ccadebe8..d0494969 100644 --- a/app/src/main/jni/vpnproxy-jni/pcap_utils.c +++ b/app/src/main/jni/core/pcap_utils.c @@ -19,7 +19,7 @@ #include #include "common/utils.h" -#include "vpnproxy.h" +#include "pcapdroid.h" #include "pcap_utils.h" #define SNAPLEN 65535 @@ -66,13 +66,13 @@ int pcap_rec_size(int pkt_len) { /* Dumps a packet into the provided buffer. The buffer must have at least pcap_rec_size() * bytes available */ -void pcap_dump_rec(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn) { - const zdtun_pkt_t *pkt = proxy->cur_pkt.pkt; +void pcap_dump_rec(u_char *buffer, pcapdroid_t *pd, pd_conn_t *conn) { + const zdtun_pkt_t *pkt = pd->cur_pkt.pkt; struct pcaprec_hdr_s *pcap_rec = (pcaprec_hdr_s*) buffer; int offset = 0; - pcap_rec->ts_sec = proxy->cur_pkt.tv.tv_sec; - pcap_rec->ts_usec = proxy->cur_pkt.tv.tv_usec; + pcap_rec->ts_sec = pd->cur_pkt.tv.tv_sec; + pcap_rec->ts_usec = pd->cur_pkt.tv.tv_usec; pcap_rec->incl_len = pcap_rec_size(pkt->len) - (int)sizeof(struct pcaprec_hdr_s); pcap_rec->orig_len = pkt->len; buffer += sizeof(struct pcaprec_hdr_s); @@ -107,7 +107,7 @@ void pcap_dump_rec(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn) { // Populate the custom data pcapdroid_trailer_t *cdata = (pcapdroid_trailer_t*)(buffer + offset); - fill_custom_data(cdata, proxy, conn); + fill_custom_data(cdata, pd, conn); //clock_t start = clock(); cdata->fcs = crc32(buffer, pcap_rec->incl_len - 4, 0); diff --git a/app/src/main/jni/vpnproxy-jni/pcap_utils.h b/app/src/main/jni/core/pcap_utils.h similarity index 96% rename from app/src/main/jni/vpnproxy-jni/pcap_utils.h rename to app/src/main/jni/core/pcap_utils.h index 49e8c3ca..53bcf77b 100644 --- a/app/src/main/jni/vpnproxy-jni/pcap_utils.h +++ b/app/src/main/jni/core/pcap_utils.h @@ -60,6 +60,6 @@ typedef struct pcapdroid_trailer { void pcap_set_pcapdroid_trailer(uint8_t enabled); void pcap_build_hdr(struct pcap_hdr_s *pcap_hdr); int pcap_rec_size(int pkt_len); -void pcap_dump_rec(u_char *buffer, vpnproxy_data_t *proxy, conn_data_t *conn); +void pcap_dump_rec(u_char *buffer, pcapdroid_t *pd, pd_conn_t *conn); #endif // __MY_PCAP_H__ diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.c b/app/src/main/jni/core/pcapdroid.c similarity index 70% rename from app/src/main/jni/vpnproxy-jni/vpnproxy.c rename to app/src/main/jni/core/pcapdroid.c index 1da85560..563d5a93 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.c +++ b/app/src/main/jni/core/pcapdroid.c @@ -19,7 +19,7 @@ #include #include // NOTE: look for "assertion" in logcat -#include "vpnproxy.h" +#include "pcapdroid.h" #include "pcap_utils.h" #include "common/utils.h" #include "ndpi_protocol_ids.h" @@ -27,6 +27,9 @@ // Minimum length (e.g. of "GET") to avoid reporting non-requests #define MIN_REQ_PLAINTEXT_CHARS 3 +extern int run_vpn(pcapdroid_t *pd); +extern int run_root(pcapdroid_t *pd); + /* ******************************************************* */ jni_classes_t cls; @@ -47,11 +50,11 @@ static int bl_num_checked_connections = 0; static int netd_resolve_waiting; static u_int64_t last_connections_dump; static u_int64_t next_connections_dump; -static vpnproxy_data_t *global_proxy = NULL; +static pcapdroid_t *global_pd = NULL; /* ******************************************************* */ -static void conn_free_ndpi(conn_data_t *data) { +static void conn_free_ndpi(pd_conn_t *data) { if(data->ndpi_flow) { ndpi_free_flow(data->ndpi_flow); data->ndpi_flow = NULL; @@ -68,7 +71,7 @@ static void conn_free_ndpi(conn_data_t *data) { /* ******************************************************* */ -void conn_free_data(conn_data_t *data) { +void pd_destroy_connection(pd_conn_t *data) { if(!data) return; @@ -86,11 +89,11 @@ void conn_free_data(conn_data_t *data) { /* ******************************************************* */ -void notify_connection(conn_array_t *arr, const zdtun_5tuple_t *tuple, conn_data_t *data) { +static void notif_connection(pcapdroid_t *pd, conn_array_t *arr, const zdtun_5tuple_t *tuple, pd_conn_t *data) { // End the detection when the connection is closed // Always check this, even pending_notification are present if(data->status >= CONN_STATUS_CLOSED) - conn_end_ndpi_detection(data, global_proxy, tuple); + pd_giveup_dpi(pd, data, tuple); if(data->pending_notification) return; @@ -98,7 +101,7 @@ void notify_connection(conn_array_t *arr, const zdtun_5tuple_t *tuple, conn_data if(arr->cur_items >= arr->size) { /* Extend array */ arr->size = (arr->size == 0) ? 8 : (arr->size * 2); - arr->items = pd_realloc(arr->items, arr->size * sizeof(vpn_conn_t)); + arr->items = pd_realloc(arr->items, arr->size * sizeof(conn_and_tuple_t)); if(arr->items == NULL) { log_e("realloc(conn_array_t) (%d items) failed", arr->size); @@ -106,21 +109,27 @@ void notify_connection(conn_array_t *arr, const zdtun_5tuple_t *tuple, conn_data } } - vpn_conn_t *slot = &arr->items[arr->cur_items++]; + conn_and_tuple_t *slot = &arr->items[arr->cur_items++]; slot->tuple = *tuple; slot->data = data; data->pending_notification = true; } +/* Call this when the connection data has changed. The connection data will sent to JAVA during the + * next sendConnectionsDump. The type of change is determined by the data->update_type. */ +void pd_notify_connection_update(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data) { + notif_connection(pd, &pd->conns_updates, tuple, data); +} + /* ******************************************************* */ static void conns_clear(conn_array_t *arr, bool free_all) { if(arr->items) { for(int i=0; i < arr->cur_items; i++) { - vpn_conn_t *slot = &arr->items[i]; + conn_and_tuple_t *slot = &arr->items[i]; if(slot->data && (slot->data->to_purge || free_all)) - conn_free_data(slot->data); + pd_destroy_connection(slot->data); } pd_free(arr->items); @@ -133,11 +142,11 @@ static void conns_clear(conn_array_t *arr, bool free_all) { /* ******************************************************* */ -char* getStringPref(vpnproxy_data_t *proxy, const char *key, char *buf, int bufsize) { - JNIEnv *env = proxy->env; +char* getStringPref(pcapdroid_t *pd, const char *key, char *buf, int bufsize) { + JNIEnv *env = pd->env; jmethodID midMethod = jniGetMethodID(env, cls.vpn_service, key, "()Ljava/lang/String;"); - jstring obj = (*env)->CallObjectMethod(env, proxy->vpn_service, midMethod); + jstring obj = (*env)->CallObjectMethod(env, pd->vpn_service, midMethod); char *rv = NULL; if(!jniCheckException(env)) { @@ -218,11 +227,11 @@ int getIntPref(JNIEnv *env, jobject vpn_inst, const char *key) { /* ******************************************************* */ -static void getApplicationByUidJava(vpnproxy_data_t *proxy, jint uid, char *buf, int bufsize) { - JNIEnv *env = proxy->env; +static void getApplicationByUidJava(pcapdroid_t *pd, jint uid, char *buf, int bufsize) { + JNIEnv *env = pd->env; const char *value = NULL; - jstring obj = (*env)->CallObjectMethod(env, proxy->vpn_service, mids.getApplicationByUid, uid); + jstring obj = (*env)->CallObjectMethod(env, pd->vpn_service, mids.getApplicationByUid, uid); jniCheckException(env); if(obj) @@ -242,21 +251,21 @@ static void getApplicationByUidJava(vpnproxy_data_t *proxy, jint uid, char *buf, /* ******************************************************* */ -static char* get_appname_by_uid(vpnproxy_data_t *proxy, int uid, char *buf, int bufsize) { +char* get_appname_by_uid(pcapdroid_t *pd, int uid, char *buf, int bufsize) { uid_to_app_t *app_entry; - HASH_FIND_INT(proxy->uid2app, &uid, app_entry); + HASH_FIND_INT(pd->uid2app, &uid, app_entry); if(app_entry == NULL) { app_entry = (uid_to_app_t*) pd_malloc(sizeof(uid_to_app_t)); if(app_entry) { // Resolve the app name - getApplicationByUidJava(proxy, uid, app_entry->appname, sizeof(app_entry->appname)); + getApplicationByUidJava(pd, uid, app_entry->appname, sizeof(app_entry->appname)); log_d("uid %d resolved to \"%s\"", uid, app_entry->appname); app_entry->uid = uid; - HASH_ADD_INT(proxy->uid2app, uid, app_entry); + HASH_ADD_INT(pd->uid2app, uid, app_entry); } } @@ -302,16 +311,16 @@ const char *getProtoName(struct ndpi_detection_module_struct *mod, ndpi_protocol /* ******************************************************* */ -static void check_blacklisted_domain(vpnproxy_data_t *proxy, conn_data_t *data, const zdtun_5tuple_t *tuple) { +static void check_blacklisted_domain(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple) { if(data->info && data->info[0]) { - if(proxy->malware_detection.bl && !data->blacklisted_domain) { - data->blacklisted_domain = blacklist_match_domain(proxy->malware_detection.bl, + if(pd->malware_detection.bl && !data->blacklisted_domain) { + data->blacklisted_domain = blacklist_match_domain(pd->malware_detection.bl, data->info); if (data->blacklisted_domain) { char appbuf[64]; char buf[512]; - get_appname_by_uid(proxy, data->uid, appbuf, sizeof(appbuf)); + get_appname_by_uid(pd, data->uid, appbuf, sizeof(appbuf)); log_w("Blacklisted domain [%s]: %s [%s]", data->info, zdtun_5tuple2str(tuple, buf, sizeof(buf)), appbuf); @@ -319,14 +328,14 @@ static void check_blacklisted_domain(vpnproxy_data_t *proxy, conn_data_t *data, data->to_block = true; } } - if(proxy->firewall.bl && !data->to_block) { + if(pd->firewall.bl && !data->to_block) { // Check if the domain is explicitly blocked - data->to_block = blacklist_match_domain(proxy->firewall.bl, data->info); + data->to_block = blacklist_match_domain(pd->firewall.bl, data->info); if(data->to_block) { char appbuf[64]; char buf[512]; - get_appname_by_uid(proxy, data->uid, appbuf, sizeof(appbuf)); + get_appname_by_uid(pd, data->uid, appbuf, sizeof(appbuf)); log_w("Blocked domain [%s]: %s [%s]", data->info, zdtun_5tuple2str(tuple, buf, sizeof(buf)), appbuf); } @@ -337,11 +346,11 @@ static void check_blacklisted_domain(vpnproxy_data_t *proxy, conn_data_t *data, /* ******************************************************* */ -conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, int uid) { - conn_data_t *data = pd_calloc(1, sizeof(conn_data_t)); +pd_conn_t* pd_new_connection(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, int uid) { + pd_conn_t *data = pd_calloc(1, sizeof(pd_conn_t)); if(!data) { - log_e("calloc(conn_data_t) failed with code %d/%s", + log_e("calloc(pd_conn_t) failed with code %d/%s", errno, strerror(errno)); return(NULL); } @@ -363,10 +372,11 @@ conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, } data->uid = uid; + data->incr_id = pd->incr_id++; // Try to resolve host name via the LRU cache const zdtun_ip_t dst_ip = tuple->dst_ip; - data->info = ip_lru_find(proxy->ip_to_host, &dst_ip); + data->info = ip_lru_find(pd->ip_to_host, &dst_ip); if(data->info) { char resip[INET6_ADDRSTRLEN]; @@ -380,9 +390,9 @@ conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, if(data->uid != UID_UNKNOWN) { // When a DNS request is followed by a TLS connection or similar, mark the DNS request // with the uid of this connection. This allows us to match netd requests to actual apps. - // Only change the uid of new connections (proxy->new_conns) to avoid possible side effects - for(int i=0; inew_conns.cur_items; i++) { - vpn_conn_t *conn = &proxy->new_conns.items[i]; + // Only change the uid of new connections (pd->new_conns) to avoid possible side effects + for(int i=0; i < pd->new_conns.cur_items; i++) { + conn_and_tuple_t *conn = &pd->new_conns.items[i]; if((conn->data->uid == UID_NETD) && (conn->data->info != NULL) @@ -405,16 +415,16 @@ conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, } } - check_blacklisted_domain(proxy, data, tuple); + check_blacklisted_domain(pd, data, tuple); } - if(proxy->malware_detection.bl) { - data->blacklisted_ip = blacklist_match_ip(proxy->malware_detection.bl, &dst_ip, tuple->ipver); + if(pd->malware_detection.bl) { + data->blacklisted_ip = blacklist_match_ip(pd->malware_detection.bl, &dst_ip, tuple->ipver); if(data->blacklisted_ip) { char appbuf[64]; char buf[256]; - get_appname_by_uid(proxy, data->uid, appbuf, sizeof(appbuf)); + get_appname_by_uid(pd, data->uid, appbuf, sizeof(appbuf)); log_w("Blacklisted dst ip: %s [%s]", zdtun_5tuple2str(tuple, buf, sizeof(buf)), appbuf); data->to_block = true; @@ -422,26 +432,28 @@ conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, bl_num_checked_connections++; } - if(proxy->firewall.bl && !data->to_block) { - data->to_block = blacklist_match_ip(proxy->firewall.bl, &dst_ip, tuple->ipver); + if(pd->firewall.bl && !data->to_block) { + data->to_block = blacklist_match_ip(pd->firewall.bl, &dst_ip, tuple->ipver); if(data->to_block) { char appbuf[64]; char buf[256]; - get_appname_by_uid(proxy, data->uid, appbuf, sizeof(appbuf)); + get_appname_by_uid(pd, data->uid, appbuf, sizeof(appbuf)); log_w("Blocked ip: %s [%s]", zdtun_5tuple2str(tuple, buf, sizeof(buf)), appbuf); } else { - data->to_block = blacklist_match_uid(proxy->firewall.bl, data->uid); + data->to_block = blacklist_match_uid(pd->firewall.bl, data->uid); if(data->to_block) { char appbuf[64]; char buf[256]; - get_appname_by_uid(proxy, data->uid, appbuf, sizeof(appbuf)); + get_appname_by_uid(pd, data->uid, appbuf, sizeof(appbuf)); log_w("Blocked app: %s [%s]", zdtun_5tuple2str(tuple, buf, sizeof(buf)), appbuf); } } } + notif_connection(pd, &pd->new_conns, tuple, data); + return(data); } @@ -465,14 +477,15 @@ static bool is_numeric_host(const char *host) { /* ******************************************************* */ -void conn_end_ndpi_detection(conn_data_t *data, vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple) { +/* Stop the DPI detection and determine the l7proto of the connection. */ +void pd_giveup_dpi(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple) { if(!data->ndpi_flow) return; if(data->l7proto.app_protocol == NDPI_PROTOCOL_UNKNOWN) { uint8_t proto_guessed; - data->l7proto = ndpi_detection_giveup(proxy->ndpi, data->ndpi_flow, 1 /* Guess */, + data->l7proto = ndpi_detection_giveup(pd->ndpi, data->ndpi_flow, 1 /* Guess */, &proto_guessed); } @@ -513,7 +526,7 @@ void conn_end_ndpi_detection(conn_data_t *data, vpnproxy_data_t *proxy, const zd } // TODO early match - check_blacklisted_domain(proxy, data, tuple); + check_blacklisted_domain(pd, data, tuple); data->update_type |= CONN_UPDATE_INFO; conn_free_ndpi(data); @@ -527,11 +540,11 @@ static int is_plaintext(char c) { /* ******************************************************* */ -static void process_request_data(vpnproxy_data_t *proxy, conn_data_t *data) { - const zdtun_pkt_t *pkt = proxy->cur_pkt.pkt; +static void process_request_data(pcapdroid_t *pd, pd_conn_t *data) { + const zdtun_pkt_t *pkt = pd->cur_pkt.pkt; if(pkt->l7_len > 0) { - if(proxy->cur_pkt.is_tx && is_plaintext(pkt->l7[0])) { + if(pd->cur_pkt.is_tx && is_plaintext(pkt->l7[0])) { int request_len = data->request_data ? (int)strlen(data->request_data) : 0; int num_chars = min(MAX_PLAINTEXT_LENGTH - request_len, pkt->l7_len); @@ -570,7 +583,7 @@ static void process_request_data(vpnproxy_data_t *proxy, conn_data_t *data) { /* ******************************************************* */ -static void process_dns_reply(conn_data_t *data, vpnproxy_data_t *proxy, const struct zdtun_pkt *pkt) { +static void process_dns_reply(pd_conn_t *data, pcapdroid_t *pd, const struct zdtun_pkt *pkt) { const char *query = (const char*) data->ndpi_flow->host_server_name; if((!query[0]) || !strchr(query, '.') || (pkt->l7_len < sizeof(dns_packet_t))) @@ -634,7 +647,7 @@ static void process_dns_reply(conn_data_t *data, vpnproxy_data_t *proxy, const s inet_ntop(family, &rsp_addr, rspip, sizeof(rspip)); log_d("Host LRU cache ADD [v%d]: %s -> %s", ipver, rspip, query); - ip_lru_add(proxy->ip_to_host, &rsp_addr, query); + ip_lru_add(pd->ip_to_host, &rsp_addr, query); } reply += addr_len; len -= addr_len; @@ -644,14 +657,14 @@ static void process_dns_reply(conn_data_t *data, vpnproxy_data_t *proxy, const s /* ******************************************************* */ -static void process_ndpi_packet(vpnproxy_data_t *proxy, conn_data_t *data) { +static void process_ndpi_packet(pcapdroid_t *pd, pd_conn_t *data) { bool giveup = ((data->sent_pkts + data->rcvd_pkts) >= MAX_DPI_PACKETS); - zdtun_pkt_t *pkt = proxy->cur_pkt.pkt; - bool is_tx = proxy->cur_pkt.is_tx; + zdtun_pkt_t *pkt = pd->cur_pkt.pkt; + bool is_tx = pd->cur_pkt.is_tx; u_int16_t old_proto = data->l7proto.master_protocol; - data->l7proto = ndpi_detection_process_packet(proxy->ndpi, data->ndpi_flow, (const u_char *)pkt->buf, - pkt->len, data->last_seen, + data->l7proto = ndpi_detection_process_packet(pd->ndpi, data->ndpi_flow, (const u_char *)pkt->buf, + pkt->len, data->last_seen, is_tx ? data->src_id : data->dst_id, is_tx ? data->dst_id : data->src_id); @@ -659,66 +672,44 @@ static void process_ndpi_packet(vpnproxy_data_t *proxy, conn_data_t *data) { data->update_type |= CONN_UPDATE_INFO; if((!data->request_done) && !data->ndpi_flow->packet.tcp_retransmission) - process_request_data(proxy, data); + process_request_data(pd, data); bool is_dns = ((data->l7proto.master_protocol == NDPI_PROTOCOL_DNS) || (data->l7proto.app_protocol == NDPI_PROTOCOL_DNS)); if(!is_tx && is_dns) - process_dns_reply(data, proxy, pkt); + process_dns_reply(data, pd, pkt); if(giveup || ((data->l7proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) && - !ndpi_extra_dissection_possible(proxy->ndpi, data->ndpi_flow))) - conn_end_ndpi_detection(data, proxy, &pkt->tuple); + !ndpi_extra_dissection_possible(pd->ndpi, data->ndpi_flow))) + pd_giveup_dpi(pd, data, &pkt->tuple); } /* ******************************************************* */ -static void javaPcapDump(vpnproxy_data_t *proxy) { - JNIEnv *env = proxy->env; +static void javaPcapDump(pcapdroid_t *pd) { + JNIEnv *env = pd->env; - log_d("Exporting a %d B PCAP buffer", proxy->pcap_dump.buffer_idx); + log_d("Exporting a %d B PCAP buffer", pd->pcap_dump.buffer_idx); - jbyteArray barray = (*env)->NewByteArray(env, proxy->pcap_dump.buffer_idx); + jbyteArray barray = (*env)->NewByteArray(env, pd->pcap_dump.buffer_idx); if(jniCheckException(env)) return; - (*env)->SetByteArrayRegion(env, barray, 0, proxy->pcap_dump.buffer_idx, proxy->pcap_dump.buffer); - (*env)->CallVoidMethod(env, proxy->vpn_service, mids.dumpPcapData, barray); + (*env)->SetByteArrayRegion(env, barray, 0, pd->pcap_dump.buffer_idx, pd->pcap_dump.buffer); + (*env)->CallVoidMethod(env, pd->vpn_service, mids.dumpPcapData, barray); jniCheckException(env); - proxy->pcap_dump.buffer_idx = 0; - proxy->pcap_dump.last_dump_ms = proxy->now_ms; + pd->pcap_dump.buffer_idx = 0; + pd->pcap_dump.last_dump_ms = pd->now_ms; (*env)->DeleteLocalRef(env, barray); } /* ******************************************************* */ -int resolve_uid(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_info) { - char buf[256]; - jint uid; - - zdtun_5tuple2str(conn_info, buf, sizeof(buf)); - uid = get_uid(proxy->resolver, conn_info); - - if(uid >= 0) { - char appbuf[64]; - - get_appname_by_uid(proxy, uid, appbuf, sizeof(appbuf)); - log_i( "%s [%d/%s]", buf, uid, appbuf); - } else { - uid = UID_UNKNOWN; - log_w("%s => UID not found!", buf); - } - - return(uid); -} - -/* ******************************************************* */ - -static jobject getConnUpdate(vpnproxy_data_t *proxy, const vpn_conn_t *conn) { - JNIEnv *env = proxy->env; - conn_data_t *data = conn->data; +static jobject getConnUpdate(pcapdroid_t *pd, const conn_and_tuple_t *conn) { + JNIEnv *env = pd->env; + pd_conn_t *data = conn->data; jobject update = (*env)->NewObject(env, cls.conn_update, mids.connUpdateInit, data->incr_id); @@ -739,7 +730,7 @@ static jobject getConnUpdate(vpnproxy_data_t *proxy, const vpn_conn_t *conn) { jobject url = (*env)->NewStringUTF(env, data->url ? data->url : ""); jobject req = (*env)->NewStringUTF(env, (data->request_data && (strnlen(data->request_data, MIN_REQ_PLAINTEXT_CHARS) == MIN_REQ_PLAINTEXT_CHARS)) ? data->request_data : ""); - jobject l7proto = (*env)->NewStringUTF(env, getProtoName(proxy->ndpi, data->l7proto, conn->tuple.ipproto)); + jobject l7proto = (*env)->NewStringUTF(env, getProtoName(pd->ndpi, data->l7proto, conn->tuple.ipproto)); (*env)->CallVoidMethod(env, update, mids.connUpdateSetInfo, info, url, req, l7proto); @@ -763,11 +754,11 @@ static jobject getConnUpdate(vpnproxy_data_t *proxy, const vpn_conn_t *conn) { /* ******************************************************* */ -static int dumpNewConnection(vpnproxy_data_t *proxy, const vpn_conn_t *conn, jobject arr, int idx) { +static int dumpNewConnection(pcapdroid_t *pd, const conn_and_tuple_t *conn, jobject arr, int idx) { char srcip[INET6_ADDRSTRLEN], dstip[INET6_ADDRSTRLEN]; - JNIEnv *env = proxy->env; + JNIEnv *env = pd->env; const zdtun_5tuple_t *conn_info = &conn->tuple; - const conn_data_t *data = conn->data; + const pd_conn_t *data = conn->data; int rv = 0; int family = (conn->tuple.ipver == 4) ? AF_INET : AF_INET6; @@ -796,7 +787,7 @@ static int dumpNewConnection(vpnproxy_data_t *proxy, const vpn_conn_t *conn, job if((conn_descriptor != NULL) && !jniCheckException(env)) { // This is the first update, send all the data conn->data->update_type = CONN_UPDATE_STATS | CONN_UPDATE_INFO; - jobject update = getConnUpdate(proxy, conn); + jobject update = getConnUpdate(pd, conn); if(update != NULL) { (*env)->CallVoidMethod(env, conn_descriptor, mids.connProcessUpdate, update); @@ -824,9 +815,9 @@ static int dumpNewConnection(vpnproxy_data_t *proxy, const vpn_conn_t *conn, job /* ******************************************************* */ -static int dumpConnectionUpdate(vpnproxy_data_t *proxy, const vpn_conn_t *conn, jobject arr, int idx) { - JNIEnv *env = proxy->env; - jobject update = getConnUpdate(proxy, conn); +static int dumpConnectionUpdate(pcapdroid_t *pd, const conn_and_tuple_t *conn, jobject arr, int idx) { + JNIEnv *env = pd->env; + jobject update = getConnUpdate(pd, conn); if(update != NULL) { (*env)->SetObjectArrayElement(env, arr, idx, update); @@ -840,17 +831,17 @@ static int dumpConnectionUpdate(vpnproxy_data_t *proxy, const vpn_conn_t *conn, /* ******************************************************* */ /* Perform a full dump of the active connections */ -static void sendConnectionsDump(vpnproxy_data_t *proxy) { - if((proxy->new_conns.cur_items == 0) && (proxy->conns_updates.cur_items == 0)) +static void sendConnectionsDump(pcapdroid_t *pd) { + if((pd->new_conns.cur_items == 0) && (pd->conns_updates.cur_items == 0)) return; log_d("sendConnectionsDump [after %" PRIu64 " ms]: new=%d, updates=%d", - proxy->now_ms - last_connections_dump, - proxy->new_conns.cur_items, proxy->conns_updates.cur_items); + pd->now_ms - last_connections_dump, + pd->new_conns.cur_items, pd->conns_updates.cur_items); - JNIEnv *env = proxy->env; - jobject new_conns = (*env)->NewObjectArray(env, proxy->new_conns.cur_items, cls.conn, NULL); - jobject conns_updates = (*env)->NewObjectArray(env, proxy->conns_updates.cur_items, cls.conn_update, NULL); + JNIEnv *env = pd->env; + jobject new_conns = (*env)->NewObjectArray(env, pd->new_conns.cur_items, cls.conn, NULL); + jobject conns_updates = (*env)->NewObjectArray(env, pd->conns_updates.cur_items, cls.conn_update, NULL); if((new_conns == NULL) || (conns_updates == NULL) || jniCheckException(env)) { log_e("NewObjectArray() failed"); @@ -858,35 +849,35 @@ static void sendConnectionsDump(vpnproxy_data_t *proxy) { } // New connections - for(int i=0; inew_conns.cur_items; i++) { - vpn_conn_t *conn = &proxy->new_conns.items[i]; + for(int i=0; i < pd->new_conns.cur_items; i++) { + conn_and_tuple_t *conn = &pd->new_conns.items[i]; conn->data->pending_notification = false; - if(dumpNewConnection(proxy, conn, new_conns, i) < 0) + if(dumpNewConnection(pd, conn, new_conns, i) < 0) goto cleanup; } //clock_t start = clock(); // Updated connections - for(int i=0; iconns_updates.cur_items; i++) { - vpn_conn_t *conn = &proxy->conns_updates.items[i]; + for(int i=0; i < pd->conns_updates.cur_items; i++) { + conn_and_tuple_t *conn = &pd->conns_updates.items[i]; conn->data->pending_notification = false; - if(dumpConnectionUpdate(proxy, conn, conns_updates, i) < 0) + if(dumpConnectionUpdate(pd, conn, conns_updates, i) < 0) goto cleanup; } //double cpu_time_used = ((double) (clock() - start)) / CLOCKS_PER_SEC; - //log_d("avg cpu_time_used per update: %f sec", cpu_time_used / proxy->conns_updates.cur_items); + //log_d("avg cpu_time_used per update: %f sec", cpu_time_used / pd->conns_updates.cur_items); /* Send the dump */ - (*env)->CallVoidMethod(env, proxy->vpn_service, mids.updateConnections, new_conns, conns_updates); + (*env)->CallVoidMethod(env, pd->vpn_service, mids.updateConnections, new_conns, conns_updates); jniCheckException(env); cleanup: - conns_clear(&proxy->new_conns, false); - conns_clear(&proxy->conns_updates, false); + conns_clear(&pd->new_conns, false); + conns_clear(&pd->conns_updates, false); (*env)->DeleteLocalRef(env, new_conns); (*env)->DeleteLocalRef(env, conns_updates); @@ -918,13 +909,13 @@ static char* get_allocs_summary() { /* ******************************************************* */ -static void sendStatsDump(const vpnproxy_data_t *proxy) { - JNIEnv *env = proxy->env; - const capture_stats_t *capstats = &proxy->capture_stats; - const zdtun_statistics_t *stats = &proxy->stats; +static void sendStatsDump(const pcapdroid_t *pd) { + JNIEnv *env = pd->env; + const capture_stats_t *capstats = &pd->capture_stats; + const zdtun_statistics_t *stats = &pd->stats; jstring allocs_summary = #ifdef PCAPDROID_TRACK_ALLOCS - (*proxy->env)->NewStringUTF(proxy->env, get_allocs_summary()); + (*pd->env)->NewStringUTF(pd->env, get_allocs_summary()); #else NULL; #endif @@ -940,15 +931,15 @@ static void sendStatsDump(const vpnproxy_data_t *proxy) { } (*env)->CallVoidMethod(env, stats_obj, mids.statsSetData, - allocs_summary, - capstats->sent_bytes, capstats->rcvd_bytes, - capstats->sent_pkts, capstats->rcvd_pkts, - min(proxy->num_dropped_pkts, INT_MAX), proxy->num_dropped_connections, - stats->num_open_sockets, stats->all_max_fd, active_conns, tot_conns, - proxy->num_dns_requests); + allocs_summary, + capstats->sent_bytes, capstats->rcvd_bytes, + capstats->sent_pkts, capstats->rcvd_pkts, + min(pd->num_dropped_pkts, INT_MAX), pd->num_dropped_connections, + stats->num_open_sockets, stats->all_max_fd, active_conns, tot_conns, + pd->num_dns_requests); if(!jniCheckException(env)) { - (*env)->CallVoidMethod(env, proxy->vpn_service, mids.sendStatsDump, stats_obj); + (*env)->CallVoidMethod(env, pd->vpn_service, mids.sendStatsDump, stats_obj); jniCheckException(env); } @@ -958,13 +949,13 @@ static void sendStatsDump(const vpnproxy_data_t *proxy) { /* ******************************************************* */ -static void notifyServiceStatus(vpnproxy_data_t *proxy, const char *status) { - JNIEnv *env = proxy->env; +static void notifyServiceStatus(pcapdroid_t *pd, const char *status) { + JNIEnv *env = pd->env; jstring status_str; status_str = (*env)->NewStringUTF(env, status); - (*env)->CallVoidMethod(env, proxy->vpn_service, mids.sendServiceStatus, status_str); + (*env)->CallVoidMethod(env, pd->vpn_service, mids.sendServiceStatus, status_str); jniCheckException(env); (*env)->DeleteLocalRef(env, status_str); @@ -972,55 +963,38 @@ static void notifyServiceStatus(vpnproxy_data_t *proxy, const char *status) { /* ******************************************************* */ -void vpn_protect_socket(vpnproxy_data_t *proxy, socket_t sock) { - JNIEnv *env = proxy->env; - - if(proxy->root_capture) - return; - - /* Call VpnService protect */ - jboolean isProtected = (*env)->CallBooleanMethod( - env, proxy->vpn_service, mids.protect, sock); - jniCheckException(env); - - if (!isProtected) - log_e("socket protect failed"); -} - -/* ******************************************************* */ - const char* get_cache_path(const char *subpath) { - strncpy(global_proxy->cachedir + global_proxy->cachedir_len, subpath, - sizeof(global_proxy->cachedir) - global_proxy->cachedir_len - 1); - global_proxy->cachedir[sizeof(global_proxy->cachedir) - 1] = 0; - return global_proxy->cachedir; + strncpy(global_pd->cachedir + global_pd->cachedir_len, subpath, + sizeof(global_pd->cachedir) - global_pd->cachedir_len - 1); + global_pd->cachedir[sizeof(global_pd->cachedir) - 1] = 0; + return global_pd->cachedir; } /* ******************************************************* */ const char* get_file_path(const char *subpath) { - strncpy(global_proxy->filesdir + global_proxy->filesdir_len, subpath, - sizeof(global_proxy->filesdir) - global_proxy->filesdir_len - 1); - global_proxy->filesdir[sizeof(global_proxy->filesdir) - 1] = 0; - return global_proxy->filesdir; + strncpy(global_pd->filesdir + global_pd->filesdir_len, subpath, + sizeof(global_pd->filesdir) - global_pd->filesdir_len - 1); + global_pd->filesdir[sizeof(global_pd->filesdir) - 1] = 0; + return global_pd->filesdir; } /* ******************************************************* */ // called after load_new_blacklists -static void use_new_blacklists(vpnproxy_data_t *proxy) { - JNIEnv *env = proxy->env; +static void use_new_blacklists(pcapdroid_t *pd) { + JNIEnv *env = pd->env; - if(!proxy->malware_detection.new_bl) + if(!pd->malware_detection.new_bl) return; - if(proxy->malware_detection.bl) - blacklist_destroy(proxy->malware_detection.bl); - proxy->malware_detection.bl = proxy->malware_detection.new_bl; - proxy->malware_detection.new_bl = NULL; + if(pd->malware_detection.bl) + blacklist_destroy(pd->malware_detection.bl); + pd->malware_detection.bl = pd->malware_detection.new_bl; + pd->malware_detection.new_bl = NULL; - bl_status_arr_t *status_arr = proxy->malware_detection.status_arr; - proxy->malware_detection.status_arr = NULL; + bl_status_arr_t *status_arr = pd->malware_detection.status_arr; + pd->malware_detection.status_arr = NULL; jobject status_obj = (*env)->NewObjectArray(env, status_arr ? status_arr->cur_items : 0, cls.blacklist_status, NULL); if((status_obj == NULL) || jniCheckException(env)) { @@ -1050,7 +1024,7 @@ static void use_new_blacklists(vpnproxy_data_t *proxy) { } } } - (*proxy->env)->CallVoidMethod(proxy->env, proxy->vpn_service, mids.notifyBlacklistsLoaded, status_obj); + (*pd->env)->CallVoidMethod(pd->env, pd->vpn_service, mids.notifyBlacklistsLoaded, status_obj); cleanup: if(status_arr != NULL) { @@ -1065,51 +1039,51 @@ cleanup: /* ******************************************************* */ -// Load information about the blacklists to use (proxy->malware_detection.bls_info) -int load_blacklists_info(vpnproxy_data_t *proxy) { +// Load information about the blacklists to use (pd->malware_detection.bls_info) +int load_blacklists_info(pcapdroid_t *pd) { int rv = 0; - JNIEnv *env = proxy->env; - jobjectArray *arr = (*env)->CallObjectMethod(env, proxy->vpn_service, mids.getBlacklistsInfo); - proxy->malware_detection.bls_info = NULL; - proxy->malware_detection.num_bls = 0; + JNIEnv *env = pd->env; + jobjectArray *arr = (*env)->CallObjectMethod(env, pd->vpn_service, mids.getBlacklistsInfo); + pd->malware_detection.bls_info = NULL; + pd->malware_detection.num_bls = 0; - if((jniCheckException(proxy->env) != 0) || (arr == NULL)) + if((jniCheckException(pd->env) != 0) || (arr == NULL)) return -1; - proxy->malware_detection.num_bls = (*env)->GetArrayLength(env, arr); - if(proxy->malware_detection.num_bls == 0) + pd->malware_detection.num_bls = (*env)->GetArrayLength(env, arr); + if(pd->malware_detection.num_bls == 0) goto cleanup; - proxy->malware_detection.bls_info = (bl_info_t*) pd_calloc(proxy->malware_detection.num_bls, sizeof(bl_info_t)); - if(proxy->malware_detection.bls_info == NULL) { - proxy->malware_detection.num_bls = 0; + pd->malware_detection.bls_info = (bl_info_t*) pd_calloc(pd->malware_detection.num_bls, sizeof(bl_info_t)); + if(pd->malware_detection.bls_info == NULL) { + pd->malware_detection.num_bls = 0; rv = -1; goto cleanup; } jobject type_ip = jniEnumVal(env, "com/emanuelef/remote_capture/model/BlacklistDescriptor$Type", "IP_BLACKLIST"); - for(int i = 0; i < proxy->malware_detection.num_bls; i++) { + for(int i = 0; i < pd->malware_detection.num_bls; i++) { jobject *bl_descr = (*env)->GetObjectArrayElement(env, arr, i); if(bl_descr != NULL) { - bl_info_t *blinfo = &proxy->malware_detection.bls_info[i]; + bl_info_t *blinfo = &pd->malware_detection.bls_info[i]; jstring fname_obj = (*env)->GetObjectField(env, bl_descr, fields.bldescr_fname); const char *fname = (*env)->GetStringUTFChars(env, fname_obj, 0); blinfo->fname = pd_strdup(fname); (*env)->ReleaseStringUTFChars(env, fname_obj, fname); - (*proxy->env)->DeleteLocalRef(proxy->env, fname_obj); + (*pd->env)->DeleteLocalRef(pd->env, fname_obj); jobject bl_type = (*env)->GetObjectField(env, bl_descr, fields.bldescr_type); blinfo->type = (*env)->IsSameObject(env, bl_type, type_ip) ? IP_BLACKLIST : DOMAIN_BLACKLIST; - (*proxy->env)->DeleteLocalRef(proxy->env, bl_type); + (*pd->env)->DeleteLocalRef(pd->env, bl_type); //log_d("[+] Blacklist: %s (%s)", blinfo->fname, (blinfo->type == IP_BLACKLIST) ? "IP" : "domain"); } } cleanup: - (*proxy->env)->DeleteLocalRef(proxy->env, arr); + (*pd->env)->DeleteLocalRef(pd->env, arr); return rv; } @@ -1118,25 +1092,25 @@ cleanup: // Loads the blacklists data into new_bl and sets reload_done. // use_new_blacklists needs to be called to use it. static void* load_new_blacklists(void *data) { - vpnproxy_data_t *proxy = (vpnproxy_data_t*) data; + pcapdroid_t *pd = (pcapdroid_t*) data; bl_status_arr_t *status_arr = pd_calloc(1, sizeof(bl_status_arr_t)); if(!status_arr) { - proxy->malware_detection.reload_done = true; + pd->malware_detection.reload_done = true; return NULL; } blacklist_t *bl = blacklist_init(); if(!bl) { pd_free(status_arr); - proxy->malware_detection.reload_done = true; + pd->malware_detection.reload_done = true; return NULL; } clock_t start = clock(); // load files in the malware_bl directory - for(int i = 0; i < proxy->malware_detection.num_bls; i++) { - bl_info_t *blinfo = &proxy->malware_detection.bls_info[i]; + for(int i = 0; i < pd->malware_detection.num_bls; i++) { + bl_info_t *blinfo = &pd->malware_detection.bls_info[i]; char subpath[256]; blacklist_stats_t stats; @@ -1171,20 +1145,20 @@ static void* load_new_blacklists(void *data) { log_d("Blacklists loaded in %.3f sec", ((double) (clock() - start)) / CLOCKS_PER_SEC); - proxy->malware_detection.new_bl = bl; - proxy->malware_detection.status_arr = status_arr; - proxy->malware_detection.reload_done = true; + pd->malware_detection.new_bl = bl; + pd->malware_detection.status_arr = status_arr; + pd->malware_detection.reload_done = true; return NULL; } /* ******************************************************* */ static int check_blocked_conn_cb(zdtun_t *tun, const zdtun_conn_t *conn_info, void *userdata) { - vpnproxy_data_t *proxy = (vpnproxy_data_t*) userdata; - conn_data_t *data = zdtun_conn_get_userdata(conn_info); + pcapdroid_t *pd = (pcapdroid_t*) userdata; + pd_conn_t *data = zdtun_conn_get_userdata(conn_info); const zdtun_5tuple_t *tuple = zdtun_conn_get_5tuple(conn_info); zdtun_ip_t dst_ip = tuple->dst_ip; - blacklist_t *bl = proxy->firewall.bl; + blacklist_t *bl = pd->firewall.bl; bool old_block = data->to_block; data->to_block = (data->blacklisted_ip || data->blacklisted_domain) || @@ -1194,7 +1168,7 @@ static int check_blocked_conn_cb(zdtun_t *tun, const zdtun_conn_t *conn_info, vo if(old_block != data->to_block) { data->update_type |= CONN_UPDATE_STATS; - notify_connection(&proxy->conns_updates, tuple, data); + pd_notify_connection_update(pd, tuple, data); } // continue @@ -1203,155 +1177,161 @@ static int check_blocked_conn_cb(zdtun_t *tun, const zdtun_conn_t *conn_info, vo /* ******************************************************* */ -void run_housekeeping(vpnproxy_data_t *proxy) { +/* Perfom periodic tasks. This should be called after processing a packet or after some time has + * passed (e.g. after a select with no packet). pd->cur_pkt.pkt is invalidated after this call. */ +void pd_housekeeping(pcapdroid_t *pd) { // can reach housekeeping from any state except housekeeping - assert(proxy->pkt_phase != PKT_PHASE_HOUSEKEEPING); - proxy->pkt_phase = PKT_PHASE_HOUSEKEEPING; + assert(pd->pkt_phase != PKT_PHASE_HOUSEKEEPING); + pd->pkt_phase = PKT_PHASE_HOUSEKEEPING; - if(proxy->capture_stats.new_stats - && ((proxy->now_ms - proxy->capture_stats.last_update_ms) >= CAPTURE_STATS_UPDATE_FREQUENCY_MS) || - dump_capture_stats_now) { + if(pd->capture_stats.new_stats + && ((pd->now_ms - pd->capture_stats.last_update_ms) >= CAPTURE_STATS_UPDATE_FREQUENCY_MS) || + dump_capture_stats_now) { dump_capture_stats_now = false; - if(!proxy->root_capture) - zdtun_get_stats(proxy->tun, &proxy->stats); + if(!pd->root_capture) + zdtun_get_stats(pd->tun, &pd->stats); - sendStatsDump(proxy); + sendStatsDump(pd); - proxy->capture_stats.new_stats = false; - proxy->capture_stats.last_update_ms = proxy->now_ms; - } else if (proxy->now_ms >= next_connections_dump) { - sendConnectionsDump(proxy); - last_connections_dump = proxy->now_ms; - next_connections_dump = proxy->now_ms + CONNECTION_DUMP_UPDATE_FREQUENCY_MS; + pd->capture_stats.new_stats = false; + pd->capture_stats.last_update_ms = pd->now_ms; + } else if (pd->now_ms >= next_connections_dump) { + sendConnectionsDump(pd); + last_connections_dump = pd->now_ms; + next_connections_dump = pd->now_ms + CONNECTION_DUMP_UPDATE_FREQUENCY_MS; netd_resolve_waiting = 0; - } else if ((proxy->pcap_dump.buffer_idx > 0) - && (proxy->now_ms - proxy->pcap_dump.last_dump_ms) >= MAX_JAVA_DUMP_DELAY_MS) { - javaPcapDump(proxy); - } else if(proxy->malware_detection.enabled) { + } else if ((pd->pcap_dump.buffer_idx > 0) + && (pd->now_ms - pd->pcap_dump.last_dump_ms) >= MAX_JAVA_DUMP_DELAY_MS) { + javaPcapDump(pd); + } else if(pd->malware_detection.enabled) { // Malware detection - if(proxy->malware_detection.reload_in_progress) { - if(proxy->malware_detection.reload_done) { - pthread_join(proxy->malware_detection.reload_worker, NULL); - proxy->malware_detection.reload_in_progress = false; - use_new_blacklists(proxy); + if(pd->malware_detection.reload_in_progress) { + if(pd->malware_detection.reload_done) { + pthread_join(pd->malware_detection.reload_worker, NULL); + pd->malware_detection.reload_in_progress = false; + use_new_blacklists(pd); } } else if(reload_blacklists_now) { reload_blacklists_now = false; - proxy->malware_detection.reload_done = false; - proxy->malware_detection.new_bl = NULL; - proxy->malware_detection.status_arr = NULL; - pthread_create(&proxy->malware_detection.reload_worker, NULL, load_new_blacklists, - proxy); - proxy->malware_detection.reload_in_progress = true; + pd->malware_detection.reload_done = false; + pd->malware_detection.new_bl = NULL; + pd->malware_detection.status_arr = NULL; + pthread_create(&pd->malware_detection.reload_worker, NULL, load_new_blacklists, + pd); + pd->malware_detection.reload_in_progress = true; } } - if(proxy->firewall.new_bl) { + if(pd->firewall.new_bl) { // Load new bl - if(proxy->firewall.bl) - blacklist_destroy(proxy->firewall.bl); - proxy->firewall.bl = proxy->firewall.new_bl; - proxy->firewall.new_bl = NULL; + if(pd->firewall.bl) + blacklist_destroy(pd->firewall.bl); + pd->firewall.bl = pd->firewall.new_bl; + pd->firewall.new_bl = NULL; - if(proxy->tun) - zdtun_iter_connections(proxy->tun, check_blocked_conn_cb, proxy); + if(pd->tun) + zdtun_iter_connections(pd->tun, check_blocked_conn_cb, pd); } // avoid using freed data - proxy->cur_pkt.pkt = NULL; + pd->cur_pkt.pkt = NULL; } /* ******************************************************* */ -void refresh_time(vpnproxy_data_t *proxy) { +/* Refresh the monotonic time. This must be called before any call to pd_housekeeping. */ +void pd_refresh_time(pcapdroid_t *pd) { struct timespec ts; // can be reached by any phase - proxy->pkt_phase = PKT_PHASE_REFRESH_TIME; + pd->pkt_phase = PKT_PHASE_REFRESH_TIME; if(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts)) { log_d("clock_gettime failed[%d]: %s", errno, strerror(errno)); return; } - proxy->now_ms = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + pd->now_ms = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } /* ******************************************************* */ static void log_callback(int lvl, const char *line) { if(lvl >= ANDROID_LOG_FATAL) { - vpnproxy_data_t *proxy = global_proxy; + pcapdroid_t *pd = global_pd; // This is a fatal error, report it to the gui - jobject info_string = (*proxy->env)->NewStringUTF(proxy->env, line); + jobject info_string = (*pd->env)->NewStringUTF(pd->env, line); - if((jniCheckException(proxy->env) != 0) || (info_string == NULL)) + if((jniCheckException(pd->env) != 0) || (info_string == NULL)) return; - (*proxy->env)->CallVoidMethod(proxy->env, proxy->vpn_service, mids.reportError, info_string); - jniCheckException(proxy->env); + (*pd->env)->CallVoidMethod(pd->env, pd->vpn_service, mids.reportError, info_string); + jniCheckException(pd->env); - (*proxy->env)->DeleteLocalRef(proxy->env, info_string); + (*pd->env)->DeleteLocalRef(pd->env, info_string); } } /* ******************************************************* */ -void fill_custom_data(struct pcapdroid_trailer *cdata, vpnproxy_data_t *proxy, conn_data_t *conn) { +void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn) { memset(cdata, 0, sizeof(*cdata)); cdata->magic = htonl(PCAPDROID_TRAILER_MAGIC); cdata->uid = htonl(conn->uid); - get_appname_by_uid(proxy, conn->uid, cdata->appname, sizeof(cdata->appname)); + get_appname_by_uid(pd, conn->uid, cdata->appname, sizeof(cdata->appname)); } /* ******************************************************* */ -void set_current_packet(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv) { - assert(proxy->pkt_phase == PKT_PHASE_REFRESH_TIME); - proxy->pkt_phase = PKT_PHASE_PKT_SET; +/* Set the current packet data. The packet pointer is available via pd->cur_pkt.pkt until the next + * call to pd_housekeeping. This must be called after pd_refresh_time. */ +void pd_set_current_packet(pcapdroid_t *pd, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv) { + assert(pd->pkt_phase == PKT_PHASE_REFRESH_TIME); + pd->pkt_phase = PKT_PHASE_PKT_SET; - proxy->cur_pkt.pkt = pkt; - proxy->cur_pkt.tv = *tv; - proxy->cur_pkt.ms = (uint64_t)tv->tv_sec * 1000 + tv->tv_usec / 1000; - proxy->cur_pkt.is_tx = is_tx; + pd->cur_pkt.pkt = pkt; + pd->cur_pkt.tv = *tv; + pd->cur_pkt.ms = (uint64_t)tv->tv_sec * 1000 + tv->tv_usec / 1000; + pd->cur_pkt.is_tx = is_tx; } /* ******************************************************* */ -void account_stats(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_tuple, conn_data_t *data) { - zdtun_pkt_t *pkt = proxy->cur_pkt.pkt; +/* Update the stats for the current packet. */ +void pd_account_stats(pcapdroid_t *pd, const zdtun_5tuple_t *conn_tuple, pd_conn_t *data) { + zdtun_pkt_t *pkt = pd->cur_pkt.pkt; - assert(proxy->pkt_phase == PKT_PHASE_PKT_SET); - proxy->pkt_phase = PKT_PHASE_ACCOUNT_STATS; + assert(pd->pkt_phase == PKT_PHASE_PKT_SET); + pd->pkt_phase = PKT_PHASE_ACCOUNT_STATS; - data->last_seen = proxy->cur_pkt.ms; + data->last_seen = pd->cur_pkt.ms; if(!data->first_seen) data->first_seen = data->last_seen; - if(proxy->cur_pkt.is_tx) { + if(pd->cur_pkt.is_tx) { data->sent_pkts++; data->sent_bytes += pkt->len; - proxy->capture_stats.sent_pkts++; - proxy->capture_stats.sent_bytes += pkt->len; + pd->capture_stats.sent_pkts++; + pd->capture_stats.sent_bytes += pkt->len; } else { data->rcvd_pkts++; data->rcvd_bytes += pkt->len; - proxy->capture_stats.rcvd_pkts++; - proxy->capture_stats.rcvd_bytes += pkt->len; + pd->capture_stats.rcvd_pkts++; + pd->capture_stats.rcvd_bytes += pkt->len; } if(data->ndpi_flow && (!(pkt->flags & ZDTUN_PKT_IS_FRAGMENT) || (pkt->flags & ZDTUN_PKT_IS_FIRST_FRAGMENT))) { // nDPI cannot handle fragments, since they miss the L4 layer (see ndpi_iph_is_valid_and_not_fragmented) - process_ndpi_packet(proxy, data); + process_ndpi_packet(pd, data); if(((data->l7proto.master_protocol == NDPI_PROTOCOL_DNS) || (data->l7proto.app_protocol == NDPI_PROTOCOL_DNS)) && (data->uid == UID_NETD) && (data->sent_pkts + data->rcvd_pkts == 1) - && ((netd_resolve_waiting > 0) || ((next_connections_dump - NETD_RESOLVE_DELAY_MS) < proxy->now_ms))) { + && ((netd_resolve_waiting > 0) || ((next_connections_dump - NETD_RESOLVE_DELAY_MS) < pd->now_ms))) { if(netd_resolve_waiting == 0) { // Wait before sending the dump to possibly resolve netd DNS connections uid. // Only delay for the first DNS request, to avoid excessive delay. @@ -1363,27 +1343,27 @@ void account_stats(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_tuple, con } /* New stats to notify */ - proxy->capture_stats.new_stats = true; + pd->capture_stats.new_stats = true; data->update_type |= CONN_UPDATE_STATS; - notify_connection(&proxy->conns_updates, conn_tuple, data); + pd_notify_connection_update(pd, conn_tuple, data); - if (proxy->pcap_dump.buffer) { + if (pd->pcap_dump.buffer) { int rec_size = pcap_rec_size(pkt->len); - if ((JAVA_PCAP_BUFFER_SIZE - proxy->pcap_dump.buffer_idx) <= rec_size) { + if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size) { // Flush the buffer - javaPcapDump(proxy); + javaPcapDump(pd); } - if ((JAVA_PCAP_BUFFER_SIZE - proxy->pcap_dump.buffer_idx) <= rec_size) + if ((JAVA_PCAP_BUFFER_SIZE - pd->pcap_dump.buffer_idx) <= rec_size) log_e("Invalid buffer size [size=%d, idx=%d, tot_size=%d]", - JAVA_PCAP_BUFFER_SIZE, proxy->pcap_dump.buffer_idx, rec_size); + JAVA_PCAP_BUFFER_SIZE, pd->pcap_dump.buffer_idx, rec_size); else { - pcap_dump_rec((u_char *) proxy->pcap_dump.buffer + proxy->pcap_dump.buffer_idx, - proxy, data); + pcap_dump_rec((u_char *) pd->pcap_dump.buffer + pd->pcap_dump.buffer_idx, + pd, data); - proxy->pcap_dump.buffer_idx += rec_size; + pd->pcap_dump.buffer_idx += rec_size; } } } @@ -1431,7 +1411,7 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { fields.bldescr_fname = jniFieldID(env, cls.blacklist_descriptor, "fname", "Ljava/lang/String;"); fields.bldescr_type = jniFieldID(env, cls.blacklist_descriptor, "type", "Lcom/emanuelef/remote_capture/model/BlacklistDescriptor$Type;"); - vpnproxy_data_t proxy = { + pcapdroid_t pd = { .tunfd = tunfd, .sdk = sdk, .env = env, @@ -1462,13 +1442,13 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { } }; - getStringPref(&proxy, "getWorkingDir", proxy.cachedir, sizeof(proxy.cachedir)); - strcat(proxy.cachedir, "/"); - proxy.cachedir_len = strlen(proxy.cachedir); + getStringPref(&pd, "getWorkingDir", pd.cachedir, sizeof(pd.cachedir)); + strcat(pd.cachedir, "/"); + pd.cachedir_len = strlen(pd.cachedir); - getStringPref(&proxy, "getPersistentDir", proxy.filesdir, sizeof(proxy.filesdir)); - strcat(proxy.filesdir, "/"); - proxy.filesdir_len = strlen(proxy.filesdir); + getStringPref(&pd, "getPersistentDir", pd.filesdir, sizeof(pd.filesdir)); + strcat(pd.filesdir, "/"); + pd.filesdir_len = strlen(pd.filesdir); // Enable or disable the PCAPdroid trailer pcap_set_pcapdroid_trailer((bool)getIntPref(env, vpn, "addPcapdroidTrailer")); @@ -1477,101 +1457,101 @@ static int run_tun(JNIEnv *env, jclass vpn, int tunfd, jint sdk) { running = true; logcallback = log_callback; - global_proxy = &proxy; + global_pd = &pd; /* nDPI */ - proxy.ndpi = init_ndpi(); + pd.ndpi = init_ndpi(); init_protocols_bitmask(&masterProtos); - if(proxy.ndpi == NULL) { + if(pd.ndpi == NULL) { log_f("nDPI initialization failed"); return(-1); } - if(proxy.malware_detection.enabled) - load_blacklists_info(&proxy); + if(pd.malware_detection.enabled) + load_blacklists_info(&pd); // Load the blacklist before starting - if(proxy.malware_detection.enabled && reload_blacklists_now) { + if(pd.malware_detection.enabled && reload_blacklists_now) { reload_blacklists_now = false; - load_new_blacklists(&proxy); - use_new_blacklists(&proxy); + load_new_blacklists(&pd); + use_new_blacklists(&pd); } signal(SIGPIPE, SIG_IGN); - if(proxy.pcap_dump.enabled) { - proxy.pcap_dump.buffer = pd_malloc(JAVA_PCAP_BUFFER_SIZE); - proxy.pcap_dump.buffer_idx = 0; + if(pd.pcap_dump.enabled) { + pd.pcap_dump.buffer = pd_malloc(JAVA_PCAP_BUFFER_SIZE); + pd.pcap_dump.buffer_idx = 0; - if(!proxy.pcap_dump.buffer) { + if(!pd.pcap_dump.buffer) { log_f("malloc(pcap_dump.buffer) failed with code %d/%s", errno, strerror(errno)); running = false; } } - memset(&proxy.stats, 0, sizeof(proxy.stats)); + memset(&pd.stats, 0, sizeof(pd.stats)); - proxy.pkt_phase = PKT_PHASE_HOUSEKEEPING; - refresh_time(&proxy); - last_connections_dump = proxy.now_ms; + pd.pkt_phase = PKT_PHASE_HOUSEKEEPING; + pd_refresh_time(&pd); + last_connections_dump = pd.now_ms; next_connections_dump = last_connections_dump + 500 /* first update after 500 ms */; bl_num_checked_connections = 0; - notifyServiceStatus(&proxy, "started"); + notifyServiceStatus(&pd, "started"); // Run the capture - int rv = proxy.root_capture ? run_root(&proxy) : run_proxy(&proxy); + int rv = pd.root_capture ? run_root(&pd) : run_vpn(&pd); log_d("Stopped packet loop"); - conns_clear(&proxy.new_conns, true); - conns_clear(&proxy.conns_updates, true); + conns_clear(&pd.new_conns, true); + conns_clear(&pd.conns_updates, true); - if(proxy.firewall.bl) - blacklist_destroy(proxy.firewall.bl); - if(proxy.firewall.new_bl) - blacklist_destroy(proxy.firewall.new_bl); + if(pd.firewall.bl) + blacklist_destroy(pd.firewall.bl); + if(pd.firewall.new_bl) + blacklist_destroy(pd.firewall.new_bl); - if(proxy.malware_detection.enabled) { - if(proxy.malware_detection.reload_in_progress) { + if(pd.malware_detection.enabled) { + if(pd.malware_detection.reload_in_progress) { log_d("Joining blacklists reload_worker"); - pthread_join(proxy.malware_detection.reload_worker, NULL); + pthread_join(pd.malware_detection.reload_worker, NULL); } - if(proxy.malware_detection.bl) - blacklist_destroy(proxy.malware_detection.bl); - if(proxy.malware_detection.bls_info) { - for(int i=0; i 0) - javaPcapDump(&proxy); + if(pd.pcap_dump.buffer) { + if(pd.pcap_dump.buffer_idx > 0) + javaPcapDump(&pd); - pd_free(proxy.pcap_dump.buffer); - proxy.pcap_dump.buffer = NULL; + pd_free(pd.pcap_dump.buffer); + pd.pcap_dump.buffer = NULL; } uid_to_app_t *e, *tmp; - HASH_ITER(hh, proxy.uid2app, e, tmp) { - HASH_DEL(proxy.uid2app, e); + HASH_ITER(hh, pd.uid2app, e, tmp) { + HASH_DEL(pd.uid2app, e); pd_free(e); } - notifyServiceStatus(&proxy, "stopped"); - destroy_uid_resolver(proxy.resolver); - ndpi_ptree_destroy(proxy.known_dns_servers); + notifyServiceStatus(&pd, "stopped"); + destroy_uid_resolver(pd.resolver); + ndpi_ptree_destroy(pd.known_dns_servers); - log_d("Host LRU cache size: %d", ip_lru_size(proxy.ip_to_host)); - log_d("Discarded fragments: %ld", proxy.num_discarded_fragments); - ip_lru_destroy(proxy.ip_to_host); + log_d("Host LRU cache size: %d", ip_lru_size(pd.ip_to_host)); + log_d("Discarded fragments: %ld", pd.num_discarded_fragments); + ip_lru_destroy(pd.ip_to_host); logcallback = NULL; - global_proxy = NULL; + global_pd = NULL; #ifdef PCAPDROID_TRACK_ALLOCS log_i(get_allocs_summary()); @@ -1689,18 +1669,18 @@ static int bl_add_array(JNIEnv *env, blacklist_t *bl, jobjectArray arr, blacklis JNIEXPORT jboolean JNICALL Java_com_emanuelef_remote_1capture_CaptureService_reloadBlocklist(JNIEnv *env, jclass clazz, jobjectArray apps, jobjectArray domains, jobjectArray ips) { - vpnproxy_data_t *proxy = global_proxy; - if(!proxy) { - log_e("NULL proxy instance"); + pcapdroid_t *pd = global_pd; + if(!pd) { + log_e("NULL pd instance"); return false; } - if(proxy->root_capture) { + if(pd->root_capture) { log_e("firewall in root mode not implemented"); return false; } - if(proxy->firewall.new_bl != NULL) { + if(pd->firewall.new_bl != NULL) { log_e("previous bl not loaded yet"); return false; } @@ -1722,6 +1702,6 @@ Java_com_emanuelef_remote_1capture_CaptureService_reloadBlocklist(JNIEnv *env, j } log_d("reloadBlocklist: %d apps, %d domains, %d IPs", num_apps, num_domains, num_ips); - proxy->firewall.new_bl = bl; + pd->firewall.new_bl = bl; return true; } \ No newline at end of file diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.h b/app/src/main/jni/core/pcapdroid.h similarity index 79% rename from app/src/main/jni/vpnproxy-jni/vpnproxy.h rename to app/src/main/jni/core/pcapdroid.h index 5b4eb6a0..e167f2e1 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.h +++ b/app/src/main/jni/core/pcapdroid.h @@ -57,17 +57,17 @@ typedef struct { u_int64_t last_update_ms; } capture_stats_t; -// This tracks the packet processing phases, to ensure that the vpnproxy functions are called in +// This tracks the packet processing phases, to ensure that the API functions are called in // the correct order. typedef enum { - PKT_PHASE_REFRESH_TIME = 0, // refresh_time - PKT_PHASE_PKT_SET, // set_current_packet - PKT_PHASE_ACCOUNT_STATS, // account_stats - PKT_PHASE_HOUSEKEEPING, // run_housekeeping + PKT_PHASE_REFRESH_TIME = 0, // pd_refresh_time + PKT_PHASE_PKT_SET, // pd_set_current_packet + PKT_PHASE_ACCOUNT_STATS, // pd_account_stats + PKT_PHASE_HOUSEKEEPING, // pd_housekeeping } pkt_processing_phase_t; typedef struct { - jint incr_id; /* an incremental identifier */ + jint incr_id; // an incremental number which identifies a specific connection /* nDPI */ struct ndpi_flow_struct *ndpi_flow; @@ -99,15 +99,15 @@ typedef struct { char *request_data; char *url; uint8_t update_type; -} conn_data_t; +} pd_conn_t; typedef struct { zdtun_5tuple_t tuple; - conn_data_t *data; -} vpn_conn_t; + pd_conn_t *data; +} conn_and_tuple_t; typedef struct { - vpn_conn_t *items; + conn_and_tuple_t *items; int size; int cur_items; } conn_array_t; @@ -118,22 +118,6 @@ typedef struct { UT_hash_handle hh; } uid_to_app_t; -typedef struct { - char *fname; - blacklist_type type; -} bl_info_t; - -typedef struct { - char *fname; - int num_rules; -} bl_status_t; - -typedef struct { - bl_status_t *items; - int size; - int cur_items; -} bl_status_arr_t; - typedef struct pcap_conn pcap_conn_t; typedef struct { @@ -154,7 +138,7 @@ typedef struct { char filesdir[PATH_MAX]; int cachedir_len; int filesdir_len; - uint64_t now_ms; // Monotonic timestamp, see refresh_time + uint64_t now_ms; // Monotonic timestamp, see pd_refresh_time u_int num_dropped_pkts; long num_discarded_fragments; u_int32_t num_dropped_connections; @@ -168,7 +152,7 @@ typedef struct { pcap_conn_t *connections; // root only pkt_processing_phase_t pkt_phase; - // populated via set_current_packet + // populated via pd_set_current_packet struct { zdtun_pkt_t *pkt; struct timeval tv; // Packet timestamp, need by pcap_dump_rec @@ -214,7 +198,7 @@ typedef struct { } firewall; capture_stats_t capture_stats; -} vpnproxy_data_t; +} pcapdroid_t; /* ******************************************************* */ @@ -274,32 +258,31 @@ extern bool running; extern uint32_t new_dns_server; extern bool block_private_dns; -struct pcapdroid_trailer; +// capture API +void pd_refresh_time(pcapdroid_t *pd); +void pd_set_current_packet(pcapdroid_t *pd, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv); +void pd_account_stats(pcapdroid_t *pd, const zdtun_5tuple_t *conn_tuple, pd_conn_t *data); +void pd_housekeeping(pcapdroid_t *pd); +pd_conn_t* pd_new_connection(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, int uid); +void pd_destroy_connection(pd_conn_t *data); +void pd_notify_connection_update(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data); +void pd_giveup_dpi(pcapdroid_t *pd, pd_conn_t *data, const zdtun_5tuple_t *tuple); -conn_data_t* new_connection(vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple, int uid); -void conn_free_data(conn_data_t *data); -void notify_connection(conn_array_t *arr, const zdtun_5tuple_t *tuple, conn_data_t *data); -void conn_end_ndpi_detection(conn_data_t *data, vpnproxy_data_t *proxy, const zdtun_5tuple_t *tuple); -void run_housekeeping(vpnproxy_data_t *proxy); -void set_current_packet(vpnproxy_data_t *proxy, zdtun_pkt_t *pkt, bool is_tx, struct timeval *tv); -void account_stats(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_tuple, conn_data_t *data); -int resolve_uid(vpnproxy_data_t *proxy, const zdtun_5tuple_t *conn_info); -void refresh_time(vpnproxy_data_t *proxy); -void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b); -void vpn_protect_socket(vpnproxy_data_t *proxy, socket_t sock); -void fill_custom_data(struct pcapdroid_trailer *cdata, vpnproxy_data_t *proxy, conn_data_t *conn); -uint32_t crc32(u_char *buf, size_t len, uint32_t crc); +// Utility const char* get_cache_path(const char *subpath); const char* get_file_path(const char *subpath); static inline const char* get_cache_dir() { return get_cache_path(""); } static inline const char* get_files_dir() { return get_file_path(""); } - -char* getStringPref(vpnproxy_data_t *proxy, const char *key, char *buf, int bufsize); +char* get_appname_by_uid(pcapdroid_t *pd, int uid, char *buf, int bufsize); +char* getStringPref(pcapdroid_t *pd, const char *key, char *buf, int bufsize); int getIntPref(JNIEnv *env, jobject vpn_inst, const char *key); uint32_t getIPv4Pref(JNIEnv *env, jobject vpn_inst, const char *key); struct in6_addr getIPv6Pref(JNIEnv *env, jobject vpn_inst, const char *key); -int run_proxy(vpnproxy_data_t *proxy); -int run_root(vpnproxy_data_t *proxy); +// Internals +struct pcapdroid_trailer; +void fill_custom_data(struct pcapdroid_trailer *cdata, pcapdroid_t *pd, pd_conn_t *conn); +void init_protocols_bitmask(ndpi_protocol_bitmask_struct_t *b); +uint32_t crc32(u_char *buf, size_t len, uint32_t crc); #endif //__PCAPDROID_H__ diff --git a/app/src/main/jni/pcapd/README.md b/app/src/main/jni/pcapd/README.md index c93726e0..9e835281 100644 --- a/app/src/main/jni/pcapd/README.md +++ b/app/src/main/jni/pcapd/README.md @@ -58,7 +58,7 @@ Here are the steps to make it communicate with your app: 5. The app can now receive the packets on the UNIX socket. 6. When the app closes the UNIX socket, the pcapd daemon is automatically stopped. -Check out the [capture_root.c source](https://github.com/emanuele-f/PCAPdroid/blob/master/app/src/main/jni/vpnproxy-jni/capture_root.c) to see an example of integration. +Check out the [capture_root.c source](https://github.com/emanuele-f/PCAPdroid/blob/master/app/src/main/jni/core/capture_root.c) to see an example of integration. Packets Data ------------