From ddec1a85eb674534bfbe01cb244a998c0b4c89ea Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Mon, 25 Dec 2023 17:06:58 +0100 Subject: [PATCH] Only block QUIC for connections to decrypt Since PCAPdroid can now be run with decryption enabled all the time, blocking QUIC is now limited to the connections matching the decryption whitelist. This also hides the block QUIC option when TLS decryption is disabled. Closes #369 --- .../activities/prefs/SettingsActivity.java | 10 +++---- .../fragments/EditListFragment.java | 2 +- app/src/main/jni/core/capture_vpn.c | 26 +++++++++++++------ docs/app_api.md | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/prefs/SettingsActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/prefs/SettingsActivity.java index edaa90fe..223befad 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/prefs/SettingsActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/prefs/SettingsActivity.java @@ -167,8 +167,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment setupSecurityPrefs(); setupOtherPrefs(); - socks5ProxyHideShow(mTlsDecryption.isChecked(), rootCaptureEnabled()); - mBlockQuic.setVisible(!rootCaptureEnabled()); + socks5ProxyAndQuicHideShow(mTlsDecryption.isChecked(), rootCaptureEnabled()); rootCaptureHideShow(rootCaptureEnabled()); Intent intent = requireActivity().getIntent(); @@ -310,7 +309,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment mMitmWizard.setVisible((boolean) newValue); mMitmproxyOpts.setVisible((boolean) newValue); - socks5ProxyHideShow((boolean) newValue, rootCaptureEnabled()); + socks5ProxyAndQuicHideShow((boolean) newValue, rootCaptureEnabled()); return true; }); @@ -344,8 +343,9 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment mSocks5Settings = requirePreference("socks5_settings"); } - private void socks5ProxyHideShow(boolean tlsDecryption, boolean rootEnabled) { + private void socks5ProxyAndQuicHideShow(boolean tlsDecryption, boolean rootEnabled) { mSocks5Settings.setVisible(!tlsDecryption && !rootEnabled); + mBlockQuic.setVisible(tlsDecryption && !rootEnabled); } private void setupOtherPrefs() { @@ -406,7 +406,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment } else { mAutoBlockPrivateDNS.setVisible(true); mBlockQuic.setVisible(true); - socks5ProxyHideShow(mTlsDecryption.isChecked(), false); + socks5ProxyAndQuicHideShow(mTlsDecryption.isChecked(), false); } mIpMode.setVisible(!enabled); diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java index e41f3f1f..8e887dd8 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java @@ -77,7 +77,7 @@ public class EditListFragment extends Fragment implements MatchList.ListChangeLi private boolean mIsOwnUpdate; private ActionMode mActionMode; private AppSelectDialog mAppSelDialog; - private int MAX_RULES_BEFORE_WARNING = 5000; + private static final int MAX_RULES_BEFORE_WARNING = 5000; private static final String TAG = "EditListFragment"; private static final String LIST_TYPE_ARG = "list_type"; diff --git a/app/src/main/jni/core/capture_vpn.c b/app/src/main/jni/core/capture_vpn.c index 2f62d869..1c19f487 100644 --- a/app/src/main/jni/core/capture_vpn.c +++ b/app/src/main/jni/core/capture_vpn.c @@ -348,22 +348,31 @@ static void update_conn_status(zdtun_t *zdt, const zdtun_pkt_t *pkt, uint8_t fro /* ******************************************************* */ +static bool matches_decryption_whitelist(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data) { + zdtun_ip_t dst_ip = tuple->dst_ip; + + if(!pd->tls_decryption.list) + return false; + + // NOTE: domain matching only works if a prior DNS reply is seen (see ip_lru_find in pd_new_connection) + return blacklist_match_ip(pd->tls_decryption.list, &dst_ip, tuple->ipver) || + blacklist_match_uid(pd->tls_decryption.list, data->uid) || + (data->info && blacklist_match_domain(pd->tls_decryption.list, data->info)); +} + +/* ******************************************************* */ + static bool should_proxify(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data) { // NOTE: connections must be proxified as soon as the first packet arrives. // In case of TLS decryption, since we cannot reliably determine TLS connections with 1 packet, - // we must proxy all the TCP connections. + // we must proxify all the TCP connections. if(!pd->socks5.enabled || (tuple->ipproto != IPPROTO_TCP)) { data->decryption_ignored = true; return false; } if(pd->tls_decryption.list) { - zdtun_ip_t dst_ip = tuple->dst_ip; - - // NOTE: domain matching only works if a prior DNS reply is seen (see ip_lru_find in pd_new_connection) - if(blacklist_match_ip(pd->tls_decryption.list, &dst_ip, tuple->ipver) || - blacklist_match_uid(pd->tls_decryption.list, data->uid) || - (data->info && blacklist_match_domain(pd->tls_decryption.list, data->info))) + if(matches_decryption_whitelist(pd, tuple, data)) return true; data->decryption_ignored = true; @@ -376,7 +385,8 @@ static bool should_proxify(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn /* ******************************************************* */ void vpn_process_ndpi(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data) { - if(pd->vpn.block_quic && (data->l7proto == NDPI_PROTOCOL_QUIC)) { + if(pd->vpn.block_quic && (data->l7proto == NDPI_PROTOCOL_QUIC) && + pd->tls_decryption.enabled && matches_decryption_whitelist(pd, tuple, data)) { data->blacklisted_internal = true; data->to_block = true; } diff --git a/docs/app_api.md b/docs/app_api.md index 8912f126..862edd3b 100644 --- a/docs/app_api.md +++ b/docs/app_api.md @@ -94,7 +94,7 @@ As shown above, the capture settings can be specified by using intent extras. Th | max_pkts_per_flow | int | 43 | | only dump the first max_pkts_per_flow packets per flow | | max_dump_size | int | 43 | | max size in bytes for the PCAP dump | | tls_decryption | bool | 49 | vpn | true to enable the built-in TLS decryption | -| block_quic | bool | 51 | vpn | true to block QUIC traffic | +| block_quic | bool | 51 | vpn | true to block QUIC traffic (73+: matching the decryption whitelist)| | 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 |