Ability to provide custom mitmproxy options

A new preference has been added to provide additional mitmproxy options

Closes #283
This commit is contained in:
emanuele-f
2022-11-24 20:02:37 +01:00
parent 77560bdebd
commit 60460880af
11 changed files with 59 additions and 17 deletions
@@ -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
}
}
+3
View File
@@ -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"
+1
View File
@@ -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.