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 b14c721f..e8f204ba 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -585,8 +585,7 @@ public class CaptureService extends VpnService implements Runnable { // signal termination mPendingUpdates.offer(new Pair<>(null, null)); - if(mDumpQueue != null) - mDumpQueue.offer(new byte[0]); + stopPcapDump(); while((mCaptureThread != null) && (mCaptureThread.isAlive())) { try { @@ -615,7 +614,7 @@ public class CaptureService extends VpnService implements Runnable { mDumperThread.join(); } catch (InterruptedException e) { Log.e(TAG, "Joining dumper thread failed"); - mDumpQueue.offer(new byte[0]); + stopPcapDump(); } } mDumperThread = null; @@ -1005,6 +1004,11 @@ public class CaptureService extends VpnService implements Runnable { } } + public void stopPcapDump() { + if((mDumpQueue != null) && (mDumperThread != null) && (mDumperThread.isAlive())) + mDumpQueue.offer(new byte[0]); + } + public void reportError(String msg) { mHandler.post(() -> { Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); diff --git a/app/src/main/jni/core/jni_impl.c b/app/src/main/jni/core/jni_impl.c index e216649e..65e67707 100644 --- a/app/src/main/jni/core/jni_impl.c +++ b/app/src/main/jni/core/jni_impl.c @@ -112,6 +112,15 @@ static void sendPcapDump(pcapdroid_t *pd) { /* ******************************************************* */ +static void stopPcapDump(pcapdroid_t *pd) { + JNIEnv *env = pd->env; + + (*env)->CallVoidMethod(env, pd->capture_service, mids.stopPcapDump); + jniCheckException(env); +} + +/* ******************************************************* */ + static void notifyServiceStatus(pcapdroid_t *pd, const char *status) { JNIEnv *env = pd->env; jstring status_str; @@ -436,6 +445,7 @@ Java_com_emanuelef_remote_1capture_CaptureService_runPacketLoop(JNIEnv *env, jcl mids.getApplicationByUid = jniGetMethodID(env, vpn_class, "getApplicationByUid", "(I)Ljava/lang/String;"), mids.protect = jniGetMethodID(env, vpn_class, "protect", "(I)Z"); mids.dumpPcapData = jniGetMethodID(env, vpn_class, "dumpPcapData", "([B)V"); + mids.stopPcapDump = jniGetMethodID(env, vpn_class, "stopPcapDump", "()V"); mids.updateConnections = jniGetMethodID(env, vpn_class, "updateConnections", "([Lcom/emanuelef/remote_capture/model/ConnectionDescriptor;[Lcom/emanuelef/remote_capture/model/ConnectionUpdate;)V"); mids.sendStatsDump = jniGetMethodID(env, vpn_class, "sendStatsDump", "(Lcom/emanuelef/remote_capture/model/VPNStats;)V"); mids.sendServiceStatus = jniGetMethodID(env, vpn_class, "sendServiceStatus", "(Ljava/lang/String;)V"); @@ -470,6 +480,7 @@ Java_com_emanuelef_remote_1capture_CaptureService_runPacketLoop(JNIEnv *env, jcl .send_stats_dump = sendStatsDump, .send_connections_dump = sendConnectionsDump, .send_pcap_dump = sendPcapDump, + .stop_pcap_dump = stopPcapDump, .notify_service_status = notifyServiceStatus, .notify_blacklists_loaded = notifyBlacklistsLoaded, }, diff --git a/app/src/main/jni/core/pcapdroid.c b/app/src/main/jni/core/pcapdroid.c index 670b5588..26f3d9c4 100644 --- a/app/src/main/jni/core/pcapdroid.c +++ b/app/src/main/jni/core/pcapdroid.c @@ -875,6 +875,9 @@ static int check_blacklisted_conn_cb(pcapdroid_t *pd, const zdtun_5tuple_t *tupl /* ******************************************************* */ static void sendPcapDump(pcapdroid_t *pd) { + if(pd->pcap_dump.buffer_idx == 0) + return; + if(pd->cb.send_pcap_dump) pd->cb.send_pcap_dump(pd); @@ -884,6 +887,17 @@ static void sendPcapDump(pcapdroid_t *pd) { /* ******************************************************* */ +static void stop_pcap_dump(pcapdroid_t *pd){ + sendPcapDump(pd); + pd_free(pd->pcap_dump.buffer); + pd->pcap_dump.buffer = NULL; + + if(pd->cb.stop_pcap_dump) + pd->cb.stop_pcap_dump(pd); +} + +/* ******************************************************* */ + /* 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). */ void pd_housekeeping(pcapdroid_t *pd) { @@ -1046,8 +1060,8 @@ void pd_account_stats(pcapdroid_t *pd, pkt_context_t *pctx) { JAVA_PCAP_BUFFER_SIZE, pd->pcap_dump.buffer_idx, rec_size); else if((pd->pcap_dump.max_dump_size > 0) && ((pd->pcap_dump.tot_size + rec_size) >= pd->pcap_dump.max_dump_size)) { - log_d("Max dump size reached, stopping capture"); - running = false; + log_d("Max dump size reached, stop the dump"); + stop_pcap_dump(pd); } else { pcap_dump_rec(pd, (u_char *) pd->pcap_dump.buffer + pd->pcap_dump.buffer_idx, pctx); @@ -1148,13 +1162,8 @@ int pd_run(pcapdroid_t *pd) { ndpi_exit_detection_module(pd->ndpi); #endif - if(pd->pcap_dump.buffer) { - if(pd->pcap_dump.buffer_idx > 0) - sendPcapDump(pd); - - pd_free(pd->pcap_dump.buffer); - pd->pcap_dump.buffer = NULL; - } + if(pd->pcap_dump.buffer) + stop_pcap_dump(pd); uid_to_app_t *e, *tmp; HASH_ITER(hh, pd->uid2app, e, tmp) { diff --git a/app/src/main/jni/core/pcapdroid.h b/app/src/main/jni/core/pcapdroid.h index 3a9c7f6a..198b3d80 100644 --- a/app/src/main/jni/core/pcapdroid.h +++ b/app/src/main/jni/core/pcapdroid.h @@ -143,6 +143,7 @@ typedef struct { void (*send_stats_dump)(struct pcapdroid *pd); void (*send_connections_dump)(struct pcapdroid *pd); void (*send_pcap_dump)(struct pcapdroid *pd); + void (*stop_pcap_dump)(struct pcapdroid *pd); void (*notify_service_status)(struct pcapdroid *pd, const char *status); void (*notify_blacklists_loaded)(struct pcapdroid *pd, bl_status_arr_t *status_arr); } pd_callbacks_t; @@ -266,6 +267,7 @@ typedef struct { jmethodID getApplicationByUid; jmethodID protect; jmethodID dumpPcapData; + jmethodID stopPcapDump; jmethodID updateConnections; jmethodID connInit; jmethodID connProcessUpdate; diff --git a/docs/app_api.md b/docs/app_api.md index b7649b00..8f600007 100644 --- a/docs/app_api.md +++ b/docs/app_api.md @@ -83,10 +83,10 @@ As shown above, the capture settings can be specified by using intent extras. Th | ipv6_enabled | bool | | true to enable IPv6 support in non-root mode | | root_capture | bool | | true to capture packets in root mode, false to use the VPNService | | pcapdroid_trailer | bool | | true to enable the PCAPdroid trailer | -| capture_interface | string | 42 | @inet \| any \| ifname - network interface to use in root mode | +| capture_interface | string | | @inet \| any \| ifname - network interface to use in root mode | | snaplen | int | 43 | max size in bytes for each individual packet in the PCAP dump | | max_pkts_per_flow | int | 43 | only dump the first max_pkts_per_flow packets per flow | -| max_dump_size | int | 43 | PCAP dump max bytes before the capture is automatically stopped | +| max_dump_size | int | 43 | max size in bytes for the PCAP dump | The `Ver` column indicates the minimum PCAPdroid version required to use the given parameter. The PCAPdroid version can be queried via the `get_status` action as explained below.