mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-16 21:10:57 +08:00
parent
c20b56a4ac
commit
bd18c5e195
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
});
|
||||
|
||||
|
||||
@ -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)));
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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>
|
||||
@ -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" />
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user