diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2e3be4b2..c01757e5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -73,7 +73,7 @@
android:launchMode="singleTop"
android:parentActivityName=".activities.MainActivity" />
mAppsStats;
private final ArrayList mListeners;
+ private final MatchList mWhitelist;
public ConnectionsRegister(int _size) {
mTail = 0;
@@ -55,6 +57,7 @@ public class ConnectionsRegister {
mItemsRing = new ConnectionDescriptor[mSize];
mListeners = new ArrayList<>();
mAppsStats = new HashMap<>(); // uid -> AppStats
+ mWhitelist = PCAPdroid.getInstance().getMalwareWhitelist();
}
private int firstPos() {
@@ -124,6 +127,7 @@ public class ConnectionsRegister {
mAppsStats.put(uid, stats);
}
+ conn.updateWhitelist(mWhitelist);
processConnectionStatus(conn);
stats.num_connections++;
@@ -165,7 +169,10 @@ public class ConnectionsRegister {
stats.bytes += bytes_delta;
//Log.d(TAG, "update " + update.incr_id + " -> " + update.update_type);
+ boolean host_changed = (update.info != null) && (!update.info.equals(conn.info));
conn.processUpdate(update);
+ if(host_changed)
+ conn.updateWhitelist(mWhitelist);
processConnectionStatus(conn);
changed_pos[k++] = (pos + mSize - first_pos) % mSize;
@@ -196,6 +203,34 @@ public class ConnectionsRegister {
listener.connectionsChanges(mNumItems);
}
+ public synchronized void refreshConnectionsWhitelist() {
+ ArrayListchanged_pos = new ArrayList<>();
+
+ for(int i = 0; i< mNumItems; i++) {
+ ConnectionDescriptor conn = mItemsRing[i];
+
+ if(conn != null) {
+ boolean was_blacklisted = conn.isBlacklisted();
+
+ conn.updateWhitelist(mWhitelist);
+ if (conn.isBlacklisted() != was_blacklisted)
+ changed_pos.add(i);
+ }
+ }
+
+ // Notify listeners
+ if(changed_pos.size() > 0) {
+ int[] changed = new int[changed_pos.size()];
+ int i = 0;
+
+ for(Integer item: changed_pos)
+ changed[i++] = item;
+
+ for(ConnectionsListener listener: mListeners)
+ listener.connectionsUpdated(changed);
+ }
+ }
+
public synchronized void addListener(ConnectionsListener listener) {
mListeners.add(listener);
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 d3033059..7bc283cd 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java
@@ -34,6 +34,7 @@ import java.lang.ref.WeakReference;
public class PCAPdroid extends Application {
private MatchList mVisMask;
+ private MatchList mMalwareWhitelist;
private BlacklistsStatus mBlacklistsStatus;
private Context mLocalizedContext;
private static WeakReference mInstance;
@@ -71,6 +72,10 @@ public class PCAPdroid extends Application {
return mInstance.get();
}
+ public Billing getBilling(Context ctx) {
+ return new Billing(ctx);
+ }
+
public MatchList getVisualizationMask() {
if(mVisMask == null)
mVisMask = new MatchList(this, Prefs.PREF_VISUALIZATION_MASK);
@@ -85,7 +90,10 @@ public class PCAPdroid extends Application {
return mBlacklistsStatus;
}
- public Billing getBilling(Context ctx) {
- return new Billing(ctx);
+ public MatchList getMalwareWhitelist() {
+ if(mMalwareWhitelist == null)
+ mMalwareWhitelist = new MatchList(this, Prefs.PREF_MALWARE_WHITELIST);
+
+ return mMalwareWhitelist;
}
}
\ No newline at end of file
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 2984cd04..c0790f47 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
@@ -32,6 +32,7 @@ import com.emanuelef.remote_capture.PCAPdroid;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.model.ConnectionDescriptor.Status;
import com.emanuelef.remote_capture.model.FilterDescriptor;
+import com.emanuelef.remote_capture.model.ListInfo;
import com.emanuelef.remote_capture.model.MatchList;
import com.google.android.material.chip.Chip;
@@ -75,7 +76,8 @@ public class EditFilterActivity extends BaseActivity {
mStatusError = findViewById(R.id.status_error);
findViewById(R.id.edit_mask).setOnClickListener(v -> {
- Intent editIntent = new Intent(this, EditMaskActivity.class);
+ Intent editIntent = new Intent(this, EditListActivity.class);
+ editIntent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.VISUALIZATION_MASK);
startActivity(editIntent);
});
diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/EditMaskActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/EditListActivity.java
similarity index 68%
rename from app/src/main/java/com/emanuelef/remote_capture/activities/EditMaskActivity.java
rename to app/src/main/java/com/emanuelef/remote_capture/activities/EditListActivity.java
index 391d14dd..2ae2a131 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/activities/EditMaskActivity.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/activities/EditListActivity.java
@@ -30,24 +30,38 @@ import androidx.annotation.NonNull;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.Utils;
-import com.emanuelef.remote_capture.adapters.MaskEditAdapter;
-import com.emanuelef.remote_capture.fragments.EditMaskFragment;
+import com.emanuelef.remote_capture.adapters.ListEditAdapter;
+import com.emanuelef.remote_capture.fragments.EditListFragment;
+import com.emanuelef.remote_capture.model.ListInfo;
+import com.emanuelef.remote_capture.model.MatchList;
-public class EditMaskActivity extends BaseActivity {
- private static final String TAG = "MaskEditActivity";
+/* An activity to edit a MatchList, specified via LIST_INFO_EXTRA */
+public class EditListActivity extends BaseActivity {
+ private static final String TAG = "EditListActivity";
+ public static final String LIST_TYPE_EXTRA = "list_type";
+ private ListInfo mListInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setTitle(R.string.edit_rules);
- setContentView(R.layout.edit_mask_activity);
+ assert(getIntent() != null);
+ ListInfo.Type ltype = (ListInfo.Type) getIntent().getSerializableExtra(LIST_TYPE_EXTRA);
+ assert(ltype != null);
+ mListInfo = new ListInfo(ltype);
+
+ setTitle(mListInfo.getTitle());
+ setContentView(R.layout.edit_list_activity);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.mask_fragment, new EditMaskFragment())
+ .replace(R.id.fragment, new EditListFragment())
.commit();
}
+ public MatchList getList() {
+ return mListInfo.getList();
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@@ -65,15 +79,15 @@ public class EditMaskActivity extends BaseActivity {
return false;
if(id == R.id.copy_to_clipboard) {
- String contents = Utils.adapter2Text((MaskEditAdapter)lv.getAdapter());
+ String contents = Utils.adapter2Text((ListEditAdapter)lv.getAdapter());
Utils.copyToClipboard(this, contents);
return true;
} else if(id == R.id.share) {
- String contents = Utils.adapter2Text((MaskEditAdapter)lv.getAdapter());
+ String contents = Utils.adapter2Text((ListEditAdapter)lv.getAdapter());
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.setType("text/plain");
- intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.hidden_connections_rules));
+ intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(mListInfo.getShareSubject()));
intent.putExtra(android.content.Intent.EXTRA_TEXT, contents);
startActivity(Intent.createChooser(intent, getResources().getString(R.string.share)));
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 d5f3d4f3..b5736580 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
@@ -67,6 +67,7 @@ import com.emanuelef.remote_capture.interfaces.AppStateListener;
import com.emanuelef.remote_capture.model.AppState;
import com.emanuelef.remote_capture.CaptureService;
import com.emanuelef.remote_capture.model.CaptureSettings;
+import com.emanuelef.remote_capture.model.ListInfo;
import com.emanuelef.remote_capture.model.Prefs;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.Utils;
@@ -193,6 +194,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.edit_malware_whitelist).setVisible(Prefs.isMalwareDetectionEnabled(this, mPrefs));
}
private void setupNavigationDrawer() {
@@ -347,6 +349,10 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
startActivity(intent);
} else
Utils.showToast(this, R.string.capture_not_started);
+ } else if(id == R.id.edit_malware_whitelist) {
+ Intent intent = new Intent(MainActivity.this, EditListActivity.class);
+ intent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.MALWARE_WHITELIST);
+ startActivity(intent);
} else if(id == R.id.open_root_log) {
Intent intent = new Intent(MainActivity.this, LogviewActivity.class);
startActivity(intent);
diff --git a/app/src/main/java/com/emanuelef/remote_capture/adapters/MaskEditAdapter.java b/app/src/main/java/com/emanuelef/remote_capture/adapters/ListEditAdapter.java
similarity index 94%
rename from app/src/main/java/com/emanuelef/remote_capture/adapters/MaskEditAdapter.java
rename to app/src/main/java/com/emanuelef/remote_capture/adapters/ListEditAdapter.java
index e31d3320..291155e9 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/adapters/MaskEditAdapter.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/adapters/ListEditAdapter.java
@@ -35,10 +35,10 @@ import com.emanuelef.remote_capture.model.MatchList;
import java.util.Iterator;
-public class MaskEditAdapter extends ArrayAdapter implements TextAdapter {
+public class ListEditAdapter extends ArrayAdapter implements TextAdapter {
private final LayoutInflater mLayoutInflater;
- public MaskEditAdapter(Context context, Iterator items) {
+ public ListEditAdapter(Context context, Iterator items) {
super(context, R.layout.rule_item);
mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
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 183614c4..49760f60 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
@@ -55,6 +55,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.emanuelef.remote_capture.AppsResolver;
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.activities.AppDetailsActivity;
@@ -308,18 +309,24 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
if(app != null) {
MenuItem item = menu.findItem(R.id.hide_app);
- String label = MatchList.getLabel(ctx, RuleType.APP, app.getName());
+ String label = MatchList.getRuleLabel(ctx, RuleType.APP, Integer.toString(app.getUid()));
item.setTitle(label);
item.setVisible(true);
item = menu.findItem(R.id.search_app);
item.setTitle(label);
item.setVisible(true);
+
+ if(conn.isBlacklisted()) {
+ item = menu.findItem(R.id.whitelist_app);
+ item.setTitle(label);
+ item.setVisible(true);
+ }
}
if((conn.info != null) && (!conn.info.isEmpty())) {
MenuItem item = menu.findItem(R.id.hide_host);
- String label = MatchList.getLabel(ctx, RuleType.HOST, conn.info);
+ String label = MatchList.getRuleLabel(ctx, RuleType.HOST, conn.info);
item.setTitle(label);
item.setVisible(true);
@@ -331,18 +338,29 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
if(!rootDomain.equals(conn.info)) {
item = menu.findItem(R.id.hide_root_domain);
- item.setTitle(MatchList.getLabel(ctx, RuleType.ROOT_DOMAIN, rootDomain));
+ item.setTitle(MatchList.getRuleLabel(ctx, RuleType.ROOT_DOMAIN, rootDomain));
+ item.setVisible(true);
+ }
+
+ if(conn.isBlacklistedHost()) {
+ item = menu.findItem(R.id.whitelist_host);
+ item.setTitle(label);
item.setVisible(true);
}
}
- String label = MatchList.getLabel(ctx, RuleType.IP, conn.dst_ip);
+ String label = MatchList.getRuleLabel(ctx, RuleType.IP, conn.dst_ip);
menu.findItem(R.id.hide_ip).setTitle(label);
menu.findItem(R.id.search_ip).setTitle(label);
+ if(conn.isBlacklistedIp())
+ menu.findItem(R.id.whitelist_ip).setTitle(label);
- label = MatchList.getLabel(ctx, RuleType.PROTOCOL, conn.l7proto);
+ label = MatchList.getRuleLabel(ctx, RuleType.PROTOCOL, conn.l7proto);
menu.findItem(R.id.hide_proto).setTitle(label);
menu.findItem(R.id.search_proto).setTitle(label);
+
+ if(!conn.isBlacklisted())
+ menu.findItem(R.id.whitelist_menu).setVisible(false);
}
private void setQuery(String query) {
@@ -358,50 +376,73 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
});
}
+ private void recheckBlacklistedConnections() {
+ ConnectionsRegister reg = CaptureService.getConnsRegister();
+ if(reg != null)
+ reg.refreshConnectionsWhitelist();
+ }
+
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
ConnectionDescriptor conn = mAdapter.getClickedItem();
+ MatchList whitelist = PCAPdroid.getInstance().getMalwareWhitelist();
+ boolean mask_changed = false;
+ boolean whitelist_changed = false;
if(conn == null)
return super.onContextItemSelected(item);
int id = item.getItemId();
- String label = item.getTitle().toString();
- if(id == R.id.hide_app)
- mAdapter.mMask.addApp(conn.uid, label);
- else if(id == R.id.hide_host)
- mAdapter.mMask.addHost(conn.info, label);
- else if(id == R.id.hide_ip)
- mAdapter.mMask.addIp(conn.dst_ip, label);
- else if(id == R.id.hide_proto)
- mAdapter.mMask.addProto(conn.l7proto, label);
- else if(id == R.id.hide_root_domain)
- mAdapter.mMask.addRootDomain(Utils.getRootDomain(conn.info), label);
- else if(id == R.id.search_app) {
+ if(id == R.id.hide_app) {
+ mAdapter.mMask.addApp(conn.uid);
+ mask_changed = true;
+ } else if(id == R.id.hide_host) {
+ mAdapter.mMask.addHost(conn.info);
+ mask_changed = true;
+ } else if(id == R.id.hide_ip) {
+ mAdapter.mMask.addIp(conn.dst_ip);
+ mask_changed = true;
+ } else if(id == R.id.hide_proto) {
+ mAdapter.mMask.addProto(conn.l7proto);
+ mask_changed = true;
+ } else if(id == R.id.hide_root_domain) {
+ mAdapter.mMask.addRootDomain(Utils.getRootDomain(conn.info));
+ mask_changed = true;
+ } else if(id == R.id.search_app)
setQuery(Objects.requireNonNull(
mApps.get(conn.uid, 0)).getPackageName());
- return true;
- } else if(id == R.id.search_host) {
+ else if(id == R.id.search_host)
setQuery(conn.info);
- return true;
- } else if(id == R.id.search_ip) {
+ else if(id == R.id.search_ip)
setQuery(conn.dst_ip);
- return true;
- } else if(id == R.id.search_proto) {
+ else if(id == R.id.search_proto)
setQuery(conn.l7proto);
- return true;
+ else if(id == R.id.whitelist_app) {
+ whitelist.addApp(conn.uid);
+ whitelist_changed = true;
+ } else if(id == R.id.whitelist_ip) {
+ whitelist.addIp(conn.dst_ip);
+ whitelist_changed = true;
+ } else if(id == R.id.whitelist_host) {
+ whitelist.addHost(conn.info);
+ whitelist_changed = true;
} else if(id == R.id.open_app_details) {
Intent intent = new Intent(requireContext(), AppDetailsActivity.class);
intent.putExtra(AppDetailsActivity.APP_UID_EXTRA, conn.uid);
startActivity(intent);
- return true;
} else
return super.onContextItemSelected(item);
- mAdapter.mMask.save();
- mAdapter.mFilter.showMasked = false;
- refreshFilteredConnections();
+ if(mask_changed) {
+ mAdapter.mMask.save();
+ mAdapter.mFilter.showMasked = false;
+ refreshFilteredConnections();
+ } else if(whitelist_changed) {
+ whitelist.save();
+ recheckBlacklistedConnections();
+ }
+
return true;
}
diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/EditMaskFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java
similarity index 82%
rename from app/src/main/java/com/emanuelef/remote_capture/fragments/EditMaskFragment.java
rename to app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java
index 68abfca1..58949ab1 100644
--- a/app/src/main/java/com/emanuelef/remote_capture/fragments/EditMaskFragment.java
+++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/EditListFragment.java
@@ -35,35 +35,35 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
-import com.emanuelef.remote_capture.PCAPdroid;
import com.emanuelef.remote_capture.R;
-import com.emanuelef.remote_capture.adapters.MaskEditAdapter;
+import com.emanuelef.remote_capture.activities.EditListActivity;
+import com.emanuelef.remote_capture.adapters.ListEditAdapter;
import com.emanuelef.remote_capture.model.MatchList;
import java.util.ArrayList;
import java.util.Iterator;
-public class EditMaskFragment extends Fragment {
- private MaskEditAdapter mAdapter;
+public class EditListFragment extends Fragment {
+ private ListEditAdapter mAdapter;
private TextView mEmptyText;
private ArrayList mSelected = new ArrayList<>();
- private MatchList mMask;
+ private MatchList mList;
private ListView mListView;
- private static final String TAG = "MaskEditFragment";
+ private static final String TAG = "EditListFragment";
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
- return inflater.inflate(R.layout.edit_mask_fragment, container, false);
+ return inflater.inflate(R.layout.edit_list_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mListView = view.findViewById(R.id.listview);
- mEmptyText = view.findViewById(R.id.mask_empty);
- mMask = PCAPdroid.getInstance().getVisualizationMask();
+ mEmptyText = view.findViewById(R.id.list_empty);
+ mList = ((EditListActivity)requireActivity()).getList();
- mAdapter = new MaskEditAdapter(requireContext(), mMask.iterRules());
+ mAdapter = new ListEditAdapter(requireContext(), mList.iterRules());
mListView.setAdapter(mAdapter);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
@@ -82,7 +82,7 @@ public class EditMaskFragment extends Fragment {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = requireActivity().getMenuInflater();
- inflater.inflate(R.menu.mask_edit_cab, menu);
+ inflater.inflate(R.menu.list_edit_cab, menu);
return true;
}
@@ -98,12 +98,12 @@ public class EditMaskFragment extends Fragment {
if(id == R.id.delete_entry) {
if(mSelected.size() >= mAdapter.getCount()) {
mAdapter.clear();
- mMask.clear();
- mMask.save();
+ mList.clear();
+ mList.save();
} else {
for(MatchList.Rule item : mSelected)
mAdapter.remove(item);
- updateMask();
+ updateList();
}
mode.finish();
@@ -137,12 +137,11 @@ public class EditMaskFragment extends Fragment {
mEmptyText.setVisibility((mAdapter.getCount() == 0) ? View.VISIBLE : View.GONE);
}
- private void updateMask() {
+ private void updateList() {
ArrayList toRemove = new ArrayList<>();
+ Iterator iter = mList.iterRules();
- Iterator iter = mMask.iterRules();
-
- // Remove the mMask rules which are not in the adapter dataset
+ // Remove the mList rules which are not in the adapter dataset
while(iter.hasNext()) {
MatchList.Rule rule = iter.next();
@@ -151,8 +150,8 @@ public class EditMaskFragment extends Fragment {
}
if(toRemove.size() > 0) {
- mMask.removeRules(toRemove);
- mMask.save();
+ mList.removeRules(toRemove);
+ mList.save();
}
}
}
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 9b713f4a..82a670d6 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
@@ -73,11 +73,14 @@ public class ConnectionDescriptor implements Serializable {
public int incr_id;
public int status;
private int tcp_flags;
- public boolean blacklisted_ip;
- public boolean blacklisted_domain;
+ private boolean blacklisted_ip;
+ private boolean blacklisted_host;
/* Internal */
- public boolean alerted = false;
+ public boolean alerted;
+ private boolean whitelisted_ip;
+ private boolean whitelisted_host;
+ private boolean whitelisted_app;
public ConnectionDescriptor(int _incr_id, int _ipver, int _ipproto, String _src_ip, String _dst_ip,
int _src_port, int _dst_port, int _uid, long when) {
@@ -101,7 +104,7 @@ public class ConnectionDescriptor implements Serializable {
rcvd_pkts = update.rcvd_pkts;
status = (update.status & 0x00FF);
blacklisted_ip = (update.status & 0x0100) != 0;
- blacklisted_domain = (update.status & 0x0200) != 0;
+ blacklisted_host = (update.status & 0x0200) != 0;
last_seen = update.last_seen;
tcp_flags = update.tcp_flags;
}
@@ -164,8 +167,16 @@ public class ConnectionDescriptor implements Serializable {
return (tcp_flags & 0xFF);
}
+ public boolean isBlacklistedIp() { return !whitelisted_app && !whitelisted_ip && blacklisted_ip; }
+ public boolean isBlacklistedHost() { return !whitelisted_app && !whitelisted_host && blacklisted_host; }
public boolean isBlacklisted() {
- return blacklisted_ip || blacklisted_domain;
+ return isBlacklistedIp() || isBlacklistedHost();
+ }
+
+ public void updateWhitelist(MatchList whitelist) {
+ whitelisted_app = whitelist.matchesApp(uid);
+ whitelisted_ip = whitelist.matchesIP(dst_ip);
+ whitelisted_host = whitelist.matchesHost(info);
}
@Override
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
new file mode 100644
index 00000000..c8c21211
--- /dev/null
+++ b/app/src/main/java/com/emanuelef/remote_capture/model/ListInfo.java
@@ -0,0 +1,75 @@
+/*
+ * 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 .
+ *
+ * Copyright 2020-21 - Emanuele Faranda
+ */
+
+package com.emanuelef.remote_capture.model;
+
+import androidx.annotation.NonNull;
+
+import com.emanuelef.remote_capture.PCAPdroid;
+import com.emanuelef.remote_capture.R;
+
+
+public class ListInfo {
+ private final Type mType;
+
+ public enum Type {
+ VISUALIZATION_MASK,
+ MALWARE_WHITELIST,
+ }
+
+ public ListInfo(Type tp) {
+ mType = tp;
+ }
+
+ public @NonNull MatchList getList() {
+ switch(mType) {
+ case VISUALIZATION_MASK:
+ return PCAPdroid.getInstance().getVisualizationMask();
+ case MALWARE_WHITELIST:
+ return PCAPdroid.getInstance().getMalwareWhitelist();
+ }
+
+ assert false;
+ return null;
+ }
+
+ public int getTitle() {
+ switch(mType) {
+ case VISUALIZATION_MASK:
+ return R.string.edit_hidden_connections;
+ case MALWARE_WHITELIST:
+ return R.string.edit_malware_whitelist;
+ }
+
+ assert false;
+ return 0;
+ }
+
+ public int getShareSubject() {
+ switch(mType) {
+ case VISUALIZATION_MASK:
+ return R.string.hidden_connections_rules;
+ case MALWARE_WHITELIST:
+ return R.string.malware_whitelist_rules;
+ }
+
+ assert false;
+ return 0;
+ }
+}
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 e7f5b69c..bbb0ca5f 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
@@ -64,21 +64,17 @@ public class MatchList {
PROTOCOL
}
- public static class Rule {
+ public class Rule {
private final String mLabel;
private final RuleType mType;
private final Object mValue;
- Rule(RuleType tp, Object value, String label) {
- mLabel = label;
+ private Rule(RuleType tp, Object value) {
+ mLabel = MatchList.getRuleLabel(mContext, tp, value.toString());
mType = tp;
mValue = value;
}
- public Rule(Context ctx, RuleType tp, Object value) {
- this(tp, value, MatchList.getLabel(ctx, tp, value.toString()));
- }
-
public String getLabel() {
return mLabel;
}
@@ -124,7 +120,7 @@ public class MatchList {
.apply();
}
- public static String getLabel(Context ctx, RuleType tp, String value) {
+ public static String getRuleLabel(Context ctx, RuleType tp, String value) {
int resid;
switch(tp) {
@@ -137,6 +133,14 @@ public class MatchList {
return "";
}
+ if(tp == RuleType.APP) {
+ AppsResolver resolver = new AppsResolver(ctx);
+ AppDescriptor app = resolver.get(Integer.parseInt(value), 0);
+
+ if(app != null)
+ value = app.getName();
+ }
+
return Utils.formatTextValue(ctx, null, italic, resid, value).toString();
}
@@ -167,8 +171,6 @@ public class MatchList {
if(ruleArray == null)
return;
- AppsResolver resolver = new AppsResolver(mContext);
-
for(JsonElement el: ruleArray) {
JsonObject ruleObj = el.getAsJsonObject();
RuleType type;
@@ -181,25 +183,15 @@ public class MatchList {
}
String val = ruleObj.get("value").getAsString();
- String valLabel = val;
-
- if(type == RuleType.APP) {
- AppDescriptor app = resolver.get(Integer.parseInt(val), 0);
-
- if(app != null)
- valLabel = app.getName();
- }
-
- String label = getLabel(mContext, type, valLabel);
- addRule(new Rule(type, val, label));
+ addRule(new Rule(type, val));
}
}
- public void addApp(int uid, String label) { addRule(new Rule(RuleType.APP, uid, label)); }
- public void addIp(String ip, String label) { addRule(new Rule(RuleType.IP, ip, label)); }
- public void addHost(String info, String label) { addRule(new Rule(RuleType.HOST, info, label)); }
- public void addProto(String proto, String label) { addRule(new Rule(RuleType.PROTOCOL, proto, label)); }
- public void addRootDomain(String domain, String label) { addRule(new Rule(RuleType.ROOT_DOMAIN, domain, label)); }
+ public void addApp(int uid) { addRule(new Rule(RuleType.APP, uid)); }
+ public void addIp(String ip) { addRule(new Rule(RuleType.IP, ip)); }
+ public void addHost(String info) { addRule(new Rule(RuleType.HOST, info)); }
+ public void addProto(String proto) { addRule(new Rule(RuleType.PROTOCOL, proto)); }
+ public void addRootDomain(String domain) { addRule(new Rule(RuleType.ROOT_DOMAIN, domain)); }
static private String matchKey(RuleType tp, Object val) {
return tp + "@" + val;
@@ -223,14 +215,36 @@ public class MatchList {
}
}
- public boolean matches(ConnectionDescriptor conn) {
- boolean hasInfo = ((conn.info != null) && (!conn.info.isEmpty()));
+ public boolean matchesApp(int uid) {
+ return mMatches.containsKey(matchKey(RuleType.APP, uid));
+ }
- return(mMatches.containsKey(matchKey(RuleType.APP, conn.uid)) ||
- mMatches.containsKey(matchKey(RuleType.IP, conn.dst_ip)) ||
- mMatches.containsKey(matchKey(RuleType.PROTOCOL, conn.l7proto)) ||
- (hasInfo && mMatches.containsKey(matchKey(RuleType.HOST, conn.info))) ||
- (hasInfo && mMatches.containsKey(matchKey(RuleType.ROOT_DOMAIN, Utils.getRootDomain(conn.info)))));
+ public boolean matchesIP(String ip) {
+ return mMatches.containsKey(matchKey(RuleType.IP, ip));
+ }
+
+ public boolean matchesProto(String l7proto) {
+ return mMatches.containsKey(matchKey(RuleType.PROTOCOL, l7proto));
+ }
+
+ public boolean matchesHost(String host) {
+ return mMatches.containsKey(matchKey(RuleType.HOST, host));
+ }
+
+ public boolean matchesRootDomain(String root_domain) {
+ return mMatches.containsKey(matchKey(RuleType.ROOT_DOMAIN, root_domain));
+ }
+
+ public boolean matches(ConnectionDescriptor conn) {
+ if(mMatches.isEmpty())
+ return false;
+
+ boolean hasInfo = ((conn.info != null) && (!conn.info.isEmpty()));
+ return(matchesApp(conn.uid) ||
+ matchesIP(conn.dst_ip) ||
+ matchesIP(conn.l7proto) ||
+ (hasInfo && matchesHost(conn.info))) ||
+ (hasInfo && matchesRootDomain(Utils.getRootDomain(conn.info)));
}
public Iterator iterRules() {
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 69a5342e..9d3ec5b2 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
@@ -47,6 +47,7 @@ public class Prefs {
public static final String PREF_APP_THEME = "app_theme";
public static final String PREF_ROOT_CAPTURE = "root_capture";
public static final String PREF_VISUALIZATION_MASK = "vis_mask";
+ public static final String PREF_MALWARE_WHITELIST = "maware_whitelist";
public static final String PREF_PCAPDROID_TRAILER = "pcapdroid_trailer";
public enum DumpMode {
diff --git a/app/src/main/res/layout/edit_filter_activity.xml b/app/src/main/res/layout/edit_filter_activity.xml
index 90e196a8..42b97537 100644
--- a/app/src/main/res/layout/edit_filter_activity.xml
+++ b/app/src/main/res/layout/edit_filter_activity.xml
@@ -31,7 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
- android:text="@string/edit_rules"
+ android:text="@string/edit_list"
style="?attr/materialButtonOutlinedStyle"
android:textColor="@color/colorTabText" />
diff --git a/app/src/main/res/layout/edit_mask_activity.xml b/app/src/main/res/layout/edit_list_activity.xml
similarity index 90%
rename from app/src/main/res/layout/edit_mask_activity.xml
rename to app/src/main/res/layout/edit_list_activity.xml
index e8591c99..a6a94592 100644
--- a/app/src/main/res/layout/edit_mask_activity.xml
+++ b/app/src/main/res/layout/edit_list_activity.xml
@@ -5,7 +5,7 @@
android:orientation="vertical">
diff --git a/app/src/main/res/layout/edit_mask_fragment.xml b/app/src/main/res/layout/edit_list_fragment.xml
similarity index 89%
rename from app/src/main/res/layout/edit_mask_fragment.xml
rename to app/src/main/res/layout/edit_list_fragment.xml
index 2ffdee5f..0677d81e 100644
--- a/app/src/main/res/layout/edit_mask_fragment.xml
+++ b/app/src/main/res/layout/edit_list_fragment.xml
@@ -10,13 +10,13 @@
android:scrollbarStyle="outsideOverlay" />
+ android:text="@string/list_is_empty">
diff --git a/app/src/main/res/menu/connection_context_menu.xml b/app/src/main/res/menu/connection_context_menu.xml
index 86041471..3247fe7a 100644
--- a/app/src/main/res/menu/connection_context_menu.xml
+++ b/app/src/main/res/menu/connection_context_menu.xml
@@ -61,6 +61,28 @@
+ -
+
+
+
diff --git a/app/src/main/res/menu/mask_edit_cab.xml b/app/src/main/res/menu/list_edit_cab.xml
similarity index 100%
rename from app/src/main/res/menu/mask_edit_cab.xml
rename to app/src/main/res/menu/list_edit_cab.xml
diff --git a/app/src/main/res/menu/nav_items.xml b/app/src/main/res/menu/nav_items.xml
index 017509d7..590be011 100644
--- a/app/src/main/res/menu/nav_items.xml
+++ b/app/src/main/res/menu/nav_items.xml
@@ -9,6 +9,10 @@
android:id="@+id/action_stats"
android:title="@string/stats"
android:icon="@drawable/ic_list" />
+
- Capturing packets from \"%1$s\"
Edit Filter
Show hidden connections
- Edit Rules
+ Edit List
Hidden Connections Rules
- No rules
+ List is empty
Malicious connection detected (%1$s)
Only malicious connections
Security
@@ -192,5 +192,9 @@
Blacklists Status
Up-to-date: %1$d/%2$d ― Domain rules: %3$s ― IP rules: %4$s\nLast update: %5$s
Reset
+ Malware Whitelist
+ Malware Whitelist Rules
+ Edit Hidden Connections
+ Edit Malware Whitelist