mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-16 21:10:57 +08:00
parent
3e08121edc
commit
7e7d469666
@ -25,6 +25,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import android.net.VpnService;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -41,7 +42,9 @@ import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
import com.emanuelef.remote_capture.model.VPNStats;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class CaptureService extends VpnService implements Runnable {
|
||||
@ -64,7 +67,10 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
private static CaptureService INSTANCE;
|
||||
private String app_filter;
|
||||
private HTTPServer mHttpServer;
|
||||
private OutputStream mOutputStream;
|
||||
private ConnectionsRegister conn_reg;
|
||||
private Uri mPcapUri;
|
||||
private boolean mFirstStreamWrite;
|
||||
|
||||
/* The maximum connections to log into the ConnectionsRegister. Older connections are dropped.
|
||||
* Max Estimated max memory usage: less than 2 MB. */
|
||||
@ -140,6 +146,11 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
|
||||
conn_reg = new ConnectionsRegister(CONNECTIONS_LOG_SIZE);
|
||||
|
||||
if(dump_mode != Prefs.DumpMode.HTTP_SERVER)
|
||||
mHttpServer = null;
|
||||
mOutputStream = null;
|
||||
mPcapUri = null;
|
||||
|
||||
if(dump_mode == Prefs.DumpMode.HTTP_SERVER) {
|
||||
if (mHttpServer == null)
|
||||
mHttpServer = new HTTPServer(app_ctx, http_server_port);
|
||||
@ -150,8 +161,25 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
Log.e(CaptureService.TAG, "Could not start the HTTP server");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else
|
||||
mHttpServer = null;
|
||||
} else if(dump_mode == Prefs.DumpMode.PCAP_FILE) {
|
||||
String path = settings.getString(Prefs.PREF_PCAP_URI);
|
||||
|
||||
if(path != null) {
|
||||
mPcapUri = Uri.parse(path);
|
||||
|
||||
try {
|
||||
mOutputStream = getContentResolver().openOutputStream(mPcapUri);
|
||||
mFirstStreamWrite = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(mOutputStream == null) {
|
||||
Utils.showToast(this, R.string.cannot_write_pcap_file);
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, "Using DNS server " + public_dns);
|
||||
|
||||
@ -244,6 +272,16 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
if(mHttpServer != null)
|
||||
mHttpServer.endConnections();
|
||||
// NOTE: do not destroy the mHttpServer, let it terminate the active connections
|
||||
|
||||
if(mOutputStream != null) {
|
||||
try {
|
||||
mOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
mPcapUri = null;
|
||||
}
|
||||
|
||||
/* Check if the VPN service was launched */
|
||||
@ -256,6 +294,10 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
return((INSTANCE != null) ? INSTANCE.app_filter : null);
|
||||
}
|
||||
|
||||
public static Uri getPcapUri() {
|
||||
return ((INSTANCE != null) ? INSTANCE.mPcapUri : null);
|
||||
}
|
||||
|
||||
public static long getBytes() {
|
||||
return((INSTANCE != null) ? INSTANCE.last_bytes : 0);
|
||||
}
|
||||
@ -334,7 +376,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
|
||||
// returns 1 if dumpPcapData should be called
|
||||
public int dumpPcapToJava() {
|
||||
return((mHttpServer != null) ? 1 : 0);
|
||||
return(((dump_mode == Prefs.DumpMode.HTTP_SERVER) || (dump_mode == Prefs.DumpMode.PCAP_FILE)) ? 1 : 0);
|
||||
}
|
||||
|
||||
public int dumpPcapToUdp() {
|
||||
@ -410,6 +452,20 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
public void dumpPcapData(byte[] data) {
|
||||
if(mHttpServer != null)
|
||||
mHttpServer.pushData(data);
|
||||
else if(mOutputStream != null) {
|
||||
try {
|
||||
if(mFirstStreamWrite) {
|
||||
mOutputStream.write(Utils.hexStringToByteArray(Utils.PCAP_HEADER));
|
||||
mFirstStreamWrite = false;
|
||||
}
|
||||
|
||||
mOutputStream.write(data);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
reportError(e.getLocalizedMessage());
|
||||
stopPacketLoop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reportError(String msg) {
|
||||
|
||||
@ -30,7 +30,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
single bytes[] in order to avoid excessive data copies.
|
||||
*/
|
||||
class ChunkedInputStream extends InputStream {
|
||||
private static final byte[] pcapHeader = Utils.hexStringToByteArray("d4c3b2a1020004000000000000000000ffff000065000000");
|
||||
private static final byte[] pcapHeader = Utils.hexStringToByteArray(Utils.PCAP_HEADER);
|
||||
final Lock mLock = new ReentrantLock();
|
||||
final Condition newData = mLock.newCondition();
|
||||
ArrayList<byte[]> mChunks = new ArrayList<byte[]>();
|
||||
|
||||
@ -20,20 +20,15 @@
|
||||
package com.emanuelef.remote_capture;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import fi.iki.elonen.NanoHTTPD.Response.Status;
|
||||
|
||||
public class HTTPServer extends NanoHTTPD {
|
||||
private static final String PCAP_MIME = "application/vnd.tcpdump.pcap";
|
||||
private final DateFormat mFmt = new SimpleDateFormat("HH_mm_ss");
|
||||
private boolean firstStart = true;
|
||||
private boolean mAcceptConnections = false;
|
||||
private final Context mContext;
|
||||
@ -47,7 +42,7 @@ public class HTTPServer extends NanoHTTPD {
|
||||
}
|
||||
|
||||
private Response redirectToPcap() {
|
||||
String fname = "PCAPdroid_" + mFmt.format(new Date()) + ".pcap";
|
||||
String fname = Utils.getUniquePcapFileName(mContext);
|
||||
Response r = newFixedLengthResponse(Status.TEMPORARY_REDIRECT, MIME_HTML, "");
|
||||
r.addHeader("Location", "/" + fname);
|
||||
return(r);
|
||||
|
||||
@ -46,12 +46,17 @@ import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Utils {
|
||||
public static final String PCAP_HEADER = "d4c3b2a1020004000000000000000000ffff000065000000";
|
||||
|
||||
public static String formatBytes(long bytes) {
|
||||
long divisor;
|
||||
String suffix;
|
||||
@ -269,4 +274,10 @@ public class Utils {
|
||||
|
||||
alert.show();
|
||||
}
|
||||
|
||||
public static String getUniquePcapFileName(Context context) {
|
||||
Locale locale = context.getResources().getConfiguration().locale;
|
||||
final DateFormat fmt = new SimpleDateFormat("dd_MMM_HH_mm_ss", locale);
|
||||
return "PCAPdroid_" + fmt.format(new Date()) + ".pcap";
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.net.VpnService;
|
||||
@ -41,6 +42,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -59,6 +62,7 @@ import com.emanuelef.remote_capture.R;
|
||||
import com.emanuelef.remote_capture.Utils;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -68,22 +72,25 @@ import java.util.Objects;
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements AppsLoadListener, NavigationView.OnNavigationItemSelectedListener {
|
||||
SharedPreferences mPrefs;
|
||||
Menu mMenu;
|
||||
MenuItem mMenuItemStartBtn;
|
||||
MenuItem mMenuItemAppSel;
|
||||
MenuItem mMenuSettings;
|
||||
Drawable mFilterIcon;
|
||||
String mFilterApp;
|
||||
boolean mOpenAppsWhenDone;
|
||||
List<AppDescriptor> mInstalledApps;
|
||||
AppState mState;
|
||||
AppStateListener mListener;
|
||||
AppDescriptor mNoFilterApp;
|
||||
private SharedPreferences mPrefs;
|
||||
private Menu mMenu;
|
||||
private MenuItem mMenuItemStartBtn;
|
||||
private MenuItem mMenuItemAppSel;
|
||||
private MenuItem mMenuSettings;
|
||||
private Drawable mFilterIcon;
|
||||
private String mFilterApp;
|
||||
private boolean mOpenAppsWhenDone;
|
||||
private List<AppDescriptor> mInstalledApps;
|
||||
private AppState mState;
|
||||
private AppStateListener mListener;
|
||||
private AppDescriptor mNoFilterApp;
|
||||
private Uri mPcapUri;
|
||||
private BroadcastReceiver mReceiver;
|
||||
|
||||
private static final String TAG = "Main";
|
||||
|
||||
private static final int REQUEST_CODE_VPN = 2;
|
||||
private static final int REQUEST_CODE_PCAP_FILE = 3;
|
||||
|
||||
public static final String TELEGRAM_GROUP_NAME = "PCAPdroid";
|
||||
public static final String GITHUB_PROJECT_URL = "https://github.com/emanuele-f/PCAPdroid";
|
||||
@ -97,6 +104,7 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
mNoFilterApp = new AppDescriptor("", icon, this.getResources().getString(R.string.no_filter), -1, false, true);
|
||||
|
||||
mFilterApp = CaptureService.getAppFilter();
|
||||
mPcapUri = CaptureService.getPcapUri();
|
||||
|
||||
if((mFilterApp == null) && (savedInstanceState != null)) {
|
||||
// Possibly get the temporary filter
|
||||
@ -117,10 +125,8 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
.setAppsLoadListener(this)
|
||||
.loadAllApps();
|
||||
|
||||
LocalBroadcastManager bcast_man = LocalBroadcastManager.getInstance(this);
|
||||
|
||||
/* Register for service status */
|
||||
bcast_man.registerReceiver(new BroadcastReceiver() {
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String status = intent.getStringExtra(CaptureService.SERVICE_STATUS_KEY);
|
||||
@ -133,11 +139,26 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
if (CaptureService.isServiceActive())
|
||||
CaptureService.stopService();
|
||||
|
||||
if((mPcapUri != null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE)) {
|
||||
showPcapActionDialog(mPcapUri);
|
||||
mPcapUri = null;
|
||||
}
|
||||
|
||||
appStateReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS));
|
||||
};
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if(mReceiver != null)
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -383,6 +404,9 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
Intent intent = new Intent(MainActivity.this, CaptureService.class);
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
if((mPcapUri != null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE))
|
||||
bundle.putString(Prefs.PREF_PCAP_URI, mPcapUri.toString());
|
||||
|
||||
bundle.putString(Prefs.PREF_APP_FILTER, mFilterApp);
|
||||
intent.putExtra("settings", bundle);
|
||||
|
||||
@ -393,6 +417,14 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
Log.w(TAG, "VPN request failed");
|
||||
appStateReady();
|
||||
}
|
||||
} else if(requestCode == REQUEST_CODE_PCAP_FILE) {
|
||||
if(resultCode == RESULT_OK) {
|
||||
mPcapUri = data.getData();
|
||||
Log.d(TAG, "PCAP to write: " + mPcapUri.toString());
|
||||
|
||||
toggleService();
|
||||
} else
|
||||
mPcapUri = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,6 +453,11 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
appStateStopping();
|
||||
CaptureService.stopService();
|
||||
} else {
|
||||
if((mPcapUri == null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE)) {
|
||||
openFileSelector();
|
||||
return;
|
||||
}
|
||||
|
||||
if(Utils.hasVPNRunning(this)) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(R.string.existing_vpn_confirm)
|
||||
@ -432,6 +469,77 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener,
|
||||
}
|
||||
}
|
||||
|
||||
public void openFileSelector() {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("application/cap");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, Utils.getUniquePcapFileName(this));
|
||||
|
||||
startActivityForResult(intent, REQUEST_CODE_PCAP_FILE);
|
||||
}
|
||||
|
||||
public void showPcapActionDialog(Uri pcapUri) {
|
||||
Cursor cursor;
|
||||
|
||||
try {
|
||||
cursor = getContentResolver().query(pcapUri, null, null, null, null);
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if((cursor == null) || !cursor.moveToFirst())
|
||||
return;
|
||||
|
||||
// If file is empty, delete it
|
||||
long file_size = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
|
||||
String fname = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
cursor.close();
|
||||
|
||||
if(file_size == 0) {
|
||||
Log.d(TAG, "PCAP file is empty, deleting");
|
||||
|
||||
try {
|
||||
DocumentsContract.deleteDocument(getContentResolver(), pcapUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String message = String.format(getResources().getString(R.string.pcap_file_action), fname, Utils.formatBytes(file_size));
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
|
||||
builder.setMessage(message);
|
||||
|
||||
builder.setPositiveButton(R.string.share, (dialog, which) -> {
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.setType("application/cap");
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, pcapUri);
|
||||
startActivity(Intent.createChooser(sendIntent, getResources().getString(R.string.share)));
|
||||
});
|
||||
builder.setNegativeButton(R.string.delete, (dialog, which) -> {
|
||||
Log.d(TAG, "Deleting PCAP file" + pcapUri.getPath());
|
||||
boolean deleted = false;
|
||||
|
||||
try {
|
||||
deleted = DocumentsContract.deleteDocument(getContentResolver(), pcapUri);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if(!deleted)
|
||||
Utils.showToast(MainActivity.this, R.string.delete_error);
|
||||
|
||||
dialog.cancel();
|
||||
});
|
||||
builder.setNeutralButton(R.string.ok, (dialog, which) -> {
|
||||
dialog.cancel();
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
public AppState getState() {
|
||||
return(mState);
|
||||
}
|
||||
|
||||
@ -146,6 +146,9 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
case HTTP_SERVER:
|
||||
summary_id = R.string.http_server_info;
|
||||
break;
|
||||
case PCAP_FILE:
|
||||
summary_id = R.string.pcap_file_info;
|
||||
break;
|
||||
case UDP_EXPORTER:
|
||||
summary_id = R.string.udp_exporter_info;
|
||||
break;
|
||||
|
||||
@ -37,6 +37,7 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
@ -51,8 +52,6 @@ import com.emanuelef.remote_capture.activities.MainActivity;
|
||||
import com.emanuelef.remote_capture.activities.StatsActivity;
|
||||
import com.emanuelef.remote_capture.interfaces.AppStateListener;
|
||||
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
public class StatusFragment extends Fragment implements AppStateListener {
|
||||
private TextView mCollectorInfo;
|
||||
private TextView mCaptureStatus;
|
||||
@ -120,10 +119,10 @@ public class StatusFragment extends Fragment implements AppStateListener {
|
||||
}
|
||||
|
||||
private void setupInspectorLinK() {
|
||||
int color = getResources().getColor(android.R.color.tab_indicator_text);
|
||||
int color = ContextCompat.getColor(mActivity, android.R.color.tab_indicator_text);
|
||||
|
||||
mInspectorLink.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_search, 0, 0, 0);
|
||||
Drawable drawables[] = mInspectorLink.getCompoundDrawables();
|
||||
Drawable []drawables = mInspectorLink.getCompoundDrawables();
|
||||
drawables[0].setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
mInspectorLink.setOnClickListener(v -> {
|
||||
@ -156,6 +155,10 @@ public class StatusFragment extends Fragment implements AppStateListener {
|
||||
info = String.format(getResources().getString(R.string.http_server_status),
|
||||
Utils.getLocalIPAddress(mActivity), CaptureService.getHTTPServerPort());
|
||||
break;
|
||||
case PCAP_FILE:
|
||||
modeName = getResources().getString(R.string.pcap_file);
|
||||
info = "";
|
||||
break;
|
||||
case UDP_EXPORTER:
|
||||
modeName = getResources().getString(R.string.udp_exporter);
|
||||
info = String.format(getResources().getString(R.string.collector_info),
|
||||
|
||||
@ -24,6 +24,7 @@ import android.content.SharedPreferences;
|
||||
public class Prefs {
|
||||
public static final String DUMP_HTTP_SERVER = "http_server";
|
||||
public static final String DUMP_UDP_EXPORTER = "udp_exporter";
|
||||
public static final String DUMP_PCAP_FILE = "pcap_file";
|
||||
public static final String PREF_COLLECTOR_IP_KEY = "collector_ip_address";
|
||||
public static final String PREF_COLLECTOR_PORT_KEY = "collector_port";
|
||||
public static final String PREF_TLS_PROXY_IP_KEY = "tls_proxy_ip_address";
|
||||
@ -32,16 +33,20 @@ public class Prefs {
|
||||
public static final String PREF_APP_FILTER = "app_filter";
|
||||
public static final String PREF_HTTP_SERVER_PORT = "http_server_port";
|
||||
public static final String PREF_PCAP_DUMP_MODE = "pcap_dump_mode";
|
||||
public static final String PREF_PCAP_URI = "pcap_path";
|
||||
|
||||
public enum DumpMode {
|
||||
NONE,
|
||||
HTTP_SERVER,
|
||||
PCAP_FILE,
|
||||
UDP_EXPORTER
|
||||
}
|
||||
|
||||
public static DumpMode getDumpMode(String pref) {
|
||||
if(pref.equals(DUMP_HTTP_SERVER))
|
||||
return(DumpMode.HTTP_SERVER);
|
||||
else if(pref.equals(DUMP_PCAP_FILE))
|
||||
return(DumpMode.PCAP_FILE);
|
||||
else if(pref.equals(DUMP_UDP_EXPORTER))
|
||||
return(DumpMode.UDP_EXPORTER);
|
||||
else
|
||||
|
||||
@ -371,7 +371,7 @@ static void process_ndpi_packet(conn_data_t *data, vpnproxy_data_t *proxy, const
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static void javaPcapDump(zdtun_t *tun, vpnproxy_data_t *proxy) {
|
||||
static void javaPcapDump(vpnproxy_data_t *proxy) {
|
||||
JNIEnv *env = proxy->env;
|
||||
|
||||
log_android(ANDROID_LOG_DEBUG, "Exporting a %d B PCAP buffer", proxy->java_dump.buffer_idx);
|
||||
@ -470,7 +470,7 @@ static void account_packet(zdtun_t *tun, const char *packet, int size, uint8_t f
|
||||
|
||||
if((JAVA_PCAP_BUFFER_SIZE - proxy->java_dump.buffer_idx) <= tot_size) {
|
||||
// Flush the buffer
|
||||
javaPcapDump(tun, proxy);
|
||||
javaPcapDump(proxy);
|
||||
}
|
||||
|
||||
if((JAVA_PCAP_BUFFER_SIZE - proxy->java_dump.buffer_idx) <= tot_size)
|
||||
@ -1108,7 +1108,7 @@ housekeeping:
|
||||
last_connections_dump = now_ms;
|
||||
} else if((proxy.java_dump.buffer_idx > 0)
|
||||
&& (now_ms - proxy.java_dump.last_dump_ms) >= MAX_JAVA_DUMP_DELAY_MS) {
|
||||
javaPcapDump(tun, &proxy);
|
||||
javaPcapDump(&proxy);
|
||||
} else if((now_ms >= next_purge_ms) || dump_vpn_stats_now) {
|
||||
dump_vpn_stats_now = false;
|
||||
zdtun_statistics_t stats;
|
||||
@ -1135,6 +1135,9 @@ housekeeping:
|
||||
}
|
||||
|
||||
if(proxy.java_dump.buffer) {
|
||||
if(proxy.java_dump.buffer_idx > 0)
|
||||
javaPcapDump(&proxy);
|
||||
|
||||
free(proxy.java_dump.buffer);
|
||||
proxy.java_dump.buffer = NULL;
|
||||
}
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
<string-array name="pcap_dump_modes">
|
||||
<item>none</item>
|
||||
<item>http_server</item>
|
||||
<item>pcap_file</item>
|
||||
<item>udp_exporter</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pcap_dump_modes_labels">
|
||||
<item>@string/no_dump</item>
|
||||
<item>@string/http_server</item>
|
||||
<item>@string/pcap_file</item>
|
||||
<item>@string/udp_exporter</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@ -89,5 +89,13 @@
|
||||
<string name="navigation_drawer_open">Drawer Open</string>
|
||||
<string name="navigation_drawer_close">Drawer Close</string>
|
||||
<string name="inspector">Inspector</string>
|
||||
<string name="pcap_file">PCAP File</string>
|
||||
<string name="pcap_file_info">Create a PCAP file into the device storage</string>
|
||||
<string name="cannot_write_pcap_file">Cannot write PCAP file</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="pcap_file_action">Traffic saved to file %1$s (%2$s).</string>
|
||||
<string name="delete_error">Could not delete file</string>
|
||||
</resources>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user