mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-07-03 21:21:12 +08:00
parent
4e2e168ec5
commit
dd98decfec
@ -65,6 +65,7 @@ import com.emanuelef.remote_capture.model.CaptureSettings;
|
||||
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
import com.emanuelef.remote_capture.model.ConnectionUpdate;
|
||||
import com.emanuelef.remote_capture.model.FilterDescriptor;
|
||||
import com.emanuelef.remote_capture.model.GraceList;
|
||||
import com.emanuelef.remote_capture.model.MatchList;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
import com.emanuelef.remote_capture.model.CaptureStats;
|
||||
@ -136,6 +137,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
private boolean mQueueFull;
|
||||
private boolean mStopping;
|
||||
private Blacklists mBlacklists;
|
||||
private GraceList mGracelist;
|
||||
private MatchList mBlocklist;
|
||||
private MatchList mWhitelist;
|
||||
private SparseArray<String> mIfIndexToName;
|
||||
@ -447,6 +449,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
|
||||
mWhitelist = PCAPdroid.getInstance().getMalwareWhitelist();
|
||||
mBlacklists = PCAPdroid.getInstance().getBlacklists();
|
||||
mGracelist = PCAPdroid.getInstance().getGracelist();
|
||||
if(mMalwareDetectionEnabled && !mBlacklists.needsUpdate())
|
||||
reloadBlacklists();
|
||||
checkBlacklistsUpdates();
|
||||
@ -992,6 +995,8 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
ConnectionUpdate[] conns_updates = item.second;
|
||||
|
||||
checkBlacklistsUpdates();
|
||||
if(mGracelist.checkGracePeriods())
|
||||
mHandler.post(this::reloadBlocklist);
|
||||
|
||||
if(!mLowMemory)
|
||||
checkAvailableHeap();
|
||||
@ -1297,7 +1302,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
return;
|
||||
|
||||
Log.d(TAG, "reloading firewall blocklist");
|
||||
reloadBlocklist(mBlocklist.toListDescriptor());
|
||||
reloadBlocklist(mBlocklist.toListDescriptor(mGracelist));
|
||||
}
|
||||
|
||||
public static void reloadMalwareWhitelist() {
|
||||
@ -1305,7 +1310,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
return;
|
||||
|
||||
Log.d(TAG, "reloading malware whitelist");
|
||||
reloadMalwareWhitelist(INSTANCE.mWhitelist.toListDescriptor());
|
||||
reloadMalwareWhitelist(INSTANCE.mWhitelist.toListDescriptor(null));
|
||||
}
|
||||
|
||||
public static void setFirewallEnabled(boolean enabled) {
|
||||
|
||||
@ -29,6 +29,7 @@ import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.emanuelef.remote_capture.activities.ErrorActivity;
|
||||
import com.emanuelef.remote_capture.model.CtrlPermissions;
|
||||
import com.emanuelef.remote_capture.model.GraceList;
|
||||
import com.emanuelef.remote_capture.model.MatchList;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
|
||||
@ -49,6 +50,7 @@ public class PCAPdroid extends Application {
|
||||
private MatchList mVisMask;
|
||||
private MatchList mMalwareWhitelist;
|
||||
private MatchList mBlocklist;
|
||||
private GraceList mGracelist;
|
||||
private Blacklists mBlacklists;
|
||||
private CtrlPermissions mCtrlPermissions;
|
||||
private Context mLocalizedContext;
|
||||
@ -117,6 +119,12 @@ public class PCAPdroid extends Application {
|
||||
return mBlocklist;
|
||||
}
|
||||
|
||||
public GraceList getGracelist() {
|
||||
if(mGracelist == null)
|
||||
mGracelist = new GraceList();
|
||||
return mGracelist;
|
||||
}
|
||||
|
||||
public CtrlPermissions getCtrlPermissions() {
|
||||
if(mCtrlPermissions == null)
|
||||
mCtrlPermissions = new CtrlPermissions(this);
|
||||
|
||||
@ -64,6 +64,7 @@ import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
import com.emanuelef.remote_capture.activities.ConnectionDetailsActivity;
|
||||
import com.emanuelef.remote_capture.adapters.ConnectionsAdapter;
|
||||
import com.emanuelef.remote_capture.model.FilterDescriptor;
|
||||
import com.emanuelef.remote_capture.model.GraceList;
|
||||
import com.emanuelef.remote_capture.model.MatchList;
|
||||
import com.emanuelef.remote_capture.model.MatchList.RuleType;
|
||||
import com.emanuelef.remote_capture.views.EmptyRecyclerView;
|
||||
@ -338,6 +339,10 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
item.setTitle(label);
|
||||
item.setVisible(appBlocked);
|
||||
|
||||
menu.findItem(R.id.unblock_app_1h).setTitle(getString(R.string.unblock_for_n_hours, 1));
|
||||
menu.findItem(R.id.unblock_app_2h).setTitle(getString(R.string.unblock_for_n_hours, 2));
|
||||
menu.findItem(R.id.unblock_app_8h).setTitle(getString(R.string.unblock_for_n_hours, 8));
|
||||
|
||||
if(conn.isBlacklisted()) {
|
||||
item = menu.findItem(R.id.whitelist_app);
|
||||
item.setTitle(label);
|
||||
@ -453,9 +458,11 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
ConnectionDescriptor conn = mAdapter.getClickedItem();
|
||||
MatchList whitelist = PCAPdroid.getInstance().getMalwareWhitelist();
|
||||
MatchList blocklist = PCAPdroid.getInstance().getBlocklist();
|
||||
GraceList gracelist = PCAPdroid.getInstance().getGracelist();
|
||||
boolean mask_changed = false;
|
||||
boolean whitelist_changed = false;
|
||||
boolean blocklist_changed = false;
|
||||
boolean gracelist_changed = false;
|
||||
|
||||
if(conn == null)
|
||||
return super.onContextItemSelected(item);
|
||||
@ -510,9 +517,17 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
} else if(id == R.id.block_domain) {
|
||||
blocklist.addHost(Utils.getSecondLevelDomain(conn.info));
|
||||
blocklist_changed = true;
|
||||
} else if(id == R.id.unblock_app) {
|
||||
} else if(id == R.id.unblock_app_permanently) {
|
||||
blocklist.removeApp(conn.uid);
|
||||
gracelist.removeApp(conn.uid);
|
||||
blocklist_changed = true;
|
||||
gracelist_changed = true;
|
||||
} else if(id == R.id.unblock_app_1h) {
|
||||
gracelist_changed = gracelist.unblockAppForMinutes(conn.uid, 60);
|
||||
} else if(id == R.id.unblock_app_2h) {
|
||||
gracelist_changed = gracelist.unblockAppForMinutes(conn.uid, 120);
|
||||
} else if(id == R.id.unblock_app_8h) {
|
||||
gracelist_changed = gracelist.unblockAppForMinutes(conn.uid, 480);
|
||||
} else if(id == R.id.unblock_ip) {
|
||||
blocklist.removeIp(conn.dst_ip);
|
||||
blocklist_changed = true;
|
||||
@ -546,8 +561,9 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
} else if(whitelist_changed) {
|
||||
whitelist.save();
|
||||
CaptureService.reloadMalwareWhitelist();
|
||||
} else if(blocklist_changed) {
|
||||
blocklist.save();
|
||||
} else if(blocklist_changed || gracelist_changed) {
|
||||
if(blocklist_changed)
|
||||
blocklist.save();
|
||||
if(CaptureService.isServiceActive())
|
||||
CaptureService.requireInstance().reloadBlocklist();
|
||||
}
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of PCAPdroid.
|
||||
*
|
||||
* PCAPdroid is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PCAPdroid is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020-21 - Emanuele Faranda
|
||||
*/
|
||||
|
||||
package com.emanuelef.remote_capture.model;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class GraceList {
|
||||
private static final String TAG = "GraceList";
|
||||
private final ArrayMap<Integer, Long> mUidToGrace = new ArrayMap<>();
|
||||
|
||||
// returns true if this is a new unblock
|
||||
public synchronized boolean unblockAppForMinutes(int uid, long minutes) {
|
||||
Long old_val = mUidToGrace.put(uid, SystemClock.uptimeMillis() + (minutes * 60_000));
|
||||
Log.d(TAG, "Grace app: " + uid + " for " + minutes + " minutes (old: " + old_val + ")");
|
||||
return (old_val == null);
|
||||
}
|
||||
|
||||
public synchronized boolean checkGracePeriods() {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
boolean changed = false;
|
||||
Iterator<Map.Entry<Integer,Long>> iter = mUidToGrace.entrySet().iterator();
|
||||
|
||||
while(iter.hasNext()) {
|
||||
Map.Entry<Integer, Long> entry = iter.next();
|
||||
|
||||
if(now >= entry.getValue()) {
|
||||
Log.d(TAG, "Grace period ended for app: " + entry.getKey());
|
||||
iter.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public synchronized boolean containsApp(int uid) {
|
||||
return mUidToGrace.containsKey(uid);
|
||||
}
|
||||
|
||||
public synchronized void removeApp(int uid) {
|
||||
Log.d(TAG, "Manually remove app: " + uid);
|
||||
mUidToGrace.remove(uid);
|
||||
}
|
||||
}
|
||||
@ -416,7 +416,7 @@ public class MatchList {
|
||||
/* Convert the MatchList into a ListDescriptor, which can be then loaded by JNI.
|
||||
* Only the following RuleTypes are supported: APP, IP, HOST.
|
||||
*/
|
||||
public ListDescriptor toListDescriptor() {
|
||||
public ListDescriptor toListDescriptor(GraceList exemptions) {
|
||||
final ListDescriptor rv = new ListDescriptor();
|
||||
|
||||
Iterator<MatchList.Rule> it = iterRules();
|
||||
@ -434,8 +434,10 @@ public class MatchList {
|
||||
}
|
||||
|
||||
// Apps are matched via their UID
|
||||
for(int uid: mUids)
|
||||
rv.apps.add(Integer.toString(uid));
|
||||
for(int uid: mUids) {
|
||||
if((exemptions == null) || (!exemptions.containsApp(uid)))
|
||||
rv.apps.add(Integer.toString(uid));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -75,7 +75,23 @@
|
||||
android:id="@+id/unblock_app"
|
||||
android:title=""
|
||||
tools:title="@string/app_val"
|
||||
android:visible="false" />
|
||||
android:visible="false">
|
||||
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/unblock_app_permanently"
|
||||
android:title="@string/unblock_permanently" />
|
||||
<item
|
||||
android:id="@+id/unblock_app_1h"
|
||||
android:title="" />
|
||||
<item
|
||||
android:id="@+id/unblock_app_2h"
|
||||
android:title="" />
|
||||
<item
|
||||
android:id="@+id/unblock_app_8h"
|
||||
android:title="" />
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/unblock_ip"
|
||||
|
||||
@ -377,4 +377,6 @@
|
||||
<string name="vpn_exemptions_summary">Exempt some apps from the VPN connection. Their traffic will not be monitored</string>
|
||||
<string name="no_matches_found">No matches</string>
|
||||
<string name="cleartext_connection">Cleartext</string>
|
||||
<string name="unblock_permanently">Unblock permanently</string>
|
||||
<string name="unblock_for_n_hours">Unblock for %1$dh</string>
|
||||
</resources>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user