mirror of
https://github.com/M66B/NetGuard.git
synced 2025-01-03 05:44:14 +00:00
Added malware protection
This commit is contained in:
parent
658ea3df84
commit
5003849260
5 changed files with 148 additions and 9 deletions
|
@ -73,6 +73,9 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class ActivityMain extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
@ -111,6 +114,8 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences
|
|||
public static final String EXTRA_METERED = "Metered";
|
||||
public static final String EXTRA_SIZE = "Size";
|
||||
|
||||
private static final String MALWARE_URL = "https://urlhaus.abuse.ch/downloads/hostfile/";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "Create version=" + Util.getSelfVersionName(this) + "/" + Util.getSelfVersionCode(this));
|
||||
|
@ -858,6 +863,7 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences
|
|||
menu.findItem(R.id.menu_sort_name).setChecked(true);
|
||||
|
||||
menu.findItem(R.id.menu_lockdown).setChecked(prefs.getBoolean("lockdown", false));
|
||||
menu.findItem(R.id.menu_malware).setChecked(prefs.getBoolean("malware", false));
|
||||
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
@ -903,6 +909,10 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences
|
|||
menu_lockdown(item);
|
||||
return true;
|
||||
|
||||
case R.id.menu_malware:
|
||||
menu_malware(item);
|
||||
return true;
|
||||
|
||||
case R.id.menu_log:
|
||||
if (Util.canFilter(this))
|
||||
if (IAB.isPurchased(ActivityPro.SKU_LOG, this))
|
||||
|
@ -1198,6 +1208,42 @@ public class ActivityMain extends AppCompatActivity implements SharedPreferences
|
|||
WidgetLockdown.updateWidgets(this);
|
||||
}
|
||||
|
||||
private void menu_malware(MenuItem item) {
|
||||
item.setChecked(!item.isChecked());
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefs.edit().putBoolean("malware", item.isChecked()).apply();
|
||||
if (item.isChecked())
|
||||
try {
|
||||
final File file = new File(getFilesDir(), "malware.txt");
|
||||
new DownloadTask(this, new URL(MALWARE_URL), file, new DownloadTask.Listener() {
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
prefs.edit().putBoolean("filter", true).apply();
|
||||
ServiceSinkhole.reload("malware download", ActivityMain.this, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled() {
|
||||
prefs.edit().putBoolean("malware", false).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable ex) {
|
||||
Toast.makeText(ActivityMain.this, ex.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} catch (MalformedURLException ex) {
|
||||
Toast.makeText(this, ex.toString(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
else {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
for (String key : prefs.getAll().keySet())
|
||||
if (key.startsWith("malware."))
|
||||
editor.remove(key);
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
private void menu_about() {
|
||||
// Create view
|
||||
LayoutInflater inflater = LayoutInflater.from(this);
|
||||
|
|
|
@ -74,5 +74,10 @@ public class ApplicationEx extends Application {
|
|||
access.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
access.setBypassDnd(true);
|
||||
nm.createNotificationChannel(access);
|
||||
|
||||
NotificationChannel malware = new NotificationChannel("malware", getString(R.string.setting_malware), NotificationManager.IMPORTANCE_HIGH);
|
||||
malware.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
malware.setBypassDnd(true);
|
||||
nm.createNotificationChannel(malware);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,9 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
private boolean temporarilyStopped = false;
|
||||
|
||||
private long last_hosts_modified = 0;
|
||||
private long last_malware_modified = 0;
|
||||
private Map<String, Boolean> mapHostsBlocked = new HashMap<>();
|
||||
private Map<String, Boolean> mapMalware = new HashMap<>();
|
||||
private Map<Integer, Boolean> mapUidAllowed = new HashMap<>();
|
||||
private Map<Integer, Integer> mapUidKnown = new HashMap<>();
|
||||
private final Map<IPKey, Map<InetAddress, IPRule>> mapUidIPFilters = new HashMap<>();
|
||||
|
@ -1471,6 +1473,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
if (filter) {
|
||||
prepareUidAllowed(listAllowed, listRule);
|
||||
prepareHostsBlocked();
|
||||
prepareMalwareList();
|
||||
prepareUidIPFilters(null);
|
||||
prepareForwarding();
|
||||
} else {
|
||||
|
@ -1478,6 +1481,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
mapUidAllowed.clear();
|
||||
mapUidKnown.clear();
|
||||
mapHostsBlocked.clear();
|
||||
mapMalware.clear();
|
||||
mapUidIPFilters.clear();
|
||||
mapForward.clear();
|
||||
lock.writeLock().unlock();
|
||||
|
@ -1555,6 +1559,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
mapUidAllowed.clear();
|
||||
mapUidKnown.clear();
|
||||
mapHostsBlocked.clear();
|
||||
mapMalware.clear();
|
||||
mapUidIPFilters.clear();
|
||||
mapForward.clear();
|
||||
mapNotify.clear();
|
||||
|
@ -1633,6 +1638,63 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
private void prepareMalwareList() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSinkhole.this);
|
||||
boolean malware = prefs.getBoolean("filter", false) && prefs.getBoolean("malware", false);
|
||||
File file = new File(getFilesDir(), "malware.txt");
|
||||
if (!malware || !file.exists() || !file.canRead()) {
|
||||
Log.i(TAG, "Malware use=" + malware + " exists=" + file.exists());
|
||||
lock.writeLock().lock();
|
||||
mapMalware.clear();
|
||||
lock.writeLock().unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean changed = (file.lastModified() != last_malware_modified);
|
||||
if (!changed && mapMalware.size() > 0) {
|
||||
Log.i(TAG, "Malware unchanged");
|
||||
return;
|
||||
}
|
||||
last_malware_modified = file.lastModified();
|
||||
|
||||
lock.writeLock().lock();
|
||||
|
||||
mapMalware.clear();
|
||||
|
||||
int count = 0;
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(file));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
int hash = line.indexOf('#');
|
||||
if (hash >= 0)
|
||||
line = line.substring(0, hash);
|
||||
line = line.trim();
|
||||
if (line.length() > 0) {
|
||||
String[] words = line.split("\\s+");
|
||||
if (words.length > 1) {
|
||||
count++;
|
||||
mapMalware.put(words[1], true);
|
||||
} else
|
||||
Log.i(TAG, "Invalid malware file line: " + line);
|
||||
}
|
||||
}
|
||||
Log.i(TAG, count + " malware read");
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
} finally {
|
||||
if (br != null)
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException exex) {
|
||||
Log.e(TAG, exex.toString() + "\n" + Log.getStackTraceString(exex));
|
||||
}
|
||||
}
|
||||
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
private void prepareUidIPFilters(String dname) {
|
||||
SharedPreferences lockdown = getSharedPreferences("lockdown", Context.MODE_PRIVATE);
|
||||
|
||||
|
@ -1884,6 +1946,20 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
Log.i(TAG, "New IP " + rr);
|
||||
prepareUidIPFilters(rr.QName);
|
||||
}
|
||||
if (rr.uid > 0 && !TextUtils.isEmpty(rr.AName)) {
|
||||
lock.readLock().lock();
|
||||
boolean malware = (mapMalware.containsKey(rr.AName) && mapMalware.get(rr.AName));
|
||||
lock.readLock().unlock();
|
||||
|
||||
if (malware) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean notified = prefs.getBoolean("malware." + rr.uid, false);
|
||||
if (!notified) {
|
||||
prefs.edit().putBoolean("malware." + rr.uid, true).apply();
|
||||
notifyNewApplication(rr.uid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called from native code
|
||||
|
@ -2257,7 +2333,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (IAB.isPurchased(ActivityPro.SKU_NOTIFY, context) && prefs.getBoolean("install", true)) {
|
||||
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||
notifyNewApplication(uid);
|
||||
notifyNewApplication(uid, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2299,7 +2375,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
};
|
||||
|
||||
public void notifyNewApplication(int uid) {
|
||||
public void notifyNewApplication(int uid, boolean malware) {
|
||||
if (uid < 0)
|
||||
return;
|
||||
|
||||
|
@ -2323,18 +2399,24 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
TypedValue tv = new TypedValue();
|
||||
getTheme().resolveAttribute(R.attr.colorPrimary, tv, true);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "notify");
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
|
||||
malware ? "malware" : "notify");
|
||||
builder.setSmallIcon(R.drawable.ic_security_white_24dp)
|
||||
.setContentIntent(pi)
|
||||
.setColor(tv.data)
|
||||
.setAutoCancel(true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
if (malware)
|
||||
builder.setContentTitle(name)
|
||||
.setContentText(getString(R.string.msg_installed_n));
|
||||
else
|
||||
builder.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText(getString(R.string.msg_installed, name));
|
||||
.setContentText(getString(R.string.msg_malware, name));
|
||||
else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
builder.setContentTitle(name)
|
||||
.setContentText(getString(R.string.msg_installed_n));
|
||||
else
|
||||
builder.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText(getString(R.string.msg_installed, name));
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_STATUS)
|
||||
|
@ -2696,7 +2778,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
|
|||
ServiceSinkhole.reload("notification", ServiceSinkhole.this, false);
|
||||
|
||||
// Update notification
|
||||
notifyNewApplication(uid);
|
||||
notifyNewApplication(uid, false);
|
||||
|
||||
// Update UI
|
||||
Intent ruleset = new Intent(ActivityMain.ACTION_RULES_CHANGED);
|
||||
|
|
|
@ -51,6 +51,10 @@
|
|||
android:id="@+id/menu_lockdown"
|
||||
android:checkable="true"
|
||||
android:title="@string/setting_lockdown"/>
|
||||
<item
|
||||
android:id="@+id/menu_malware"
|
||||
android:checkable="true"
|
||||
android:title="@string/setting_malware"/>
|
||||
<item
|
||||
android:id="@+id/menu_log"
|
||||
android:title="@string/menu_log"/>
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
<string name="setting_handover">Seamless VPN handover on reload</string>
|
||||
<string name="setting_clear_onreload">Close connections on reload</string>
|
||||
<string name="setting_lockdown">Lockdown traffic</string>
|
||||
<string name="setting_malware">Malware protection</string>
|
||||
<string name="setting_track_usage">Track network usage</string>
|
||||
<string name="setting_reset_usage">Reset network usage</string>
|
||||
<string name="setting_show_resolved">Show resolved domain names</string>
|
||||
|
@ -184,6 +185,7 @@
|
|||
<string name="msg_revoked">NetGuard has been disabled, likely by using another VPN based app</string>
|
||||
<string name="msg_installed">\'%1$s\' installed</string>
|
||||
<string name="msg_installed_n">Has been installed</string>
|
||||
<string name="msg_malware">Possible malware: \'%1$s\'</string>
|
||||
<string name="msg_access">%1$s attempted internet access</string>
|
||||
<string name="msg_access_n">Attempted internet access</string>
|
||||
<string name="msg_completed">Action completed</string>
|
||||
|
|
Loading…
Reference in a new issue