forked from beau/relab
371 lines
14 KiB
Java
371 lines
14 KiB
Java
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-2019 by Marcel Bokhorst (M66B)
|
|
*/
|
|
|
|
import android.content.Context;
|
|
import android.content.SharedPreferences;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.database.Cursor;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import android.os.AsyncTask;
|
|
import android.os.Build;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.util.TypedValue;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.CursorAdapter;
|
|
import android.widget.ImageView;
|
|
import android.widget.TextView;
|
|
|
|
import androidx.core.graphics.drawable.DrawableCompat;
|
|
import androidx.core.view.ViewCompat;
|
|
import androidx.preference.PreferenceManager;
|
|
|
|
import java.net.InetAddress;
|
|
import java.net.UnknownHostException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.List;
|
|
|
|
public class AdapterLog extends CursorAdapter {
|
|
private static String TAG = "NetGuard.Log";
|
|
|
|
private boolean resolve;
|
|
private boolean organization;
|
|
private int colTime;
|
|
private int colVersion;
|
|
private int colProtocol;
|
|
private int colFlags;
|
|
private int colSAddr;
|
|
private int colSPort;
|
|
private int colDAddr;
|
|
private int colDPort;
|
|
private int colDName;
|
|
private int colUid;
|
|
private int colData;
|
|
private int colAllowed;
|
|
private int colConnection;
|
|
private int colInteractive;
|
|
private int colorOn;
|
|
private int colorOff;
|
|
private int iconSize;
|
|
private InetAddress dns1 = null;
|
|
private InetAddress dns2 = null;
|
|
private InetAddress vpn4 = null;
|
|
private InetAddress vpn6 = null;
|
|
|
|
public AdapterLog(Context context, Cursor cursor, boolean resolve, boolean organization) {
|
|
super(context, cursor, 0);
|
|
this.resolve = resolve;
|
|
this.organization = organization;
|
|
colTime = cursor.getColumnIndex("time");
|
|
colVersion = cursor.getColumnIndex("version");
|
|
colProtocol = cursor.getColumnIndex("protocol");
|
|
colFlags = cursor.getColumnIndex("flags");
|
|
colSAddr = cursor.getColumnIndex("saddr");
|
|
colSPort = cursor.getColumnIndex("sport");
|
|
colDAddr = cursor.getColumnIndex("daddr");
|
|
colDPort = cursor.getColumnIndex("dport");
|
|
colDName = cursor.getColumnIndex("dname");
|
|
colUid = cursor.getColumnIndex("uid");
|
|
colData = cursor.getColumnIndex("data");
|
|
colAllowed = cursor.getColumnIndex("allowed");
|
|
colConnection = cursor.getColumnIndex("connection");
|
|
colInteractive = cursor.getColumnIndex("interactive");
|
|
|
|
TypedValue tv = new TypedValue();
|
|
context.getTheme().resolveAttribute(R.attr.colorOn, tv, true);
|
|
colorOn = tv.data;
|
|
context.getTheme().resolveAttribute(R.attr.colorOff, tv, true);
|
|
colorOff = tv.data;
|
|
|
|
iconSize = Util.dips2pixels(24, context);
|
|
|
|
try {
|
|
List<InetAddress> lstDns = ServiceSinkhole.getDns(context);
|
|
dns1 = (lstDns.size() > 0 ? lstDns.get(0) : null);
|
|
dns2 = (lstDns.size() > 1 ? lstDns.get(1) : null);
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
vpn4 = InetAddress.getByName(prefs.getString("vpn4", "10.1.10.1"));
|
|
vpn6 = InetAddress.getByName(prefs.getString("vpn6", "fd00:1:fd00:1:fd00:1:fd00:1"));
|
|
} catch (UnknownHostException ex) {
|
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
}
|
|
}
|
|
|
|
public void setResolve(boolean resolve) {
|
|
this.resolve = resolve;
|
|
}
|
|
|
|
public void setOrganization(boolean organization) {
|
|
this.organization = organization;
|
|
}
|
|
|
|
@Override
|
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
|
return LayoutInflater.from(context).inflate(R.layout.log, parent, false);
|
|
}
|
|
|
|
@Override
|
|
public void bindView(final View view, final Context context, final Cursor cursor) {
|
|
// Get values
|
|
long time = cursor.getLong(colTime);
|
|
int version = (cursor.isNull(colVersion) ? -1 : cursor.getInt(colVersion));
|
|
int protocol = (cursor.isNull(colProtocol) ? -1 : cursor.getInt(colProtocol));
|
|
String flags = cursor.getString(colFlags);
|
|
String saddr = cursor.getString(colSAddr);
|
|
int sport = (cursor.isNull(colSPort) ? -1 : cursor.getInt(colSPort));
|
|
String daddr = cursor.getString(colDAddr);
|
|
int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
|
|
String dname = (cursor.isNull(colDName) ? null : cursor.getString(colDName));
|
|
int uid = (cursor.isNull(colUid) ? -1 : cursor.getInt(colUid));
|
|
String data = cursor.getString(colData);
|
|
int allowed = (cursor.isNull(colAllowed) ? -1 : cursor.getInt(colAllowed));
|
|
int connection = (cursor.isNull(colConnection) ? -1 : cursor.getInt(colConnection));
|
|
int interactive = (cursor.isNull(colInteractive) ? -1 : cursor.getInt(colInteractive));
|
|
|
|
// Get views
|
|
TextView tvTime = view.findViewById(R.id.tvTime);
|
|
TextView tvProtocol = view.findViewById(R.id.tvProtocol);
|
|
TextView tvFlags = view.findViewById(R.id.tvFlags);
|
|
TextView tvSAddr = view.findViewById(R.id.tvSAddr);
|
|
TextView tvSPort = view.findViewById(R.id.tvSPort);
|
|
final TextView tvDaddr = view.findViewById(R.id.tvDAddr);
|
|
TextView tvDPort = view.findViewById(R.id.tvDPort);
|
|
final TextView tvOrganization = view.findViewById(R.id.tvOrganization);
|
|
final ImageView ivIcon = view.findViewById(R.id.ivIcon);
|
|
TextView tvUid = view.findViewById(R.id.tvUid);
|
|
TextView tvData = view.findViewById(R.id.tvData);
|
|
ImageView ivConnection = view.findViewById(R.id.ivConnection);
|
|
ImageView ivInteractive = view.findViewById(R.id.ivInteractive);
|
|
|
|
// Show time
|
|
tvTime.setText(new SimpleDateFormat("HH:mm:ss").format(time));
|
|
|
|
// Show connection type
|
|
if (connection <= 0)
|
|
ivConnection.setImageResource(allowed > 0 ? R.drawable.host_allowed : R.drawable.host_blocked);
|
|
else {
|
|
if (allowed > 0)
|
|
ivConnection.setImageResource(connection == 1 ? R.drawable.wifi_on : R.drawable.other_on);
|
|
else
|
|
ivConnection.setImageResource(connection == 1 ? R.drawable.wifi_off : R.drawable.other_off);
|
|
}
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
Drawable wrap = DrawableCompat.wrap(ivConnection.getDrawable());
|
|
DrawableCompat.setTint(wrap, allowed > 0 ? colorOn : colorOff);
|
|
}
|
|
|
|
// Show if screen on
|
|
if (interactive <= 0)
|
|
ivInteractive.setImageDrawable(null);
|
|
else {
|
|
ivInteractive.setImageResource(R.drawable.screen_on);
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
Drawable wrap = DrawableCompat.wrap(ivInteractive.getDrawable());
|
|
DrawableCompat.setTint(wrap, colorOn);
|
|
}
|
|
}
|
|
|
|
// Show protocol name
|
|
tvProtocol.setText(Util.getProtocolName(protocol, version, false));
|
|
|
|
// SHow TCP flags
|
|
tvFlags.setText(flags);
|
|
tvFlags.setVisibility(TextUtils.isEmpty(flags) ? View.GONE : View.VISIBLE);
|
|
|
|
// Show source and destination port
|
|
if (protocol == 6 || protocol == 17) {
|
|
tvSPort.setText(sport < 0 ? "" : getKnownPort(sport));
|
|
tvDPort.setText(dport < 0 ? "" : getKnownPort(dport));
|
|
} else {
|
|
tvSPort.setText(sport < 0 ? "" : Integer.toString(sport));
|
|
tvDPort.setText(dport < 0 ? "" : Integer.toString(dport));
|
|
}
|
|
|
|
// Application icon
|
|
ApplicationInfo info = null;
|
|
PackageManager pm = context.getPackageManager();
|
|
String[] pkg = pm.getPackagesForUid(uid);
|
|
if (pkg != null && pkg.length > 0)
|
|
try {
|
|
info = pm.getApplicationInfo(pkg[0], 0);
|
|
} catch (PackageManager.NameNotFoundException ignored) {
|
|
}
|
|
|
|
if (info == null)
|
|
ivIcon.setImageDrawable(null);
|
|
else {
|
|
if (info.icon <= 0)
|
|
ivIcon.setImageResource(android.R.drawable.sym_def_app_icon);
|
|
else {
|
|
Uri uri = Uri.parse("android.resource://" + info.packageName + "/" + info.icon);
|
|
GlideApp.with(context)
|
|
.load(uri)
|
|
//.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
//.skipMemoryCache(true)
|
|
.override(iconSize, iconSize)
|
|
.into(ivIcon);
|
|
}
|
|
}
|
|
|
|
boolean we = (android.os.Process.myUid() == uid);
|
|
|
|
// https://android.googlesource.com/platform/system/core/+/master/include/private/android_filesystem_config.h
|
|
uid = uid % 100000; // strip off user ID
|
|
if (uid == -1)
|
|
tvUid.setText("");
|
|
else if (uid == 0)
|
|
tvUid.setText(context.getString(R.string.title_root));
|
|
else if (uid == 9999)
|
|
tvUid.setText("-"); // nobody
|
|
else
|
|
tvUid.setText(Integer.toString(uid));
|
|
|
|
// Show source address
|
|
tvSAddr.setText(getKnownAddress(saddr));
|
|
|
|
// Show destination address
|
|
if (!we && resolve && !isKnownAddress(daddr))
|
|
if (dname == null) {
|
|
tvDaddr.setText(daddr);
|
|
new AsyncTask<String, Object, String>() {
|
|
@Override
|
|
protected void onPreExecute() {
|
|
ViewCompat.setHasTransientState(tvDaddr, true);
|
|
}
|
|
|
|
@Override
|
|
protected String doInBackground(String... args) {
|
|
try {
|
|
return InetAddress.getByName(args[0]).getHostName();
|
|
} catch (UnknownHostException ignored) {
|
|
return args[0];
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(String name) {
|
|
tvDaddr.setText(">" + name);
|
|
ViewCompat.setHasTransientState(tvDaddr, false);
|
|
}
|
|
}.execute(daddr);
|
|
} else
|
|
tvDaddr.setText(dname);
|
|
else
|
|
tvDaddr.setText(getKnownAddress(daddr));
|
|
|
|
// Show organization
|
|
tvOrganization.setVisibility(View.GONE);
|
|
if (!we && organization) {
|
|
if (!isKnownAddress(daddr))
|
|
new AsyncTask<String, Object, String>() {
|
|
@Override
|
|
protected void onPreExecute() {
|
|
ViewCompat.setHasTransientState(tvOrganization, true);
|
|
}
|
|
|
|
@Override
|
|
protected String doInBackground(String... args) {
|
|
try {
|
|
return Util.getOrganization(args[0]);
|
|
} catch (Throwable ex) {
|
|
Log.w(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(String organization) {
|
|
if (organization != null) {
|
|
tvOrganization.setText(organization);
|
|
tvOrganization.setVisibility(View.VISIBLE);
|
|
}
|
|
ViewCompat.setHasTransientState(tvOrganization, false);
|
|
}
|
|
}.execute(daddr);
|
|
}
|
|
|
|
// Show extra data
|
|
if (TextUtils.isEmpty(data)) {
|
|
tvData.setText("");
|
|
tvData.setVisibility(View.GONE);
|
|
} else {
|
|
tvData.setText(data);
|
|
tvData.setVisibility(View.VISIBLE);
|
|
}
|
|
}
|
|
|
|
public boolean isKnownAddress(String addr) {
|
|
try {
|
|
InetAddress a = InetAddress.getByName(addr);
|
|
if (a.equals(dns1) || a.equals(dns2) || a.equals(vpn4) || a.equals(vpn6))
|
|
return true;
|
|
} catch (UnknownHostException ignored) {
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private String getKnownAddress(String addr) {
|
|
try {
|
|
InetAddress a = InetAddress.getByName(addr);
|
|
if (a.equals(dns1))
|
|
return "dns1";
|
|
if (a.equals(dns2))
|
|
return "dns2";
|
|
if (a.equals(vpn4) || a.equals(vpn6))
|
|
return "vpn";
|
|
} catch (UnknownHostException ignored) {
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
private String getKnownPort(int port) {
|
|
// https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports
|
|
switch (port) {
|
|
case 7:
|
|
return "echo";
|
|
case 25:
|
|
return "smtp";
|
|
case 53:
|
|
return "dns";
|
|
case 80:
|
|
return "http";
|
|
case 110:
|
|
return "pop3";
|
|
case 143:
|
|
return "imap";
|
|
case 443:
|
|
return "https";
|
|
case 465:
|
|
return "smtps";
|
|
case 993:
|
|
return "imaps";
|
|
case 995:
|
|
return "pop3s";
|
|
default:
|
|
return Integer.toString(port);
|
|
}
|
|
}
|
|
}
|