From 464516409a17111dac40befef96edab15734e61b Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Wed, 31 May 2023 23:16:55 +0200 Subject: [PATCH] Only apply TLS decryption to specified connections TLS decryption is now only applied to connections matching the user-configured rules. This allows running the decryption along with the normal capture. The decryption whitelist has been removed. --- .../remote_capture/CaptureService.java | 22 ++--- .../emanuelef/remote_capture/PCAPdroid.java | 10 +- .../activities/EditFilterActivity.java | 3 - .../activities/MainActivity.java | 6 +- .../fragments/ConnectionsFragment.java | 99 ++++++++++++------- .../fragments/StatusFragment.java | 7 +- .../model/ConnectionDescriptor.java | 18 ++-- .../remote_capture/model/ListInfo.java | 20 ++-- .../emanuelef/remote_capture/model/Prefs.java | 2 +- app/src/main/jni/core/capture_vpn.c | 25 ++--- app/src/main/jni/core/jni_impl.c | 26 ++--- app/src/main/jni/core/pcapdroid.c | 18 ++-- app/src/main/jni/core/pcapdroid.h | 6 +- .../main/res/drawable/ic_lock_open_alt.xml | 5 + .../main/res/layout/edit_filter_activity.xml | 7 -- app/src/main/res/layout/status.xml | 1 + .../main/res/menu/connection_context_menu.xml | 30 +++++- app/src/main/res/menu/nav_items.xml | 6 +- app/src/main/res/values/strings.xml | 7 ++ 19 files changed, 191 insertions(+), 127 deletions(-) create mode 100644 app/src/main/res/drawable/ic_lock_open_alt.xml diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index 4f5c3fd3..2f4ec4d0 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -147,7 +147,7 @@ public class CaptureService extends VpnService implements Runnable { private Blocklist mBlocklist; private MatchList mMalwareWhitelist; private MatchList mFirewallWhitelist; - private MatchList mDecryptionWhitelist; + private MatchList mDecryptionList; private SparseArray mIfIndexToName; private boolean mSocks5Enabled; private String mSocks5Address; @@ -383,9 +383,9 @@ public class CaptureService extends VpnService implements Runnable { } if(mSettings.tls_decryption && !mSettings.root_capture) - mDecryptionWhitelist = PCAPdroid.getInstance().getDecryptionWhitelist(); + mDecryptionList = PCAPdroid.getInstance().getDecryptionList(); else - mDecryptionWhitelist = null; + mDecryptionList = null; if ((mSettings.app_filter != null) && (!mSettings.app_filter.isEmpty())) { try { @@ -1009,8 +1009,8 @@ public class CaptureService extends VpnService implements Runnable { (INSTANCE.isTlsDecryptionEnabled() == 1)); } - public static boolean isDecryptionWhitelistEnabled() { - return(INSTANCE != null && (INSTANCE.mDecryptionWhitelist != null)); + public static boolean isDecryptionListEnabled() { + return(INSTANCE != null && (INSTANCE.mDecryptionList != null)); } public static Prefs.PayloadMode getCurPayloadMode() { @@ -1351,8 +1351,8 @@ public class CaptureService extends VpnService implements Runnable { if(cur_status == ServiceStatus.STARTED) { if(mMalwareDetectionEnabled) reloadMalwareWhitelist(); - if(mDecryptionWhitelist != null) - reloadDecryptionWhitelist(); + if(mDecryptionList != null) + reloadDecryptionList(); reloadBlocklist(); reloadFirewallWhitelist(); } @@ -1446,12 +1446,12 @@ public class CaptureService extends VpnService implements Runnable { reloadMalwareWhitelist(INSTANCE.mMalwareWhitelist.toListDescriptor()); } - public static void reloadDecryptionWhitelist() { - if((INSTANCE == null) || (INSTANCE.mDecryptionWhitelist == null)) + public static void reloadDecryptionList() { + if((INSTANCE == null) || (INSTANCE.mDecryptionList == null)) return; Log.i(TAG, "reloading TLS decryption whitelist"); - reloadDecryptionWhitelist(INSTANCE.mDecryptionWhitelist.toListDescriptor()); + reloadDecryptionList(INSTANCE.mDecryptionList.toListDescriptor()); } public static void setFirewallEnabled(boolean enabled) { @@ -1510,7 +1510,7 @@ public class CaptureService extends VpnService implements Runnable { private static native boolean reloadBlocklist(MatchList.ListDescriptor blocklist); private static native boolean reloadFirewallWhitelist(MatchList.ListDescriptor whitelist); private static native boolean reloadMalwareWhitelist(MatchList.ListDescriptor whitelist); - private static native boolean reloadDecryptionWhitelist(MatchList.ListDescriptor whitelist); + private static native boolean reloadDecryptionList(MatchList.ListDescriptor whitelist); public static native void askStatsDump(); public static native byte[] getPcapHeader(); public static native void nativeSetFirewallEnabled(boolean enabled); diff --git a/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java b/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java index d41651e8..aff633b9 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java +++ b/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java @@ -49,7 +49,7 @@ public class PCAPdroid extends Application { private MatchList mVisMask; private MatchList mMalwareWhitelist; private MatchList mFirewallWhitelist; - private MatchList mDecryptionWhitelist; + private MatchList mDecryptionList; private Blocklist mBlocklist; private Blacklists mBlacklists; private CtrlPermissions mCtrlPermissions; @@ -154,11 +154,11 @@ public class PCAPdroid extends Application { return mFirewallWhitelist; } - public MatchList getDecryptionWhitelist() { - if(mDecryptionWhitelist == null) - mDecryptionWhitelist = new MatchList(mLocalizedContext, Prefs.PREF_DECRYPTION_WHITELIST); + public MatchList getDecryptionList() { + if(mDecryptionList == null) + mDecryptionList = new MatchList(mLocalizedContext, Prefs.PREF_DECRYPTION_LIST); - return mDecryptionWhitelist; + return mDecryptionList; } public CtrlPermissions getCtrlPermissions() { diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/EditFilterActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/EditFilterActivity.java index 86b7c471..79633bb1 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/EditFilterActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/EditFilterActivity.java @@ -37,7 +37,6 @@ import androidx.preference.PreferenceManager; import com.emanuelef.remote_capture.Billing; import com.emanuelef.remote_capture.CaptureService; import com.emanuelef.remote_capture.ConnectionsRegister; -import com.emanuelef.remote_capture.PCAPdroid; import com.emanuelef.remote_capture.R; import com.emanuelef.remote_capture.Utils; import com.emanuelef.remote_capture.model.ConnectionDescriptor.Status; @@ -45,7 +44,6 @@ import com.emanuelef.remote_capture.model.ConnectionDescriptor.DecryptionStatus; import com.emanuelef.remote_capture.model.ConnectionDescriptor.FilteringStatus; import com.emanuelef.remote_capture.model.FilterDescriptor; import com.emanuelef.remote_capture.model.ListInfo; -import com.emanuelef.remote_capture.model.MatchList; import com.emanuelef.remote_capture.model.Prefs; import com.google.android.material.chip.Chip; import com.google.android.material.chip.ChipGroup; @@ -113,7 +111,6 @@ public class EditFilterActivity extends BaseActivity implements MenuProvider { mDecChips = new ArrayList<>(Arrays.asList( new Pair<>(DecryptionStatus.DECRYPTED, findViewById(R.id.dec_status_decrypted)), new Pair<>(DecryptionStatus.NOT_DECRYPTABLE, findViewById(R.id.dec_status_not_decryptable)), - new Pair<>(DecryptionStatus.WHITELISTED, findViewById(R.id.dec_status_whitelisted)), new Pair<>(DecryptionStatus.ERROR, findViewById(R.id.dec_status_error)) )); diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java index 31b3077a..b13fdb95 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java @@ -211,7 +211,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig if(mNavView != null) { Menu navMenu = mNavView.getMenu(); - navMenu.findItem(R.id.dec_whitelist).setVisible(Prefs.getTlsDecryptionEnabled(mPrefs) && !Prefs.isRootCaptureEnabled(mPrefs)); + navMenu.findItem(R.id.tls_decryption).setVisible(Prefs.getTlsDecryptionEnabled(mPrefs) && !Prefs.isRootCaptureEnabled(mPrefs)); } checkPaidDrawerEntries(); @@ -473,9 +473,9 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig } else if(id == R.id.malware_detection) { Intent intent = new Intent(MainActivity.this, MalwareDetection.class); startActivity(intent); - } else if(id == R.id.dec_whitelist) { + } else if(id == R.id.tls_decryption) { Intent intent = new Intent(MainActivity.this, EditListActivity.class); - intent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.DECRYPTION_WHITELIST); + intent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.DECRYPTION_LIST); startActivity(intent); } else if(id == R.id.firewall) { Intent intent = new Intent(MainActivity.this, FirewallActivity.class); diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java index 870ef05a..0fdbd2bb 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java @@ -78,7 +78,6 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.io.IOException; import java.io.OutputStream; -import java.util.Objects; public class ConnectionsFragment extends Fragment implements ConnectionsListener, MenuProvider, SearchView.OnQueryTextListener { private static final String TAG = "ConnectionsFragment"; @@ -305,14 +304,21 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener boolean showPurchaseFirewall = (!billing.isPurchased(Billing.FIREWALL_SKU) && billing.isAvailable(Billing.FIREWALL_SKU)) && !CaptureService.isCapturingAsRoot(); boolean blockVisible = false; boolean unblockVisible = false; + boolean decryptVisible = false; + boolean dontDecryptVisible = false; Blocklist blocklist = PCAPdroid.getInstance().getBlocklist(); MatchList fwWhitelist = PCAPdroid.getInstance().getFirewallWhitelist(); + MatchList decryptionList = PCAPdroid.getInstance().getDecryptionList(); if(app != null) { boolean appBlocked = blocklist.matchesApp(app.getUid()); blockVisible = !appBlocked; unblockVisible = appBlocked; + boolean decryptApp = decryptionList.matchesApp(app.getUid()); + decryptVisible = !decryptApp; + dontDecryptVisible = decryptApp; + item = menu.findItem(R.id.hide_app); String label = Utils.shorten(MatchList.getRuleLabel(ctx, RuleType.APP, app.getPackageName()), max_length); item.setTitle(label); @@ -330,6 +336,14 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener item.setTitle(label); item.setVisible(appBlocked); + item = menu.findItem(R.id.dec_add_app); + item.setTitle(label); + item.setVisible(!decryptApp); + + item = menu.findItem(R.id.dec_rem_app); + item.setTitle(label); + item.setVisible(decryptApp); + menu.findItem(R.id.unblock_app_10m).setTitle(getString(R.string.unblock_for_n_minutes, 10)); menu.findItem(R.id.unblock_app_1h).setTitle(getString(R.string.unblock_for_n_hours, 1)); menu.findItem(R.id.unblock_app_8h).setTitle(getString(R.string.unblock_for_n_hours, 8)); @@ -340,12 +354,6 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener item.setVisible(true); } - if(!conn.decryption_whitelisted) { - item = menu.findItem(R.id.dec_whitelist_app); - item.setTitle(label); - item.setVisible(true); - } - if(firewallVisible && whitelistMode) { boolean whitelisted = fwWhitelist.matchesApp(app.getUid()); menu.findItem(R.id.add_to_fw_whitelist).setVisible(!whitelisted); @@ -359,6 +367,10 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener blockVisible |= !hostBlocked; unblockVisible |= hostBlocked; + boolean decryptHost = decryptionList.matchesExactHost(conn.info); + decryptVisible |= !decryptHost; + dontDecryptVisible |= decryptHost; + item = menu.findItem(R.id.hide_host); item.setTitle(label); item.setVisible(true); @@ -379,6 +391,14 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener item.setTitle(label); item.setVisible(true); + item = menu.findItem(R.id.dec_add_host); + item.setTitle(label); + item.setVisible(!decryptHost); + + item = menu.findItem(R.id.dec_rem_host); + item.setTitle(label); + item.setVisible(decryptHost); + String dm_clean = Utils.cleanDomain(conn.info); String domain = Utils.getSecondLevelDomain(dm_clean); @@ -406,13 +426,7 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener item.setTitle(label); item.setVisible(true); } - - if(!conn.decryption_whitelisted) { - item = menu.findItem(R.id.dec_whitelist_host); - item.setTitle(label); - item.setVisible(true); - } - } + } // conn.info if((conn.url != null) && !(conn.url.isEmpty())) { item = menu.findItem(R.id.copy_url); @@ -435,6 +449,10 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener blockVisible |= !ipBlocked; unblockVisible |= ipBlocked; + boolean decryptIp = decryptionList.matchesIP(conn.dst_ip); + decryptVisible |= !decryptIp; + dontDecryptVisible |= decryptIp; + menu.findItem(R.id.block_ip) .setTitle(label) .setVisible(!ipBlocked); @@ -442,12 +460,16 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener .setTitle(label) .setVisible(ipBlocked); + menu.findItem(R.id.dec_add_ip) + .setTitle(label) + .setVisible(!decryptIp); + menu.findItem(R.id.dec_rem_ip) + .setTitle(label) + .setVisible(decryptIp); + if(conn.isBlacklistedIp()) menu.findItem(R.id.mw_whitelist_ip).setTitle(label).setVisible(true); - if(!conn.decryption_whitelisted) - menu.findItem(R.id.dec_whitelist_ip).setTitle(label).setVisible(true); - if(conn.hasHttpRequest()) menu.findItem(R.id.copy_http_request).setVisible(true); if(conn.hasHttpResponse()) @@ -463,8 +485,10 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener if(!conn.isBlacklisted()) menu.findItem(R.id.mw_whitelist_menu).setVisible(false); - if(!CaptureService.isDecryptionWhitelistEnabled() || conn.decryption_whitelisted) - menu.findItem(R.id.dec_whitelist_menu).setVisible(false); + boolean decryptionEnabled = CaptureService.isDecryptionListEnabled(); + boolean canDecryptConnection = !conn.isNotDecryptable() && !conn.isCleartext(); + menu.findItem(R.id.decrypt_menu).setVisible(decryptionEnabled && canDecryptConnection && decryptVisible); + menu.findItem(R.id.dont_decrypt_menu).setVisible(decryptionEnabled && canDecryptConnection && dontDecryptVisible); } @Override @@ -473,14 +497,14 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener ConnectionDescriptor conn = mAdapter.getSelectedItem(); MatchList whitelist = PCAPdroid.getInstance().getMalwareWhitelist(); MatchList fwWhitelist = PCAPdroid.getInstance().getFirewallWhitelist(); - MatchList decWhitelist = PCAPdroid.getInstance().getDecryptionWhitelist(); + MatchList decryptionList = PCAPdroid.getInstance().getDecryptionList(); Blocklist blocklist = PCAPdroid.getInstance().getBlocklist(); boolean firewallPurchased = Billing.newInstance(ctx).isPurchased(Billing.FIREWALL_SKU); boolean mask_changed = false; boolean whitelist_changed = false; boolean blocklist_changed = false; boolean firewall_wl_changed = false; - boolean dec_whitelist_changed = false; + boolean decryption_list_changed = false; if(conn == null) return super.onContextItemSelected(item); @@ -526,15 +550,24 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener } else if(id == R.id.mw_whitelist_host) { whitelist.addHost(conn.info); whitelist_changed = true; - } else if(id == R.id.dec_whitelist_app) { - decWhitelist.addApp(conn.uid); - dec_whitelist_changed = true; - } else if(id == R.id.dec_whitelist_ip) { - decWhitelist.addIp(conn.dst_ip); - dec_whitelist_changed = true; - } else if(id == R.id.dec_whitelist_host) { - decWhitelist.addHost(conn.info); - dec_whitelist_changed = true; + } else if(id == R.id.dec_add_app) { + decryptionList.addApp(conn.uid); + decryption_list_changed = true; + } else if(id == R.id.dec_add_ip) { + decryptionList.addIp(conn.dst_ip); + decryption_list_changed = true; + } else if(id == R.id.dec_add_host) { + decryptionList.addHost(conn.info); + decryption_list_changed = true; + } else if(id == R.id.dec_rem_app) { + decryptionList.removeApp(conn.uid); + decryption_list_changed = true; + } else if(id == R.id.dec_rem_ip) { + decryptionList.removeIp(conn.dst_ip); + decryption_list_changed = true; + } else if(id == R.id.dec_rem_host) { + decryptionList.removeHost(conn.info); + decryption_list_changed = true; } else if(id == R.id.block_app) { if(firewallPurchased) { blocklist.addApp(conn.uid); @@ -611,9 +644,9 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener fwWhitelist.save(); if(CaptureService.isServiceActive()) CaptureService.requireInstance().reloadFirewallWhitelist(); - } else if(dec_whitelist_changed) { - decWhitelist.save(); - CaptureService.reloadDecryptionWhitelist(); + } else if(decryption_list_changed) { + decryptionList.save(); + CaptureService.reloadDecryptionList(); } else if(blocklist_changed) blocklist.saveAndReload(); diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java index 7ee25271..dd1aedab 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java @@ -193,7 +193,10 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr private void recheckFilterWarning() { boolean hasFilter = ((mAppFilter != null) && (!mAppFilter.isEmpty())); - mFilterWarning.setVisibility((Prefs.getTlsDecryptionEnabled(mPrefs) && !hasFilter) ? View.VISIBLE : View.GONE); + + mFilterWarning.setVisibility((Prefs.getTlsDecryptionEnabled(mPrefs) && + Prefs.isRootCaptureEnabled(mPrefs) + && !hasFilter) ? View.VISIBLE : View.GONE); } private void refreshDecryptionStatus() { @@ -203,7 +206,7 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr 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); + mInterfaceInfo.setText((proxy_status == MitmReceiver.Status.RUNNING) ? R.string.mitm_addon_running : R.string.mitm_addon_starting); } private void refreshFilterInfo() { diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java b/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java index 63f0d78b..57e70a92 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/ConnectionDescriptor.java @@ -66,9 +66,9 @@ public class ConnectionDescriptor { public enum DecryptionStatus { INVALID, + ENCRYPTED, CLEARTEXT, DECRYPTED, - WHITELISTED, NOT_DECRYPTABLE, WAITING_DATA, ERROR, @@ -111,7 +111,7 @@ public class ConnectionDescriptor { private boolean blacklisted_ip; private boolean blacklisted_host; public boolean is_blocked; - public boolean decryption_whitelisted; + public boolean decryption_ignored; public boolean netd_block_missed; private boolean payload_truncated; private boolean encrypted_l7; // application layer is encrypted (e.g. TLS) @@ -154,7 +154,7 @@ public class ConnectionDescriptor { rcvd_pkts = update.rcvd_pkts; blocked_pkts = update.blocked_pkts; status = (update.status & 0x00FF); - decryption_whitelisted = (update.status & 0x1000) != 0; + decryption_ignored = (update.status & 0x1000) != 0; netd_block_missed = (update.status & 0x0800) != 0; is_blocked = (update.status & 0x0400) != 0; blacklisted_ip = (update.status & 0x0100) != 0; @@ -178,7 +178,7 @@ public class ConnectionDescriptor { } if((update.update_type & ConnectionUpdate.UPDATE_PAYLOAD) != 0) { // Payload for decryptable connections should be received via the MitmReceiver - assert(isNotDecryptable()); + assert(decryption_ignored || isNotDecryptable()); // Some pending updates with payload may still be received after low memory has been // triggered and payload disabled @@ -252,8 +252,8 @@ public class ConnectionDescriptor { return DecryptionStatus.CLEARTEXT; else if(decryption_error != null) return DecryptionStatus.ERROR; - else if(decryption_whitelisted) - return DecryptionStatus.WHITELISTED; + else if(decryption_ignored) + return DecryptionStatus.ENCRYPTED; else if(isNotDecryptable()) return DecryptionStatus.NOT_DECRYPTABLE; else if(isDecrypted()) @@ -269,7 +269,7 @@ public class ConnectionDescriptor { case CLEARTEXT: resid = R.string.not_encrypted; break; case NOT_DECRYPTABLE: resid = R.string.not_decryptable; break; case DECRYPTED: resid = R.string.decrypted; break; - case WHITELISTED: resid = R.string.whitelisted; break; + case ENCRYPTED: resid = R.string.status_encrypted; break; case WAITING_DATA: resid = R.string.waiting_application_data; break; default: resid = R.string.error; } @@ -305,8 +305,8 @@ public class ConnectionDescriptor { return payload_truncated; } - public boolean isNotDecryptable() { return encrypted_payload || !mitm_decrypt; } - public boolean isDecrypted() { return !isNotDecryptable() && (getNumPayloadChunks() > 0); } + public boolean isNotDecryptable() { return !decryption_ignored && (encrypted_payload || !mitm_decrypt); } + public boolean isDecrypted() { return !decryption_ignored && !isNotDecryptable() && (getNumPayloadChunks() > 0); } public boolean isCleartext() { return !encrypted_payload && !encrypted_l7; } public synchronized int getNumPayloadChunks() { return payload_chunks.size(); } diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/ListInfo.java b/app/src/main/java/com/emanuelef/remote_capture/model/ListInfo.java index 49aa4c10..02a8a895 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/ListInfo.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/ListInfo.java @@ -41,7 +41,7 @@ public class ListInfo { MALWARE_WHITELIST, BLOCKLIST, FIREWALL_WHITELIST, - DECRYPTION_WHITELIST, + DECRYPTION_LIST, } public ListInfo(Type tp) { @@ -62,8 +62,8 @@ public class ListInfo { return PCAPdroid.getInstance().getBlocklist(); case FIREWALL_WHITELIST: return PCAPdroid.getInstance().getFirewallWhitelist(); - case DECRYPTION_WHITELIST: - return PCAPdroid.getInstance().getDecryptionWhitelist(); + case DECRYPTION_LIST: + return PCAPdroid.getInstance().getDecryptionList(); } assert false; @@ -80,8 +80,8 @@ public class ListInfo { return R.string.firewall_rules; case FIREWALL_WHITELIST: return R.string.whitelist; - case DECRYPTION_WHITELIST: - return R.string.decryption_whitelist_rules; + case DECRYPTION_LIST: + return R.string.decryption_rules; } assert false; @@ -98,8 +98,8 @@ public class ListInfo { return 0; case FIREWALL_WHITELIST: return R.string.firewall_whitelist_help; - case DECRYPTION_WHITELIST: - return R.string.decryption_whitelist_help; + case DECRYPTION_LIST: + return R.string.decryption_rules_help; } assert false; @@ -111,7 +111,7 @@ public class ListInfo { case VISUALIZATION_MASK: return new ArraySet<>(Arrays.asList(RuleType.APP, RuleType.IP, RuleType.HOST, RuleType.COUNTRY, RuleType.PROTOCOL)); case MALWARE_WHITELIST: - case DECRYPTION_WHITELIST: + case DECRYPTION_LIST: case BLOCKLIST: return new ArraySet<>(Arrays.asList(RuleType.APP, RuleType.IP, RuleType.HOST)); case FIREWALL_WHITELIST: @@ -135,8 +135,8 @@ public class ListInfo { if(CaptureService.isServiceActive()) CaptureService.requireInstance().reloadFirewallWhitelist(); break; - case DECRYPTION_WHITELIST: - CaptureService.reloadDecryptionWhitelist(); + case DECRYPTION_LIST: + CaptureService.reloadDecryptionList(); break; } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java index e900cf1b..438dbccc 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/Prefs.java @@ -71,7 +71,7 @@ public class Prefs { public static final String PREF_FIREWALL_WHITELIST_MODE = "firewall_wl_mode"; public static final String PREF_FIREWALL_WHITELIST_INIT_VER = "firewall_wl_init"; public static final String PREF_FIREWALL_WHITELIST = "firewall_whitelist"; - public static final String PREF_DECRYPTION_WHITELIST = "decryption_whitelist"; + public static final String PREF_DECRYPTION_LIST = "decryption_list"; public static final String PREF_START_AT_BOOT = "start_at_boot"; public static final String PREF_SNAPLEN = "snaplen"; public static final String PREF_MAX_PKTS_PER_FLOW = "max_pkts_per_flow"; diff --git a/app/src/main/jni/core/capture_vpn.c b/app/src/main/jni/core/capture_vpn.c index 7d8b0d2d..3d95256f 100644 --- a/app/src/main/jni/core/capture_vpn.c +++ b/app/src/main/jni/core/capture_vpn.c @@ -348,23 +348,26 @@ static void update_conn_status(zdtun_t *zdt, const zdtun_pkt_t *pkt, uint8_t fro /* ******************************************************* */ -static bool should_proxy(pcapdroid_t *pd, const zdtun_5tuple_t *tuple, pd_conn_t *data) { - // NOTE: connections must be proxied as soon as the first packet arrives. +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. - if(!pd->socks5.enabled || (tuple->ipproto != IPPROTO_TCP)) + if(!pd->socks5.enabled || (tuple->ipproto != IPPROTO_TCP)) { + data->decryption_ignored = true; return false; + } - if(pd->tls_decryption.wl) { + 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.wl, &dst_ip, tuple->ipver) || - blacklist_match_uid(pd->tls_decryption.wl, data->uid) || - (data->info && blacklist_match_domain(pd->tls_decryption.wl, data->info))) { - data->decryption_whitelisted = true; - return false; - } + 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))) + return true; + + data->decryption_ignored = true; + return false; } return true; @@ -568,7 +571,7 @@ int run_vpn(pcapdroid_t *pd) { if(data->sent_pkts == 0) { if(pd_check_port_map(conn)) /* port mapping applied */; - else if(should_proxy(pd, tuple, data)) { + else if(should_proxify(pd, tuple, data)) { zdtun_conn_proxy(conn); data->proxied = true; } diff --git a/app/src/main/jni/core/jni_impl.c b/app/src/main/jni/core/jni_impl.c index edf419e3..2cd700f3 100644 --- a/app/src/main/jni/core/jni_impl.c +++ b/app/src/main/jni/core/jni_impl.c @@ -167,7 +167,7 @@ static jobject getConnUpdate(pcapdroid_t *pd, const conn_and_tuple_t *conn) { (*env)->CallVoidMethod(env, update, mids.connUpdateSetStats, data->last_seen, data->payload_length, data->sent_bytes, data->rcvd_bytes, data->sent_pkts, data->rcvd_pkts, data->blocked_pkts, (data->tcp_flags[0] << 8) | data->tcp_flags[1], - (data->decryption_whitelisted << 12) | + (data->decryption_ignored << 12) | (data->netd_block_missed << 11) | (blocked << 10) | (data->blacklisted_domain << 9) | @@ -927,8 +927,8 @@ Java_com_emanuelef_remote_1capture_CaptureService_reloadMalwareWhitelist(JNIEnv /* ******************************************************* */ JNIEXPORT jboolean JNICALL -Java_com_emanuelef_remote_1capture_CaptureService_reloadDecryptionWhitelist(JNIEnv *env, - jclass clazz, jobject whitelist) { +Java_com_emanuelef_remote_1capture_CaptureService_reloadDecryptionList(JNIEnv *env, + jclass clazz, jobject listobj) { pcapdroid_t *pd = global_pd; if(!pd) { log_e("NULL pd instance"); @@ -940,28 +940,28 @@ Java_com_emanuelef_remote_1capture_CaptureService_reloadDecryptionWhitelist(JNIE return false; } - if(pd->tls_decryption.new_wl != NULL) { - log_e("previous decryption whitelist not loaded yet"); + if(pd->tls_decryption.new_list != NULL) { + log_e("previous decryption list not loaded yet"); return false; } - blacklist_t *wl = blacklist_init(); - if(!wl) { + blacklist_t *list = blacklist_init(); + if(!list) { log_e("blacklist_init failed"); return false; } - if(blacklist_load_list_descriptor(wl, env, whitelist) < 0) { - log_f("Could not load decryption whitelist. Check the log for more details"); - blacklist_destroy(wl); + if(blacklist_load_list_descriptor(list, env, listobj) < 0) { + log_f("Could not load decryption list. Check the log for more details"); + blacklist_destroy(list); return false; } blacklists_stats_t stats; - blacklist_get_stats(wl, &stats); - log_d("reloadDecryptionWhitelist: %d apps, %d domains, %d IPs", stats.num_apps, stats.num_domains, stats.num_ips); + blacklist_get_stats(list, &stats); + log_d("reloadDecryptionList: %d apps, %d domains, %d IPs", stats.num_apps, stats.num_domains, stats.num_ips); - pd->tls_decryption.new_wl = wl; + pd->tls_decryption.new_list = list; return true; } diff --git a/app/src/main/jni/core/pcapdroid.c b/app/src/main/jni/core/pcapdroid.c index ea14d2cb..8e2b7b02 100644 --- a/app/src/main/jni/core/pcapdroid.c +++ b/app/src/main/jni/core/pcapdroid.c @@ -1046,12 +1046,12 @@ void pd_housekeeping(pcapdroid_t *pd) { iter_active_connections(pd, check_blocked_conn_cb); } - if(pd->tls_decryption.new_wl) { + if(pd->tls_decryption.new_list) { // Load new whitelist - if(pd->tls_decryption.wl) - blacklist_destroy(pd->tls_decryption.wl); - pd->tls_decryption.wl = pd->tls_decryption.new_wl; - pd->tls_decryption.new_wl = NULL; + if(pd->tls_decryption.list) + blacklist_destroy(pd->tls_decryption.list); + pd->tls_decryption.list = pd->tls_decryption.new_list; + pd->tls_decryption.new_list = NULL; } } @@ -1221,10 +1221,10 @@ int pd_run(pcapdroid_t *pd) { blacklist_destroy(pd->firewall.wl); if(pd->firewall.new_wl) blacklist_destroy(pd->firewall.new_wl); - if(pd->tls_decryption.wl) - blacklist_destroy(pd->tls_decryption.wl); - if(pd->tls_decryption.new_wl) - blacklist_destroy(pd->tls_decryption.new_wl); + if(pd->tls_decryption.list) + blacklist_destroy(pd->tls_decryption.list); + if(pd->tls_decryption.new_list) + blacklist_destroy(pd->tls_decryption.new_list); if(pd->malware_detection.enabled) { if(pd->malware_detection.reload_in_progress) { diff --git a/app/src/main/jni/core/pcapdroid.h b/app/src/main/jni/core/pcapdroid.h index 15e717fb..b2e43206 100644 --- a/app/src/main/jni/core/pcapdroid.h +++ b/app/src/main/jni/core/pcapdroid.h @@ -113,7 +113,7 @@ typedef struct { bool to_block; bool netd_block_missed; bool proxied; - bool decryption_whitelisted; + bool decryption_ignored; bool encrypted_l7; bool payload_truncated; bool has_payload[2]; // [0]: rx, [1] tx @@ -268,8 +268,8 @@ typedef struct pcapdroid { struct { bool enabled; - blacklist_t *wl; - blacklist_t *new_wl; + blacklist_t *list; + blacklist_t *new_list; } tls_decryption; } pcapdroid_t; diff --git a/app/src/main/res/drawable/ic_lock_open_alt.xml b/app/src/main/res/drawable/ic_lock_open_alt.xml new file mode 100644 index 00000000..7f4c3149 --- /dev/null +++ b/app/src/main/res/drawable/ic_lock_open_alt.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/edit_filter_activity.xml b/app/src/main/res/layout/edit_filter_activity.xml index dc259edf..71cdf443 100644 --- a/app/src/main/res/layout/edit_filter_activity.xml +++ b/app/src/main/res/layout/edit_filter_activity.xml @@ -127,13 +127,6 @@ android:layout_height="wrap_content" android:text="@string/not_decryptable"/> - - diff --git a/app/src/main/res/menu/connection_context_menu.xml b/app/src/main/res/menu/connection_context_menu.xml index ac26290c..15611bc3 100644 --- a/app/src/main/res/menu/connection_context_menu.xml +++ b/app/src/main/res/menu/connection_context_menu.xml @@ -177,22 +177,44 @@ - + + + + + + + + + + + diff --git a/app/src/main/res/menu/nav_items.xml b/app/src/main/res/menu/nav_items.xml index 9978e3b6..454d4d3a 100644 --- a/app/src/main/res/menu/nav_items.xml +++ b/app/src/main/res/menu/nav_items.xml @@ -10,9 +10,9 @@ android:title="@string/stats" android:icon="@drawable/ic_stacked_bar_chart" /> + android:id="@+id/tls_decryption" + android:title="@string/decryption_rules" + android:icon="@drawable/ic_lock_open_alt" /> License generation error [%1$d]: %2$s Requesting a license code, please wait License activation completed + Mitm addon is starting… + Mitm addon is running + Decryption rules + These rules specify which connections to decrypt. Host-based rules only work if a prior DNS reply is seen + Decrypt… + Don\'t decrypt… + Encrypted