Add ability to whitelist malicious connections

Needed for #105
This commit is contained in:
emanuele-f 2021-10-21 14:49:23 +02:00
parent c20b56a4ac
commit bd18c5e195
21 changed files with 347 additions and 111 deletions

View File

@ -73,7 +73,7 @@
android:launchMode="singleTop"
android:parentActivityName=".activities.MainActivity" />
<activity
android:name=".activities.EditMaskActivity"
android:name=".activities.EditListActivity"
android:launchMode="singleTop"
android:parentActivityName=".activities.EditFilterActivity" />
<activity

View File

@ -412,10 +412,10 @@ public class CaptureService extends VpnService implements Runnable {
intent, Utils.getIntentFlags(PendingIntent.FLAG_UPDATE_CURRENT));
String rule_label;
if(conn.blacklisted_domain)
rule_label = MatchList.getLabel(this, MatchList.RuleType.HOST, conn.info);
if(conn.isBlacklistedHost())
rule_label = MatchList.getRuleLabel(this, MatchList.RuleType.HOST, conn.info);
else
rule_label = MatchList.getLabel(this, MatchList.RuleType.IP, conn.dst_ip);
rule_label = MatchList.getRuleLabel(this, MatchList.RuleType.IP, conn.dst_ip);
mBlacklistedBuilder
.setContentIntent(pi)

View File

@ -27,6 +27,7 @@ import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
import com.emanuelef.remote_capture.model.AppStats;
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
import com.emanuelef.remote_capture.model.ConnectionUpdate;
import com.emanuelef.remote_capture.model.MatchList;
import java.util.ArrayList;
import java.util.Arrays;
@ -46,6 +47,7 @@ public class ConnectionsRegister {
private int mUntrackedItems;
private final Map<Integer, AppStats> mAppsStats;
private final ArrayList<ConnectionsListener> 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() {
ArrayList<Integer>changed_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);

View File

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

View File

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

View File

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

View File

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

View File

@ -35,10 +35,10 @@ import com.emanuelef.remote_capture.model.MatchList;
import java.util.Iterator;
public class MaskEditAdapter extends ArrayAdapter<MatchList.Rule> implements TextAdapter {
public class ListEditAdapter extends ArrayAdapter<MatchList.Rule> implements TextAdapter {
private final LayoutInflater mLayoutInflater;
public MaskEditAdapter(Context context, Iterator<MatchList.Rule> items) {
public ListEditAdapter(Context context, Iterator<MatchList.Rule> items) {
super(context, R.layout.rule_item);
mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View File

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

View File

@ -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<MatchList.Rule> 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<MatchList.Rule> toRemove = new ArrayList<>();
Iterator<MatchList.Rule> iter = mList.iterRules();
Iterator<MatchList.Rule> 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();
}
}
}

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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;
}
}

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/mask_fragment"
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -10,13 +10,13 @@
android:scrollbarStyle="outsideOverlay" />
<TextView
android:id="@+id/mask_empty"
android:id="@+id/list_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:layout_marginTop="40dp"
android:textStyle="italic"
android:textSize="15sp"
android:text="@string/no_rules">
android:text="@string/list_is_empty">
</TextView>
</RelativeLayout>

View File

@ -61,6 +61,28 @@
</menu>
</item>
<item android:id="@+id/whitelist_menu" android:title="@string/whitelist_action">
<menu>
<item
android:id="@+id/whitelist_app"
android:title=""
android:visible="false"
tools:title="@string/app_val" />
<item
android:id="@+id/whitelist_ip"
android:title=""
android:visible="false"
tools:title="@string/ip_address_val" />
<item
android:id="@+id/whitelist_host"
android:title=""
android:visible="false"
tools:title="@string/host_val" />
</menu>
</item>
<item
android:id="@+id/open_app_details"
android:title="@string/app_details" />

View File

@ -9,6 +9,10 @@
android:id="@+id/action_stats"
android:title="@string/stats"
android:icon="@drawable/ic_list" />
<item
android:id="@+id/edit_malware_whitelist"
android:title="@string/malware_whitelist"
android:icon="@drawable/ic_checklist" />
<item
android:id="@+id/open_root_log"
android:title="@string/root_log"

View File

@ -181,9 +181,9 @@
<string name="capturing_from">Capturing packets from \"%1$s\"</string>
<string name="edit_filter">Edit Filter</string>
<string name="show_hidden_connections">Show hidden connections</string>
<string name="edit_rules">Edit Rules</string>
<string name="edit_list">Edit List</string>
<string name="hidden_connections_rules">Hidden Connections Rules</string>
<string name="no_rules">No rules</string>
<string name="list_is_empty">List is empty</string>
<string name="malicious_connection_app">Malicious connection detected (%1$s)</string>
<string name="show_only_malicious">Only malicious connections</string>
<string name="security">Security</string>
@ -192,5 +192,9 @@
<string name="blacklists_status">Blacklists Status</string>
<string name="blacklists_status_summary">Up-to-date: %1$d/%2$d ― Domain rules: %3$s ― IP rules: %4$s\nLast update: %5$s</string>
<string name="reset">Reset</string>
<string name="malware_whitelist">Malware Whitelist</string>
<string name="malware_whitelist_rules">Malware Whitelist Rules</string>
<string name="edit_hidden_connections">Edit Hidden Connections</string>
<string name="edit_malware_whitelist">Edit Malware Whitelist</string>
</resources>