diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnDescriptor.java b/app/src/main/java/com/emanuelef/remote_capture/ConnDescriptor.java index 78252275..59656225 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnDescriptor.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnDescriptor.java @@ -42,6 +42,7 @@ class ConnDescriptor implements Serializable { String l7proto; int uid; int incr_id; + boolean closed; /* Invoked by native code * NOTE: interleaving String and int in the parameters is not good as it makes the app crash @@ -49,7 +50,7 @@ class ConnDescriptor implements Serializable { public void setData(String _src_ip, String _dst_ip, String _info, String _url, String _l7proto, int _ipproto, int _src_port, int _dst_port, long _first_seen, long _last_seen, long _sent_bytes, long _rcvd_bytes, int _sent_pkts, int _rcvd_pkts, int _uid, - int _incr_id) { + int _incr_id, boolean _closed) { /* Metadata */ ipproto = _ipproto; src_ip = _src_ip; @@ -69,5 +70,6 @@ class ConnDescriptor implements Serializable { l7proto = _l7proto; uid = _uid; incr_id = _incr_id; + closed = _closed; } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsAdapter.java b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsAdapter.java index 848d2afc..f046639f 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsAdapter.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsAdapter.java @@ -35,6 +35,7 @@ import java.util.Objects; class ViewHolder extends RecyclerView.ViewHolder { ImageView icon; + ImageView statusInd; TextView remote; TextView l7proto; TextView traffic; @@ -46,6 +47,7 @@ class ViewHolder extends RecyclerView.ViewHolder { remote = itemView.findViewById(R.id.remote); l7proto = itemView.findViewById(R.id.l7proto); traffic = itemView.findViewById(R.id.traffic); + statusInd = itemView.findViewById(R.id.status_ind); } public void bindConn(MainActivity activity, ConnDescriptor conn, Drawable unknownIcon) { @@ -63,6 +65,9 @@ class ViewHolder extends RecyclerView.ViewHolder { l7proto.setText(conn.l7proto); traffic.setText(Utils.formatBytes(conn.sent_bytes + conn.rcvd_bytes)); + + if(conn.closed) + statusInd.setVisibility(View.INVISIBLE); } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java index 320f0315..5883b2d8 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java @@ -31,6 +31,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -80,6 +81,10 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C mAdapter = new ConnectionsAdapter(mActivity); mRecyclerView.setAdapter(mAdapter); + /*DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), + layoutMan.getOrientation()); + mRecyclerView.addItemDecoration(dividerItemDecoration);*/ + mAdapter.setClickListener(v -> { int pos = mRecyclerView.getChildLayoutPosition(v); ConnDescriptor item = mAdapter.getItem(pos); diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.c b/app/src/main/jni/vpnproxy-jni/vpnproxy.c index 737438ad..1039b00e 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.c +++ b/app/src/main/jni/vpnproxy-jni/vpnproxy.c @@ -169,7 +169,7 @@ static void conns_clear(conn_array_t *arr, bool free_all) { for(int i=0; i < arr->cur_items; i++) { vpn_conn_t *slot = &arr->items[i]; - if(slot->data && (slot->data->terminated || free_all)) + if(slot->data && (slot->data->closed || free_all)) free_connection_data(slot->data); } @@ -283,7 +283,21 @@ struct ndpi_detection_module_struct* init_ndpi() { /* ******************************************************* */ -const char *getL7ProtoName(struct ndpi_detection_module_struct *mod, ndpi_protocol l7proto) { +const char *getProtoName(struct ndpi_detection_module_struct *mod, ndpi_protocol l7proto, int ipproto) { + if(l7proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) { + // Return the L3 protocol + switch (ipproto) { + case IPPROTO_TCP: + return "TCP"; + case IPPROTO_UDP: + return "UDP"; + case IPPROTO_ICMP: + return "ICMP"; + default: + return "Unknown"; + } + } + return ndpi_get_proto_name(mod, l7proto.master_protocol); } @@ -558,7 +572,7 @@ static void destroy_connection(zdtun_t *tun, const zdtun_conn_t *conn_info) { /* Will free the other data in sendConnectionsDump */ free_ndpi(data); - data->terminated = true; + data->closed = true; } /* ******************************************************* */ @@ -707,7 +721,7 @@ static int dumpConnection(vpnproxy_data_t *proxy, const vpn_conn_t *conn, jobjec jobject info_string = (*env)->NewStringUTF(env, data->info ? data->info : ""); jobject url_string = (*env)->NewStringUTF(env, data->url ? data->url : ""); - jobject proto_string = (*env)->NewStringUTF(env, getL7ProtoName(proxy->ndpi, data->l7proto)); + jobject proto_string = (*env)->NewStringUTF(env, getProtoName(proxy->ndpi, data->l7proto, conn_info->ipproto)); jobject src_string = (*env)->NewStringUTF(env, srcip); jobject dst_string = (*env)->NewStringUTF(env, dstip); jobject conn_descriptor = (*env)->NewObject(env, cls.conn, mids.connInit); @@ -720,8 +734,8 @@ static int dumpConnection(vpnproxy_data_t *proxy, const vpn_conn_t *conn, jobjec conn_info->ipproto, ntohs(conn_info->src_port), ntohs(conn_info->dst_port), data->first_seen, data->last_seen, data->sent_bytes, - data->rcvd_bytes, - data->sent_pkts, data->rcvd_pkts, data->uid, data->incr_id); + data->rcvd_bytes, data->sent_pkts, + data->rcvd_pkts, data->uid, data->incr_id, data->closed); if(jniCheckException(env)) rv = -1; else { @@ -894,7 +908,7 @@ static int run_tun(JNIEnv *env, jclass vpn, int tapfd, jint sdk) { mids.connInit = jniGetMethodID(env, cls.conn, "", "()V"); mids.connSetData = jniGetMethodID(env, cls.conn, "setData", /* NOTE: must match ConnDescriptor::setData */ - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIJJJJIIII)V"); + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIJJJJIIIIZ)V"); mids.statsInit = jniGetMethodID(env, cls.stats, "", "()V"); mids.statsSetData = jniGetMethodID(env, cls.stats, "setData", "(IIIIII)V"); diff --git a/app/src/main/jni/vpnproxy-jni/vpnproxy.h b/app/src/main/jni/vpnproxy-jni/vpnproxy.h index 476eade4..c4c409b7 100644 --- a/app/src/main/jni/vpnproxy-jni/vpnproxy.h +++ b/app/src/main/jni/vpnproxy-jni/vpnproxy.h @@ -52,7 +52,7 @@ typedef struct conn_data { char *info; char *url; jint uid; - bool terminated; + bool closed; bool pending_notification; bool mitm_header_needed; } conn_data_t; diff --git a/app/src/main/res/drawable/ic_active_connection.xml b/app/src/main/res/drawable/ic_active_connection.xml new file mode 100644 index 00000000..6e0be2fd --- /dev/null +++ b/app/src/main/res/drawable/ic_active_connection.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/connection_item.xml b/app/src/main/res/layout/connection_item.xml index 0495a581..3d42b7b6 100644 --- a/app/src/main/res/layout/connection_item.xml +++ b/app/src/main/res/layout/connection_item.xml @@ -2,37 +2,59 @@ + android:orientation="horizontal" + android:paddingHorizontal="4dp" + android:layout_height="42dp"> + + + +