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:
emanuele-f 2023-05-31 23:16:55 +02:00
parent f482d0fa8f
commit 464516409a
19 changed files with 191 additions and 127 deletions

View File

@ -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);

View File

@ -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() {

View File

@ -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))
));

View File

@ -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);

View File

@ -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();

View File

@ -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() {

View File

@ -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(); }

View File

@ -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;
}
}

View File

@ -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";

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View 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>

View File

@ -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"

View File

@ -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" />

View File

@ -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" />

View File

@ -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"

View File

@ -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>