mirror of
https://github.com/M66B/NetGuard.git
synced 2025-01-01 12:54:07 +00:00
Block/allow hosts UI
This commit is contained in:
parent
c7bd5292a8
commit
46fd086337
17 changed files with 364 additions and 56 deletions
|
@ -98,7 +98,6 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/objectFiles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
|
|
|
@ -1,12 +1,31 @@
|
|||
package eu.faircode.netguard;
|
||||
|
||||
/*
|
||||
This file is part of NetGuard.
|
||||
|
||||
NetGuard 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.
|
||||
|
||||
NetGuard 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 NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -42,13 +61,15 @@ public class AccessAdapter extends CursorAdapter {
|
|||
|
||||
// Get views
|
||||
TextView tvTime = (TextView) view.findViewById(R.id.tvTime);
|
||||
CheckBox cbBlock = (CheckBox) view.findViewById(R.id.cbBlock);
|
||||
ImageView ivBlock = (ImageView) view.findViewById(R.id.ivBlock);
|
||||
final TextView tvDest = (TextView) view.findViewById(R.id.tvDest);
|
||||
|
||||
// Set values
|
||||
tvTime.setText(new SimpleDateFormat("HH:mm:ss").format(time));
|
||||
cbBlock.setVisibility(block < 0 ? View.INVISIBLE : View.VISIBLE);
|
||||
cbBlock.setChecked(block > 0);
|
||||
if (block < 0)
|
||||
ivBlock.setImageDrawable(null);
|
||||
else
|
||||
ivBlock.setImageResource(block > 0 ? R.drawable.host_blocked : R.drawable.host_allowed);
|
||||
tvDest.setText(daddr + (dport > 0 ? ":" + dport : ""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -363,7 +363,7 @@ public class ActivityLog extends AppCompatActivity implements SharedPreferences.
|
|||
new AsyncTask<Object, Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground(Object... objects) {
|
||||
dh.clear();
|
||||
dh.clearLog();
|
||||
if (prefs.getBoolean("pcap", false)) {
|
||||
SinkholeService.setPcap(null, false);
|
||||
pcap_file.delete();
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
package eu.faircode.netguard;
|
||||
|
||||
/*
|
||||
This file is part of NetGuard.
|
||||
|
||||
NetGuard 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.
|
||||
|
||||
NetGuard 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 NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
@ -9,7 +28,6 @@ import android.util.Log;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
@ -19,8 +37,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
private static final int DB_VERSION = 11;
|
||||
|
||||
private static boolean once = true;
|
||||
private static List<LogChangedListener> logChangedListeners = new ArrayList<LogChangedListener>();
|
||||
private static List<AccessChangedListener> accessChangedListeners = new ArrayList<AccessChangedListener>();
|
||||
private static List<LogChangedListener> logChangedListeners = new ArrayList<>();
|
||||
private static List<AccessChangedListener> accessChangedListeners = new ArrayList<>();
|
||||
|
||||
private Context mContext;
|
||||
|
||||
|
@ -229,7 +247,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DatabaseHelper clear() {
|
||||
public DatabaseHelper clearLog() {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
db.delete("log", null, new String[]{});
|
||||
|
@ -248,14 +266,16 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
public Cursor getLog() {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
String query = "SELECT ID AS _id, * FROM log";
|
||||
String query = "SELECT ID AS _id, *";
|
||||
query += " FROM log";
|
||||
query += " ORDER BY time DESC";
|
||||
return db.rawQuery(query, new String[]{});
|
||||
}
|
||||
|
||||
public Cursor searchLog(String find) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
String query = "SELECT ID AS _id, * FROM log";
|
||||
String query = "SELECT ID AS _id, *";
|
||||
query += " FROM log";
|
||||
query += " WHERE daddr LIKE ? OR uid LIKE ?";
|
||||
query += " ORDER BY time DESC";
|
||||
return db.rawQuery(query, new String[]{"%" + find + "%", "%" + find + "%"});
|
||||
|
@ -297,13 +317,56 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DatabaseHelper setAccess(long id, int uid, int block) {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("block", block);
|
||||
|
||||
if (db.update("access", cv, "ID = ?", new String[]{Long.toString(id)}) != 1)
|
||||
Log.e(TAG, "Set access failed");
|
||||
|
||||
for (AccessChangedListener listener : accessChangedListeners)
|
||||
try {
|
||||
listener.onChanged(uid);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public DatabaseHelper clearAccess(int uid) {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
db.delete("access", "uid = ?", new String[]{Integer.toString(uid)});
|
||||
}
|
||||
|
||||
for (AccessChangedListener listener : accessChangedListeners)
|
||||
try {
|
||||
listener.onChanged(uid);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cursor getAccess(int uid) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
String query = "SELECT ID AS _id, * FROM access WHERE uid = ?";
|
||||
String query = "SELECT ID AS _id, *";
|
||||
query += " FROM access WHERE uid = ?";
|
||||
query += " ORDER BY time DESC";
|
||||
return db.rawQuery(query, new String[]{Integer.toString(uid)});
|
||||
}
|
||||
|
||||
public Cursor getAccess() {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
return db.query("access", new String[]{"uid", "daddr", "dport", "block"}, "block >= 0", null, null, null, null);
|
||||
}
|
||||
|
||||
public void addLogChangedListener(LogChangedListener listener) {
|
||||
logChangedListeners.add(listener);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
package eu.faircode.netguard;
|
||||
|
||||
/*
|
||||
This file is part of NetGuard.
|
||||
|
||||
NetGuard 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.
|
||||
|
||||
NetGuard 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 NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ListView;
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
package eu.faircode.netguard;
|
||||
|
||||
/*
|
||||
This file is part of NetGuard.
|
||||
|
||||
NetGuard 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.
|
||||
|
||||
NetGuard 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 NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
|
|
@ -22,10 +22,13 @@ package eu.faircode.netguard;
|
|||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
|
@ -36,9 +39,11 @@ import android.support.v7.widget.RecyclerView;
|
|||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.TouchDelegate;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
|
@ -48,6 +53,7 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
@ -107,6 +113,7 @@ public class RuleAdapter extends RecyclerView.Adapter<RuleAdapter.ViewHolder> im
|
|||
public Button btnLaunch;
|
||||
|
||||
public ListView lvAccess;
|
||||
public ImageButton btnClearAccess;
|
||||
public TextView tvStatistics;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
|
@ -146,6 +153,7 @@ public class RuleAdapter extends RecyclerView.Adapter<RuleAdapter.ViewHolder> im
|
|||
btnLaunch = (Button) itemView.findViewById(R.id.btnLaunch);
|
||||
|
||||
lvAccess = (ListView) itemView.findViewById(R.id.lvAccess);
|
||||
btnClearAccess = (ImageButton) itemView.findViewById(R.id.btnClearAccess);
|
||||
tvStatistics = (TextView) itemView.findViewById(R.id.tvStatistics);
|
||||
|
||||
final View wifiParent = (View) cbWifi.getParent();
|
||||
|
@ -417,11 +425,26 @@ public class RuleAdapter extends RecyclerView.Adapter<RuleAdapter.ViewHolder> im
|
|||
holder.btnClear.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
holder.cbWifi.setChecked(rule.wifi_default);
|
||||
holder.cbOther.setChecked(rule.other_default);
|
||||
holder.cbScreenWifi.setChecked(rule.screen_wifi_default);
|
||||
holder.cbScreenOther.setChecked(rule.screen_other_default);
|
||||
holder.cbRoaming.setChecked(rule.roaming_default);
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.msg_sure)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
holder.cbWifi.setChecked(rule.wifi_default);
|
||||
holder.cbOther.setChecked(rule.other_default);
|
||||
holder.cbScreenWifi.setChecked(rule.screen_wifi_default);
|
||||
holder.cbScreenOther.setChecked(rule.screen_other_default);
|
||||
holder.cbRoaming.setChecked(rule.roaming_default);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Do nothing
|
||||
}
|
||||
})
|
||||
.create().show();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -447,10 +470,72 @@ public class RuleAdapter extends RecyclerView.Adapter<RuleAdapter.ViewHolder> im
|
|||
});
|
||||
|
||||
if (rule.expanded) {
|
||||
AccessAdapter adapter = new AccessAdapter(context, dh.getAccess(rule.info.applicationInfo.uid));
|
||||
holder.lvAccess.setAdapter(adapter);
|
||||
} else
|
||||
final AccessAdapter badapter = new AccessAdapter(context, dh.getAccess(rule.info.applicationInfo.uid));
|
||||
|
||||
holder.lvAccess.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, final int bposition, long bid) {
|
||||
Cursor cursor = (Cursor) badapter.getItem(bposition);
|
||||
final long id = cursor.getLong(cursor.getColumnIndex("ID"));
|
||||
final String daddr = cursor.getString(cursor.getColumnIndex("daddr"));
|
||||
final int dport = (cursor.isNull(cursor.getColumnIndex("dport")) ? -1 : cursor.getInt(cursor.getColumnIndex("dport")));
|
||||
|
||||
PopupMenu popup = new PopupMenu(context, view);
|
||||
popup.inflate(R.menu.access);
|
||||
popup.getMenu().findItem(R.id.menu_host).setTitle(daddr + (dport > 0 ? ":" + dport : ""));
|
||||
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.menu_allow:
|
||||
dh.setAccess(id, rule.info.applicationInfo.uid, 0);
|
||||
SinkholeService.reload(null, "allow host", context);
|
||||
return true;
|
||||
case R.id.menu_block:
|
||||
dh.setAccess(id, rule.info.applicationInfo.uid, 1);
|
||||
SinkholeService.reload(null, "block host", context);
|
||||
return true;
|
||||
case R.id.menu_clear:
|
||||
dh.setAccess(id, rule.info.applicationInfo.uid, -1);
|
||||
SinkholeService.reload(null, "clear host", context);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
popup.show();
|
||||
}
|
||||
});
|
||||
|
||||
holder.lvAccess.setAdapter(badapter);
|
||||
} else {
|
||||
holder.lvAccess.setAdapter(null);
|
||||
holder.lvAccess.setOnItemClickListener(null);
|
||||
}
|
||||
|
||||
holder.btnClearAccess.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.msg_sure)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dh.clearAccess(rule.info.applicationInfo.uid);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Do nothing
|
||||
}
|
||||
})
|
||||
.create().show();
|
||||
}
|
||||
});
|
||||
|
||||
// Traffic statistics
|
||||
holder.tvStatistics.setText(context.getString(R.string.msg_mbday, rule.upspeed, rule.downspeed));
|
||||
|
|
|
@ -31,6 +31,7 @@ import android.content.IntentFilter;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -74,6 +75,7 @@ import java.util.Date;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -94,8 +96,9 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
private Object subscriptionsChangedListener = null;
|
||||
private ParcelFileDescriptor vpn = null;
|
||||
|
||||
private HashMap<String, Boolean> mapDomainBlocked = new HashMap<>();
|
||||
private HashMap<Integer, Boolean> mapUidAllowed = new HashMap<>();
|
||||
private Map<String, Boolean> mapHostsBlocked = new HashMap<>();
|
||||
private Map<Integer, Boolean> mapUidAllowed = new HashMap<>();
|
||||
private Map<Integer, Map<String, Boolean>> mapUidIPFilters = new HashMap<>();
|
||||
|
||||
private volatile Looper mServiceLooper;
|
||||
private volatile ServiceHandler mServiceHandler;
|
||||
|
@ -649,7 +652,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
if (packet.uid > 0)
|
||||
dh.updateAccess(packet, rr == null ? null : rr.QName);
|
||||
else
|
||||
else if (packet.dport != 53)
|
||||
Log.w(TAG, "Unknown application packet=" + packet);
|
||||
|
||||
dh.close();
|
||||
|
@ -795,8 +798,10 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
Log.i(TAG, "Start native log=" + log + " filter=" + filter);
|
||||
|
||||
// Prepare allowed/blocked lists
|
||||
prepareAllowed(listAllowed);
|
||||
// Prepare rules
|
||||
prepareUidAllowed(listAllowed);
|
||||
prepareHostsBlocked();
|
||||
prepareUidIPFilters();
|
||||
|
||||
if (log || filter) {
|
||||
int prio = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.INFO)));
|
||||
|
@ -809,15 +814,17 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
jni_stop(vpn.getFd(), clear);
|
||||
}
|
||||
|
||||
private void prepareAllowed(List<Rule> listAllowed) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean use_hosts = prefs.getBoolean("use_hosts", false);
|
||||
|
||||
private void prepareUidAllowed(List<Rule> listAllowed) {
|
||||
mapUidAllowed.clear();
|
||||
for (Rule rule : listAllowed)
|
||||
mapUidAllowed.put(rule.info.applicationInfo.uid, true);
|
||||
}
|
||||
|
||||
mapDomainBlocked.clear();
|
||||
private void prepareHostsBlocked() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean use_hosts = prefs.getBoolean("use_hosts", false);
|
||||
|
||||
mapHostsBlocked.clear();
|
||||
if (use_hosts) {
|
||||
File hosts = new File(getFilesDir(), "hosts.txt");
|
||||
BufferedReader br = null;
|
||||
|
@ -832,7 +839,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
if (line.length() > 0) {
|
||||
String[] words = line.split("\\s+");
|
||||
if (words.length == 2)
|
||||
mapDomainBlocked.put(words[1], true);
|
||||
mapHostsBlocked.put(words[1], true);
|
||||
else
|
||||
Log.i(TAG, "Invalid hosts file line: " + line);
|
||||
}
|
||||
|
@ -851,6 +858,42 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
}
|
||||
|
||||
private void prepareUidIPFilters() {
|
||||
mapUidIPFilters.clear();
|
||||
|
||||
DatabaseHelper dh = null;
|
||||
try {
|
||||
dh = new DatabaseHelper(SinkholeService.this);
|
||||
Cursor cursor = dh.getAccess();
|
||||
int colUid = cursor.getColumnIndex("uid");
|
||||
int colDAddr = cursor.getColumnIndex("daddr");
|
||||
int colDPort = cursor.getColumnIndex("dport");
|
||||
int colBlock = cursor.getColumnIndex("block");
|
||||
while (cursor.moveToNext()) {
|
||||
int uid = cursor.getInt(colUid);
|
||||
String daddr = cursor.getString(colDAddr);
|
||||
int dport = cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort);
|
||||
boolean block = (cursor.getInt(colBlock) > 0);
|
||||
if (!mapUidIPFilters.containsKey(uid))
|
||||
mapUidIPFilters.put(uid, new HashMap<String, Boolean>());
|
||||
try {
|
||||
for (InetAddress iaddr : InetAddress.getAllByName(daddr)) {
|
||||
String addr = iaddr.toString() + "/" + dport;
|
||||
addr = addr.substring(addr.indexOf('/') + 1);
|
||||
Log.i(TAG, "Set filter " + daddr + " " + addr + "=" + block);
|
||||
mapUidIPFilters.get(uid).put(addr, block);
|
||||
}
|
||||
} catch (UnknownHostException ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
} finally {
|
||||
dh.close();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Rule> getAllowedRules(List<Rule> listRule) {
|
||||
List<Rule> listAllowed = new ArrayList<>();
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
@ -979,7 +1022,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
// Called from native code
|
||||
private boolean isDomainBlocked(String name) {
|
||||
boolean blocked = (mapDomainBlocked.containsKey(name) && mapDomainBlocked.get(name));
|
||||
boolean blocked = (mapHostsBlocked.containsKey(name) && mapHostsBlocked.get(name));
|
||||
return blocked;
|
||||
}
|
||||
|
||||
|
@ -987,16 +1030,27 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
private boolean isAddressAllowed(Packet packet) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
packet.allowed = false;
|
||||
if (packet.protocol == 6 /* TCP */ || packet.protocol == 17 /* UDP */) {
|
||||
if (prefs.getBoolean("filter", false)) {
|
||||
if (packet.uid <= 0) // unknown, root
|
||||
packet.allowed = true;
|
||||
else
|
||||
packet.allowed = (mapUidAllowed.containsKey(packet.uid) && mapUidAllowed.get(packet.uid));
|
||||
} else
|
||||
packet.allowed = false;
|
||||
} else
|
||||
packet.allowed = false;
|
||||
else {
|
||||
boolean filtered = false;
|
||||
if (mapUidIPFilters.containsKey(packet.uid)) {
|
||||
String addr = packet.daddr + "/" + packet.dport;
|
||||
if (mapUidIPFilters.get(packet.uid).containsKey(addr)) {
|
||||
filtered = true;
|
||||
packet.allowed = !mapUidIPFilters.get(packet.uid).get(addr);
|
||||
Log.i(TAG, "Filtering " + addr + " allowed=" + packet.allowed);
|
||||
}
|
||||
}
|
||||
|
||||
if (!filtered)
|
||||
packet.allowed = (mapUidAllowed.containsKey(packet.uid) && mapUidAllowed.get(packet.uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prefs.getBoolean("log", false))
|
||||
logPacket(packet);
|
||||
|
|
|
@ -1220,6 +1220,8 @@ void handle_ip(const struct arguments *args, const uint8_t *pkt, const size_t le
|
|||
else if (protocol == IPPROTO_TCP)
|
||||
handle_tcp(args, pkt, length, payload, uid);
|
||||
}
|
||||
else
|
||||
log_android(ANDROID_LOG_DEBUG, "Address %s/%u syn %d not allowed", dest, dport, syn);
|
||||
|
||||
#ifdef PROFILE_EVENTS
|
||||
gettimeofday(&end, NULL);
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ip_allowed" android:state_checked="true" />
|
||||
<item android:drawable="@drawable/ip_blocked" android:state_checked="false" />
|
||||
</selector>
|
|
@ -14,15 +14,11 @@
|
|||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbBlock"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:button="@drawable/ip"
|
||||
android:scaleX="0.8"
|
||||
android:scaleY="0.8" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBlock"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDest"
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingEnd="@dimen/activity_horizontal_margin"
|
||||
android:paddingStart="@dimen/activity_horizontal_margin"
|
||||
|
|
|
@ -180,6 +180,13 @@
|
|||
android:textStyle="italic"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_conditions"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Title" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llWifiAttr"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -279,6 +286,13 @@
|
|||
android:text="@string/title_launch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_access"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Title" />
|
||||
|
||||
<eu.faircode.netguard.ExpandedListView
|
||||
android:id="@+id/lvAccess"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -286,9 +300,32 @@
|
|||
android:layout_marginTop="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvStatistics"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp" />
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/title_precedence"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textStyle="italic" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnClearAccess"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_delete_white_24dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvStatistics"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="8dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
16
app/src/main/res/menu/access.xml
Normal file
16
app/src/main/res/menu/access.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/menu_host"
|
||||
android:enabled="false"
|
||||
android:title="" />
|
||||
<item
|
||||
android:id="@+id/menu_allow"
|
||||
android:title="@string/title_allow" />
|
||||
<item
|
||||
android:id="@+id/menu_block"
|
||||
android:title="@string/title_block" />
|
||||
<item
|
||||
android:id="@+id/menu_clear"
|
||||
android:title="@string/menu_clear" />
|
||||
</menu>
|
|
@ -116,12 +116,15 @@ Since NetGuard has no internet permission, you know your internet traffic is not
|
|||
<string name="msg_filter">Using filtering will cause Android to attribute data and power usage to NetGuard - Android assumes the data and power are being used by NetGuard, rather than the original applications</string>
|
||||
<string name="msg_log_disabled">Traffic logging is disabled, use the switch above to enable logging. Traffic logging might result in extra battery usage.</string>
|
||||
|
||||
<string name="title_conditions">Conditions</string>
|
||||
<string name="title_screen_wifi">Allow Wi-Fi when screen is on</string>
|
||||
<string name="title_screen_other">Allow mobile when screen is on</string>
|
||||
<string name="title_roaming">Block when roaming</string>
|
||||
<string name="title_disabled">is disabled</string>
|
||||
<string name="title_internet">has no internet permission</string>
|
||||
<string name="title_launch">Start application</string>
|
||||
<string name="title_access">Access</string>
|
||||
<string name="title_precedence">Access rules take precedence over other rules</string>
|
||||
<string name="title_rate">Rate</string>
|
||||
<string name="title_allow">Allow</string>
|
||||
<string name="title_block">Block</string>
|
||||
|
|
Loading…
Reference in a new issue