From af2df846fdd78dd4cb35b8e91ef686acf763dea0 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Thu, 19 May 2022 22:50:49 +0200 Subject: [PATCH] Add ability to unblock connections from context menu --- .../com/emanuelef/remote_capture/Billing.java | 4 ++ .../remote_capture/CaptureService.java | 2 +- .../activities/EditFilterActivity.java | 2 +- .../activities/MainActivity.java | 2 +- .../adapters/AppsStatsAdapter.java | 13 ++-- .../fragments/AppsFragment.java | 8 ++- .../fragments/ConnectionsFragment.java | 72 ++++++++++++++++--- .../fragments/EditListFragment.java | 3 +- .../remote_capture/model/MatchList.java | 58 +++++++++------ .../emanuelef/remote_capture/model/Prefs.java | 4 +- .../main/res/menu/connection_context_menu.xml | 30 +++++++- app/src/main/res/values/strings.xml | 1 + 12 files changed, 149 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/com/emanuelef/remote_capture/Billing.java b/app/src/main/java/com/emanuelef/remote_capture/Billing.java index 119312d9..fac11856 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/Billing.java +++ b/app/src/main/java/com/emanuelef/remote_capture/Billing.java @@ -166,4 +166,8 @@ public class Billing { return rv; } + + public boolean canUseFirewall() { + return isRedeemed(Billing.FIREWALL_SKU) && !CaptureService.isCapturingAsRoot(); + } } 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 f7aa4722..102827d4 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -1139,7 +1139,7 @@ public class CaptureService extends VpnService implements Runnable { } public void reloadBlocklist() { - if(!mBilling.isRedeemed(Billing.FIREWALL_SKU) || mSettings.root_capture) + if(!mBilling.canUseFirewall()) return; Log.d(TAG, "reloading firewall blocklist"); 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 5cedf66f..4b9c630c 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 @@ -116,7 +116,7 @@ public class EditFilterActivity extends BaseActivity { if(!Prefs.isMalwareDetectionEnabled(this, prefs)) mOnlyBlacklisted.setVisibility(View.GONE); - if(!billing.isRedeemed(Billing.FIREWALL_SKU) || Prefs.isRootCaptureEnabled(prefs)) + if(!billing.canUseFirewall()) mOnlyBlocked.setVisibility(View.GONE); ConnectionsRegister reg = CaptureService.getConnsRegister(); 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 0437452f..dab6858b 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 Menu navMenu = mNavView.getMenu(); navMenu.findItem(R.id.open_root_log).setVisible(Prefs.isRootCaptureEnabled(mPrefs)); navMenu.findItem(R.id.malware_detection).setVisible(Prefs.isMalwareDetectionEnabled(this, mPrefs)); - navMenu.findItem(R.id.firewall).setVisible(mIab.isRedeemed(Billing.FIREWALL_SKU) && !Prefs.isRootCaptureEnabled(mPrefs)); + navMenu.findItem(R.id.firewall).setVisible(mIab.canUseFirewall()); } private void setupNavigationDrawer() { diff --git a/app/src/main/java/com/emanuelef/remote_capture/adapters/AppsStatsAdapter.java b/app/src/main/java/com/emanuelef/remote_capture/adapters/AppsStatsAdapter.java index 99ef1685..f9eb992e 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/adapters/AppsStatsAdapter.java +++ b/app/src/main/java/com/emanuelef/remote_capture/adapters/AppsStatsAdapter.java @@ -20,7 +20,6 @@ package com.emanuelef.remote_capture.adapters; import android.content.Context; -import android.content.SharedPreferences; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; @@ -30,10 +29,9 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; -import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; -import com.emanuelef.remote_capture.CaptureService; +import com.emanuelef.remote_capture.Billing; import com.emanuelef.remote_capture.PCAPdroid; import com.emanuelef.remote_capture.R; import com.emanuelef.remote_capture.Utils; @@ -52,10 +50,10 @@ public class AppsStatsAdapter extends RecyclerView.Adapter mStats; private final AppsResolver mApps; - private final SharedPreferences mPrefs; private int mClickedPosition; public class ViewHolder extends RecyclerView.ViewHolder { @@ -102,7 +100,7 @@ public class AppsStatsAdapter extends RecyclerView.Adapter(); - mPrefs = PreferenceManager.getDefaultSharedPreferences(context); + mFirewallAvailable = Billing.newInstance(context).canUseFirewall(); setHasStableIds(true); } @@ -121,7 +119,7 @@ public class AppsStatsAdapter extends RecyclerView.Adapter 0) { - mList.removeRules(toRemove); + for(MatchList.Rule rule: toRemove) + mList.removeRule(rule); mList.save(); } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java b/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java index 43b5a951..80215214 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java @@ -241,12 +241,11 @@ public class MatchList { return true; } - public void addApp(String pkg) { addRule(new Rule(RuleType.APP, pkg)); } public void addIp(String ip) { addRule(new Rule(RuleType.IP, ip)); } public void addHost(String info) { addRule(new Rule(RuleType.HOST, Utils.cleanDomain(info))); } public void addProto(String proto) { addRule(new Rule(RuleType.PROTOCOL, proto)); } public void addCountry(String country_code) { addRule(new Rule(RuleType.COUNTRY, country_code)); } - + public void addApp(String pkg) { addRule(new Rule(RuleType.APP, pkg)); } public void addApp(int uid) { AppDescriptor app = mResolver.get(uid, 0); if(app == null) { @@ -258,6 +257,21 @@ public class MatchList { addApp(app.getPackageName()); } + public void removeIp(String ip) { removeRule(new Rule(RuleType.IP, ip)); } + public void removeHost(String info) { removeRule(new Rule(RuleType.HOST, Utils.cleanDomain(info))); } + public void removeProto(String proto) { removeRule(new Rule(RuleType.PROTOCOL, proto)); } + public void removeCountry(String country_code) { removeRule(new Rule(RuleType.COUNTRY, country_code)); } + public void removeApp(String pkg) { removeRule(new Rule(RuleType.APP, pkg)); } + public void removeApp(int uid) { + AppDescriptor app = mResolver.get(uid, 0); + if(app == null) { + Log.e(TAG, "could not resolve UID " + uid); + return; + } + + removeApp(app.getPackageName()); + } + static private String matchKey(RuleType tp, Object val) { return tp + "@" + val; } @@ -283,24 +297,6 @@ public class MatchList { return true; } - public void removeRules(List rules) { - mRules.removeAll(rules); - - for(Rule rule: rules) { - String val = rule.getValue().toString(); - String key = matchKey(rule.getType(), val); - mMatches.remove(key); - - if(rule.getType() == RuleType.APP) { - int uid = mResolver.getUid(val); - if(uid != Utils.UID_NO_FILTER) - mUids.remove(uid); - else - Log.w(TAG, "removeRules: no uid found for package " + val); - } - } - } - public int addRules(MatchList to_add) { int num_added = 0; @@ -314,6 +310,21 @@ public class MatchList { return num_added; } + public void removeRule(Rule rule) { + String val = rule.getValue().toString(); + String key = matchKey(rule.getType(), val); + mRules.remove(rule); + mMatches.remove(key); + + if(rule.getType() == RuleType.APP) { + int uid = mResolver.getUid(val); + if(uid != Utils.UID_NO_FILTER) + mUids.remove(uid); + else + Log.w(TAG, "removeRule: no uid found for package " + val); + } + } + public boolean matchesApp(int uid) { // match apps based on their uid (faster) rather than their package name return mUids.contains(uid); @@ -327,12 +338,17 @@ public class MatchList { return mMatches.containsKey(matchKey(RuleType.PROTOCOL, l7proto)); } + public boolean matchesExactHost(String host) { + host = Utils.cleanDomain(host); + return mMatches.containsKey(matchKey(RuleType.HOST, host)); + } + public boolean matchesHost(String host) { // Keep in sync with the native blacklist_match_domain host = Utils.cleanDomain(host); // exact domain match - if(mMatches.containsKey(matchKey(RuleType.HOST, host))) + if(matchesExactHost(host)) return true; // 2nd-level domain match 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 19457e6e..12aa4c16 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 @@ -115,8 +115,8 @@ public class Prefs { && p.getBoolean(PREF_MALWARE_DETECTION, true)); } public static boolean isFirewallEnabled(Context ctx, SharedPreferences p) { - return(Billing.newInstance(ctx).isRedeemed(Billing.FIREWALL_SKU) - && !isRootCaptureEnabled(p) + // NOTE: firewall can be disabled at runtime + return(Billing.newInstance(ctx).canUseFirewall() && p.getBoolean(PREF_FIREWALL, true)); } public static boolean startAtBoot(SharedPreferences p) { return(p.getBoolean(PREF_START_AT_BOOT, false)); } diff --git a/app/src/main/res/menu/connection_context_menu.xml b/app/src/main/res/menu/connection_context_menu.xml index a74c4d95..ebaaa185 100644 --- a/app/src/main/res/menu/connection_context_menu.xml +++ b/app/src/main/res/menu/connection_context_menu.xml @@ -58,7 +58,8 @@ + tools:title="@string/host_val" + android:visible="false" /> + + + + + + + + + + + + Private DNS hinders detection Select a target app when decrypting TLS to avoid losing your connection to the Internet Block… + Unblock… Firewall Firewall rules Blocked