mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-05-08 21:12:26 +00:00
Ability to provide custom mitmproxy options
A new preference has been added to provide additional mitmproxy options Closes #283
This commit is contained in:
@@ -347,7 +347,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
mSocks5Port = MitmReceiver.TLS_DECRYPTION_PROXY_PORT;
|
||||
mSocks5Auth = Utils.genRandomString(8) + ":" + Utils.genRandomString(8);
|
||||
|
||||
mMitmReceiver = new MitmReceiver(this, mSettings.root_capture, mSocks5Auth);
|
||||
mMitmReceiver = new MitmReceiver(this, mSettings.root_capture, mSocks5Auth, mSettings.mitmproxy_opts);
|
||||
try {
|
||||
if(!mMitmReceiver.start())
|
||||
return abortStart();
|
||||
@@ -841,8 +841,11 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
(INSTANCE.mCaptureThread != null));
|
||||
}
|
||||
|
||||
public static boolean isMitmProxyRunning() {
|
||||
return((INSTANCE != null) && (INSTANCE.mMitmReceiver != null) && INSTANCE.mMitmReceiver.isProxyRunning());
|
||||
public static MitmReceiver.Status getMitmProxyStatus() {
|
||||
if((INSTANCE == null) || (INSTANCE.mMitmReceiver == null))
|
||||
return MitmReceiver.Status.NOT_STARTED;
|
||||
|
||||
return INSTANCE.mMitmReceiver.getProxyStatus();
|
||||
}
|
||||
|
||||
public static boolean isLowMemory() {
|
||||
|
||||
@@ -48,8 +48,8 @@ import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MitmAddon {
|
||||
public static final long PACKAGE_VERSION_CODE = 10;
|
||||
public static final String PACKAGE_VERSION_NAME = "v0.10";
|
||||
public static final long PACKAGE_VERSION_CODE = 11;
|
||||
public static final String PACKAGE_VERSION_NAME = "v0.11";
|
||||
public static final String REPOSITORY = "https://github.com/emanuele-f/PCAPdroid-mitm";
|
||||
private static final String TAG = "MitmAddon";
|
||||
private final Context mContext;
|
||||
|
||||
@@ -70,7 +70,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
private final Context mContext;
|
||||
private final MitmAddon mAddon;
|
||||
private final MitmAPI.MitmConfig mConfig;
|
||||
private static final MutableLiveData<Boolean> proxyRunning = new MutableLiveData<>();
|
||||
private static final MutableLiveData<Status> proxyStatus = new MutableLiveData<>(Status.NOT_STARTED);
|
||||
private ParcelFileDescriptor mSocketFd;
|
||||
private BufferedOutputStream mKeylog;
|
||||
|
||||
@@ -110,7 +110,14 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
}
|
||||
}
|
||||
|
||||
public MitmReceiver(Context ctx, boolean rootCapture, String proxyAuth) {
|
||||
public enum Status {
|
||||
NOT_STARTED,
|
||||
STARTING,
|
||||
START_ERROR,
|
||||
RUNNING
|
||||
}
|
||||
|
||||
public MitmReceiver(Context ctx, boolean rootCapture, String proxyAuth, String additionalOpts) {
|
||||
mContext = ctx;
|
||||
mReg = CaptureService.requireConnsRegister();
|
||||
mAddon = new MitmAddon(mContext, this);
|
||||
@@ -119,6 +126,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
mConfig.proxyPort = TLS_DECRYPTION_PROXY_PORT;
|
||||
mConfig.proxyAuth = proxyAuth;
|
||||
mConfig.dumpMasterSecrets = (CaptureService.getDumpMode() != Prefs.DumpMode.NONE);
|
||||
mConfig.additionalOptions = additionalOpts;
|
||||
|
||||
/* upstream certificate verification is disabled because the app does not provide a way to let the user
|
||||
accept a given cert. Moreover, it provides a workaround for a bug with HTTPS proxies described in
|
||||
@@ -138,7 +146,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
|
||||
public boolean start() throws IOException {
|
||||
Log.d(TAG, "starting");
|
||||
proxyRunning.postValue(false);
|
||||
proxyStatus.postValue(Status.STARTING);
|
||||
|
||||
if(!mAddon.connect(Context.BIND_IMPORTANT)) {
|
||||
Utils.showToastLong(mContext, R.string.mitm_start_failed);
|
||||
@@ -180,7 +188,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
public void run() {
|
||||
if(mSocketFd == null) {
|
||||
Log.e(TAG, "Null socket, abort");
|
||||
proxyRunning.postValue(false);
|
||||
proxyStatus.postValue(Status.NOT_STARTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,7 +247,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
handleLog(msg);
|
||||
} else if(type == MsgType.RUNNING) {
|
||||
Log.i(TAG, "MITM proxy is running");
|
||||
proxyRunning.postValue(true);
|
||||
proxyStatus.postValue(Status.RUNNING);
|
||||
} else {
|
||||
ConnectionDescriptor conn = getConnByLocalPort(port);
|
||||
//Log.d(TAG, "MSG." + type.name() + "[" + msg_len + " B]: port=" + port + ", match=" + (conn != null));
|
||||
@@ -259,7 +267,11 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
mKeylog = null;
|
||||
}
|
||||
|
||||
proxyRunning.postValue(false);
|
||||
if(proxyStatus.getValue() == Status.STARTING)
|
||||
proxyStatus.postValue(Status.START_ERROR);
|
||||
else
|
||||
proxyStatus.postValue(Status.NOT_STARTED);
|
||||
|
||||
Log.i(TAG, "End receiving data");
|
||||
}
|
||||
|
||||
@@ -380,12 +392,12 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
public boolean isProxyRunning() {
|
||||
return Boolean.TRUE.equals(proxyRunning.getValue());
|
||||
public Status getProxyStatus() {
|
||||
return proxyStatus.getValue();
|
||||
}
|
||||
|
||||
public static void observeRunning(LifecycleOwner lifecycleOwner, Observer<Boolean> observer) {
|
||||
proxyRunning.observe(lifecycleOwner, observer);
|
||||
public static void observeStatus(LifecycleOwner lifecycleOwner, Observer<Status> observer) {
|
||||
proxyStatus.observe(lifecycleOwner, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -131,6 +131,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
private SwitchPreference mAutoBlockPrivateDNS;
|
||||
private EditTextPreference mSocks5ProxyIp;
|
||||
private EditTextPreference mSocks5ProxyPort;
|
||||
private EditTextPreference mMitmproxyOpts;
|
||||
private DropDownPreference mIpMode;
|
||||
private DropDownPreference mCapInterface;
|
||||
private Preference mVpnExceptions;
|
||||
@@ -302,12 +303,15 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
fullPayloadHideShow((boolean) newValue);
|
||||
mBlockQuic.setVisible(((boolean) newValue) && !rootCaptureEnabled());
|
||||
mMitmWizard.setVisible((boolean) newValue);
|
||||
mMitmproxyOpts.setVisible((boolean) newValue);
|
||||
socks5ProxyHideShow((boolean) newValue, mSocks5Enabled.isChecked(), rootCaptureEnabled());
|
||||
return true;
|
||||
});
|
||||
|
||||
mFullPayloadEnabled = requirePreference(Prefs.PREF_FULL_PAYLOAD);
|
||||
mBlockQuic = requirePreference(Prefs.PREF_BLOCK_QUIC);
|
||||
mMitmproxyOpts = requirePreference(Prefs.PREF_MITMPROXY_OPTS);
|
||||
mMitmproxyOpts.setVisible(mTlsDecryption.isChecked());
|
||||
mMitmWizard = requirePreference("mitm_setup_wizard");
|
||||
mMitmWizard.setVisible(mTlsDecryption.isChecked());
|
||||
mMitmWizard.setOnPreferenceClickListener(preference -> {
|
||||
|
||||
@@ -170,7 +170,7 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr
|
||||
});
|
||||
|
||||
// Register for updates
|
||||
MitmReceiver.observeRunning(this, running -> refreshDecryptionStatus());
|
||||
MitmReceiver.observeStatus(this, status -> refreshDecryptionStatus());
|
||||
CaptureService.observeStats(this, this::onStatsUpdate);
|
||||
|
||||
// Make URLs clickable
|
||||
@@ -203,7 +203,13 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr
|
||||
}
|
||||
|
||||
private void refreshDecryptionStatus() {
|
||||
mInterfaceInfo.setText(CaptureService.isMitmProxyRunning() ? R.string.tls_decryption_running : R.string.tls_decryption_starting);
|
||||
MitmReceiver.Status proxy_status = CaptureService.getMitmProxyStatus();
|
||||
Context ctx = getContext();
|
||||
|
||||
if((proxy_status == MitmReceiver.Status.START_ERROR) && (ctx != null))
|
||||
Utils.showToastLong(ctx, R.string.mitm_addon_error);
|
||||
|
||||
mInterfaceInfo.setText((proxy_status == MitmReceiver.Status.RUNNING) ? R.string.tls_decryption_running : R.string.tls_decryption_starting);
|
||||
}
|
||||
|
||||
private void refreshFilterInfo() {
|
||||
|
||||
@@ -27,6 +27,7 @@ public class CaptureSettings implements Serializable {
|
||||
public int snaplen = 0;
|
||||
public int max_pkts_per_flow = 0;
|
||||
public int max_dump_size = 0;
|
||||
public String mitmproxy_opts;
|
||||
|
||||
public CaptureSettings(SharedPreferences prefs) {
|
||||
dump_mode = Prefs.getDumpMode(prefs);
|
||||
@@ -46,6 +47,7 @@ public class CaptureSettings implements Serializable {
|
||||
full_payload = Prefs.getFullPayloadMode(prefs);
|
||||
block_quic = Prefs.blockQuic(prefs);
|
||||
auto_block_private_dns = Prefs.isPrivateDnsBlockingEnabled(prefs);
|
||||
mitmproxy_opts = Prefs.getMitmproxyOpts(prefs);
|
||||
}
|
||||
|
||||
public CaptureSettings(Intent intent) {
|
||||
@@ -69,6 +71,7 @@ public class CaptureSettings implements Serializable {
|
||||
full_payload = false;
|
||||
block_quic = getBool(intent, Prefs.PREF_BLOCK_QUIC, false);
|
||||
auto_block_private_dns = getBool(intent, Prefs.PREF_AUTO_BLOCK_PRIVATE_DNS, true);
|
||||
mitmproxy_opts = getString(intent, Prefs.PREF_MITMPROXY_OPTS, "");
|
||||
}
|
||||
|
||||
private static String getString(Intent intent, String key, String def_value) {
|
||||
|
||||
@@ -82,6 +82,7 @@ public class Prefs {
|
||||
public static final String PREF_BLOCK_NEW_APPS = "block_new_apps";
|
||||
public static final String PREF_PAYLOAD_NOTICE_ACK = "payload_notice";
|
||||
public static final String PREF_REMOTE_COLLECTOR_ACK = "remote_collector_notice";
|
||||
public static final String PREF_MITMPROXY_OPTS = "mitmproxy_opts";
|
||||
|
||||
public enum DumpMode {
|
||||
NONE,
|
||||
@@ -171,6 +172,7 @@ public class Prefs {
|
||||
public static boolean isPrivateDnsBlockingEnabled(SharedPreferences p) { return(p.getBoolean(PREF_AUTO_BLOCK_PRIVATE_DNS, true)); }
|
||||
public static boolean lockdownVpnNoticeShown(SharedPreferences p) { return(p.getBoolean(PREF_LOCKDOWN_VPN_NOTICE_SHOWN, false)); }
|
||||
public static boolean blockNewApps(SharedPreferences p) { return(p.getBoolean(PREF_BLOCK_NEW_APPS, false)); }
|
||||
public static String getMitmproxyOpts(SharedPreferences p) { return(p.getString(PREF_MITMPROXY_OPTS, "")); }
|
||||
|
||||
|
||||
public static String asString(Context ctx) {
|
||||
|
||||
@@ -41,5 +41,6 @@ public class MitmAPI {
|
||||
public boolean sslInsecure; // true to disable upstream certificate check
|
||||
public boolean dumpMasterSecrets; // true to enable the TLS master secrets dump messages (similar to SSLKEYLOG)
|
||||
public String proxyAuth; // SOCKS5 proxy authentication, "user:pass"
|
||||
public String additionalOptions; // provide additional options to mitmproxy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,4 +415,7 @@
|
||||
<string name="firewall_purchase_msg">Buy the <i>%1$s</i> feature to start blocking connections</string>
|
||||
<string name="mitm_skip_notice">The mitm certificate does not seem to be installed. If you proceed, decryption may fail</string>
|
||||
<string name="mitm_wizard_description">Configure the device for the TLS decryption</string>
|
||||
<string name="mitmproxy_opts">Additional mitmproxy options</string>
|
||||
<string name="mitmproxy_opts_description">Provide additional options for mitmproxy</string>
|
||||
<string name="mitm_addon_error">Error while starting the mitm addon. Check the log for details</string>
|
||||
</resources>
|
||||
|
||||
@@ -72,6 +72,13 @@
|
||||
app:summary="@string/mitm_wizard_description"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="mitmproxy_opts"
|
||||
app:title="@string/mitmproxy_opts"
|
||||
app:summary="@string/mitmproxy_opts_description"
|
||||
app:iconSpaceReserved="false"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreference
|
||||
app:key="block_quic"
|
||||
app:title="@string/block_quick"
|
||||
|
||||
@@ -90,6 +90,7 @@ As shown above, the capture settings can be specified by using intent extras. Th
|
||||
| block_quic | bool | 51 | vpn | true to block QUIC traffic |
|
||||
| auto_block_private_dns | bool | 51 | vpn | true to detect and possibly block private DNS to inspect traffic |
|
||||
| ip_mode | string | 56 | vpn | which IP addresses to use for the VPN: ipv4 \| ipv6 \| both |
|
||||
| mitmproxy_opts | string | 62 | | additional options to provide to mitmproxy in decryption mode |
|
||||
|
||||
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.
|
||||
The `Mode` column indicates if the option applies to any mode or only to the VPN or root mode.
|
||||
|
||||
Reference in New Issue
Block a user