mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-07-03 21:21:12 +08:00
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.
This commit is contained in:
parent
f482d0fa8f
commit
464516409a
@ -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<String> 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);
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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))
|
||||
));
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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(); }
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
5
app/src/main/res/drawable/ic_lock_open_alt.xml
Normal file
5
app/src/main/res/drawable/ic_lock_open_alt.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
|
||||
</vector>
|
||||
@ -127,13 +127,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/not_decryptable"/>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/dec_status_whitelisted"
|
||||
style="@style/Widget.MaterialComponents.Chip.Choice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/whitelisted"/>
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/dec_status_error"
|
||||
style="@style/Widget.MaterialComponents.Chip.Choice"
|
||||
|
||||
@ -96,6 +96,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/app_filter_text"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="@string/decryption_no_filter_warn"
|
||||
android:textColor="@color/warning"
|
||||
android:textSize="14sp" />
|
||||
|
||||
@ -177,22 +177,44 @@
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/dec_whitelist_menu" android:title="@string/decryption_whitelist_action">
|
||||
<item android:id="@+id/decrypt_menu" android:title="@string/decrypt_action">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/dec_whitelist_app"
|
||||
android:id="@+id/dec_add_app"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/app_val" />
|
||||
|
||||
<item
|
||||
android:id="@+id/dec_whitelist_ip"
|
||||
android:id="@+id/dec_add_ip"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/ip_address_val" />
|
||||
|
||||
<item
|
||||
android:id="@+id/dec_whitelist_host"
|
||||
android:id="@+id/dec_add_host"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/host_val" />
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/dont_decrypt_menu" android:title="@string/dont_decrypt_action">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/dec_rem_app"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/app_val" />
|
||||
|
||||
<item
|
||||
android:id="@+id/dec_rem_ip"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/ip_address_val" />
|
||||
|
||||
<item
|
||||
android:id="@+id/dec_rem_host"
|
||||
android:title=""
|
||||
android:visible="false"
|
||||
tools:title="@string/host_val" />
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
android:title="@string/stats"
|
||||
android:icon="@drawable/ic_stacked_bar_chart" />
|
||||
<item
|
||||
android:id="@+id/dec_whitelist"
|
||||
android:title="@string/decryption_whitelist"
|
||||
android:icon="@drawable/ic_checklist" />
|
||||
android:id="@+id/tls_decryption"
|
||||
android:title="@string/decryption_rules"
|
||||
android:icon="@drawable/ic_lock_open_alt" />
|
||||
<item
|
||||
android:id="@+id/firewall"
|
||||
android:title="@string/firewall"
|
||||
|
||||
@ -473,4 +473,11 @@
|
||||
<string name="license_error">License generation error [%1$d]: %2$s</string>
|
||||
<string name="requesting_license">Requesting a license code, please wait</string>
|
||||
<string name="license_activation_ok">License activation completed</string>
|
||||
<string name="mitm_addon_starting">Mitm addon is starting…</string>
|
||||
<string name="mitm_addon_running">Mitm addon is running</string>
|
||||
<string name="decryption_rules">Decryption rules</string>
|
||||
<string name="decryption_rules_help">These rules specify which connections to decrypt. Host-based rules only work if a prior DNS reply is seen</string>
|
||||
<string name="decrypt_action">Decrypt…</string>
|
||||
<string name="dont_decrypt_action">Don\'t decrypt…</string>
|
||||
<string name="status_encrypted">Encrypted</string>
|
||||
</resources>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user