Skip to content

Commit

Permalink
Only block QUIC for connections to decrypt
Browse files Browse the repository at this point in the history
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
  • Loading branch information
emanuele-f committed Dec 25, 2023
1 parent d5661be commit ddec1a8
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setupSecurityPrefs();
setupOtherPrefs();

socks5ProxyHideShow(mTlsDecryption.isChecked(), rootCaptureEnabled());
mBlockQuic.setVisible(!rootCaptureEnabled());
socks5ProxyAndQuicHideShow(mTlsDecryption.isChecked(), rootCaptureEnabled());
rootCaptureHideShow(rootCaptureEnabled());

Intent intent = requireActivity().getIntent();
Expand Down Expand Up @@ -310,7 +309,7 @@ private void setupTrafficInspectionPrefs() {

mMitmWizard.setVisible((boolean) newValue);
mMitmproxyOpts.setVisible((boolean) newValue);
socks5ProxyHideShow((boolean) newValue, rootCaptureEnabled());
socks5ProxyAndQuicHideShow((boolean) newValue, rootCaptureEnabled());
return true;
});

Expand Down Expand Up @@ -344,8 +343,9 @@ private void setupTrafficInspectionPrefs() {
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() {
Expand Down Expand Up @@ -406,7 +406,7 @@ private void rootCaptureHideShow(boolean enabled) {
} else {
mAutoBlockPrivateDNS.setVisible(true);
mBlockQuic.setVisible(true);
socks5ProxyHideShow(mTlsDecryption.isChecked(), false);
socks5ProxyAndQuicHideShow(mTlsDecryption.isChecked(), false);
}

mIpMode.setVisible(!enabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
26 changes: 18 additions & 8 deletions app/src/main/jni/core/capture_vpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion docs/app_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down

0 comments on commit ddec1a8

Please sign in to comment.