mirror of https://github.com/M66B/NetGuard.git
Native added source to traffic logging, added switch to enable host name resolving
This commit is contained in:
parent
8cad00d2b1
commit
33845fd733
|
@ -24,9 +24,10 @@
|
|||
-keepnames class eu.faircode.netguard.** { *; }
|
||||
|
||||
#JNI callback
|
||||
-keep class eu.faircode.netguard.Packet { *; }
|
||||
-keep class eu.faircode.netguard.SinkholeService {
|
||||
void selectExit(boolean);
|
||||
void logPacket(long, int, java.lang.String, int, int, java.lang.String, int, boolean);
|
||||
void logPacket(eu.faircode.netguard.Packet);
|
||||
}
|
||||
|
||||
#Support library
|
||||
|
|
|
@ -56,6 +56,7 @@ public class ActivityLog extends AppCompatActivity {
|
|||
private LogAdapter adapter;
|
||||
private DatabaseHelper dh;
|
||||
private boolean live;
|
||||
private boolean resolve;
|
||||
|
||||
private static final int REQUEST_PCAP = 1;
|
||||
|
||||
|
@ -80,10 +81,13 @@ public class ActivityLog extends AppCompatActivity {
|
|||
getSupportActionBar().setTitle(R.string.menu_log);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
resolve = prefs.getBoolean("resolve", false);
|
||||
|
||||
lvLog = (ListView) findViewById(R.id.lvLog);
|
||||
|
||||
dh = new DatabaseHelper(this);
|
||||
adapter = new LogAdapter(this, dh.getLog());
|
||||
adapter = new LogAdapter(this, dh.getLog(), resolve);
|
||||
lvLog.setAdapter(adapter);
|
||||
|
||||
lvLog.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
|
@ -180,11 +184,13 @@ public class ActivityLog extends AppCompatActivity {
|
|||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean log = prefs.getBoolean("log", false);
|
||||
boolean resolve = prefs.getBoolean("resolve", false);
|
||||
boolean filter = prefs.getBoolean("filter", false);
|
||||
boolean pcap = prefs.getBoolean("pcap", false);
|
||||
boolean export = (getPackageManager().resolveActivity(getIntentPCAPDocument(), 0) != null);
|
||||
|
||||
menu.findItem(R.id.menu_log_enabled).setChecked(log);
|
||||
menu.findItem(R.id.menu_log_resolve).setChecked(resolve);
|
||||
menu.findItem(R.id.menu_pcap_enabled).setChecked(pcap);
|
||||
menu.findItem(R.id.menu_pcap_enabled).setEnabled(log || filter);
|
||||
menu.findItem(R.id.menu_pcap_export).setEnabled(pcap && export);
|
||||
|
@ -213,6 +219,14 @@ public class ActivityLog extends AppCompatActivity {
|
|||
DatabaseHelper.removeLocationChangedListener(listener);
|
||||
return true;
|
||||
|
||||
case R.id.menu_log_resolve:
|
||||
item.setChecked(!item.isChecked());
|
||||
resolve = item.isChecked();
|
||||
prefs.edit().putBoolean("resolve", resolve).apply();
|
||||
adapter = new LogAdapter(this, dh.getLog(), resolve);
|
||||
lvLog.setAdapter(adapter);
|
||||
return true;
|
||||
|
||||
case R.id.menu_log_clear:
|
||||
dh.clear();
|
||||
if (!live) {
|
||||
|
|
|
@ -15,7 +15,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
private static final String TAG = "NetGuard.Database";
|
||||
|
||||
private static final String DB_NAME = "Netguard";
|
||||
private static final int DB_VERSION = 6;
|
||||
private static final int DB_VERSION = 7;
|
||||
|
||||
private static List<LogChangedListener> logChangedListeners = new ArrayList<LogChangedListener>();
|
||||
|
||||
|
@ -37,16 +37,20 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
" ID INTEGER PRIMARY KEY AUTOINCREMENT" +
|
||||
", time INTEGER NOT NULL" +
|
||||
", version INTEGER NULL" +
|
||||
", ip TEXT" +
|
||||
", protocol INTEGER NULL" +
|
||||
", port INTEGER NULL" +
|
||||
", flags TEXT" +
|
||||
", saddr TEXT" +
|
||||
", sport INTEGER NULL" +
|
||||
", daddr TEXT" +
|
||||
", dport INTEGER NULL" +
|
||||
", uid INTEGER NULL" +
|
||||
", allowed INTEGER NULL" +
|
||||
", connection INTEGER NULL" +
|
||||
", interactive INTEGER NULL" +
|
||||
", allowed INTEGER NULL" +
|
||||
");");
|
||||
db.execSQL("CREATE INDEX idx_log_time ON log(time)");
|
||||
db.execSQL("CREATE INDEX idx_log_source ON log(saddr, sport)");
|
||||
db.execSQL("CREATE INDEX idx_log_dest ON log(daddr, dport)");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,6 +82,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
db.execSQL("ALTER TABLE log ADD COLUMN allowed INTEGER NULL");
|
||||
oldVersion = 6;
|
||||
}
|
||||
if (oldVersion < 7) {
|
||||
db.execSQL("DROP TABLE log");
|
||||
createTableLog(db);
|
||||
oldVersion = 7;
|
||||
}
|
||||
|
||||
db.setVersion(DB_VERSION);
|
||||
|
||||
|
@ -91,45 +100,42 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
// Location
|
||||
|
||||
public DatabaseHelper insertLog(
|
||||
long time,
|
||||
int version,
|
||||
String ip,
|
||||
int protocol,
|
||||
int port,
|
||||
String flags,
|
||||
int uid,
|
||||
int connection,
|
||||
boolean interactive,
|
||||
boolean allowed) {
|
||||
public DatabaseHelper insertLog(Packet packet, int connection, boolean interactive) {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("time", time);
|
||||
cv.put("version", version);
|
||||
cv.put("ip", ip);
|
||||
cv.put("time", packet.time);
|
||||
cv.put("version", packet.version);
|
||||
|
||||
if (protocol < 0)
|
||||
if (packet.protocol < 0)
|
||||
cv.putNull("protocol");
|
||||
else
|
||||
cv.put("protocol", protocol);
|
||||
cv.put("protocol", packet.protocol);
|
||||
|
||||
if (port < 0)
|
||||
cv.putNull("port");
|
||||
cv.put("flags", packet.flags);
|
||||
|
||||
cv.put("saddr", packet.saddr);
|
||||
if (packet.sport < 0)
|
||||
cv.putNull("sport");
|
||||
else
|
||||
cv.put("port", port);
|
||||
cv.put("sport", packet.sport);
|
||||
|
||||
cv.put("flags", flags);
|
||||
cv.put("daddr", packet.daddr);
|
||||
if (packet.dport < 0)
|
||||
cv.putNull("dport");
|
||||
else
|
||||
cv.put("dport", packet.dport);
|
||||
|
||||
if (uid < 0)
|
||||
if (packet.uid < 0)
|
||||
cv.putNull("uid");
|
||||
else
|
||||
cv.put("uid", uid);
|
||||
cv.put("uid", packet.uid);
|
||||
|
||||
cv.put("allowed", packet.allowed ? 1 : 0);
|
||||
|
||||
cv.put("connection", connection);
|
||||
cv.put("interactive", interactive ? 1 : 0);
|
||||
cv.put("allowed", allowed ? 1 : 0);
|
||||
|
||||
if (db.insert("log", null, cv) == -1)
|
||||
Log.e(TAG, "Insert log failed");
|
||||
|
|
|
@ -22,30 +22,36 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public class LogAdapter extends CursorAdapter {
|
||||
private boolean resolve;
|
||||
private int colTime;
|
||||
private int colVersion;
|
||||
private int colIP;
|
||||
private int colProtocol;
|
||||
private int colPort;
|
||||
private int colFlags;
|
||||
private int colSource;
|
||||
private int colSPort;
|
||||
private int colDest;
|
||||
private int colDPort;
|
||||
private int colUid;
|
||||
private int colAllowed;
|
||||
private int colConnection;
|
||||
private int colInteractive;
|
||||
private int colAllowed;
|
||||
private Map<String, String> mapIPHost = new HashMap<String, String>();
|
||||
|
||||
public LogAdapter(Context context, Cursor cursor) {
|
||||
public LogAdapter(Context context, Cursor cursor, boolean resolve) {
|
||||
super(context, cursor, 0);
|
||||
this.resolve = resolve;
|
||||
colTime = cursor.getColumnIndex("time");
|
||||
colVersion = cursor.getColumnIndex("version");
|
||||
colIP = cursor.getColumnIndex("ip");
|
||||
colProtocol = cursor.getColumnIndex("protocol");
|
||||
colPort = cursor.getColumnIndex("port");
|
||||
colFlags = cursor.getColumnIndex("flags");
|
||||
colSource = cursor.getColumnIndex("saddr");
|
||||
colSPort = cursor.getColumnIndex("sport");
|
||||
colDest = cursor.getColumnIndex("daddr");
|
||||
colDPort = cursor.getColumnIndex("dport");
|
||||
colUid = cursor.getColumnIndex("uid");
|
||||
colAllowed = cursor.getColumnIndex("allowed");
|
||||
colConnection = cursor.getColumnIndex("connection");
|
||||
colInteractive = cursor.getColumnIndex("interactive");
|
||||
colAllowed = cursor.getColumnIndex("allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,27 +64,29 @@ public class LogAdapter extends CursorAdapter {
|
|||
// Get values
|
||||
long time = cursor.getLong(colTime);
|
||||
int version = (cursor.isNull(colVersion) ? -1 : cursor.getInt(colVersion));
|
||||
String ip = cursor.getString(colIP);
|
||||
int protocol = (cursor.isNull(colProtocol) ? -1 : cursor.getInt(colProtocol));
|
||||
int port = (cursor.isNull(colPort) ? -1 : cursor.getInt(colPort));
|
||||
String flags = cursor.getString(colFlags);
|
||||
String source = cursor.getString(colSource);
|
||||
int sport = (cursor.isNull(colSPort) ? -1 : cursor.getInt(colSPort));
|
||||
final String dest = cursor.getString(colDest);
|
||||
int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
|
||||
int uid = (cursor.isNull(colUid) ? -1 : cursor.getInt(colUid));
|
||||
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));
|
||||
int allowed = (cursor.isNull(colAllowed) ? -1 : cursor.getInt(colAllowed));
|
||||
|
||||
final String whois = (ip.length() > 1 && ip.charAt(0) == '/' ? ip.substring(1) : ip);
|
||||
|
||||
// Get views
|
||||
TextView tvTime = (TextView) view.findViewById(R.id.tvTime);
|
||||
ImageView ivConnection = (ImageView) view.findViewById(R.id.ivConnection);
|
||||
ImageView ivInteractive = (ImageView) view.findViewById(R.id.ivInteractive);
|
||||
TextView tvProtocol = (TextView) view.findViewById(R.id.tvProtocol);
|
||||
TextView tvPort = (TextView) view.findViewById(R.id.tvPort);
|
||||
TextView tvFlags = (TextView) view.findViewById(R.id.tvFlags);
|
||||
final TextView tvSource = (TextView) view.findViewById(R.id.tvSource);
|
||||
TextView tvSPort = (TextView) view.findViewById(R.id.tvSPort);
|
||||
final TextView tvDest = (TextView) view.findViewById(R.id.tvDest);
|
||||
TextView tvDPort = (TextView) view.findViewById(R.id.tvDPort);
|
||||
ImageView ivIcon = (ImageView) view.findViewById(R.id.ivIcon);
|
||||
TextView tvUid = (TextView) view.findViewById(R.id.tvUid);
|
||||
final TextView tvIP = (TextView) view.findViewById(R.id.tvIP);
|
||||
ImageView ivConnection = (ImageView) view.findViewById(R.id.ivConnection);
|
||||
ImageView ivInteractive = (ImageView) view.findViewById(R.id.ivInteractive);
|
||||
|
||||
// Set values
|
||||
tvTime.setText(new SimpleDateFormat("HH:mm:ss").format(time));
|
||||
|
@ -106,9 +114,11 @@ public class LogAdapter extends CursorAdapter {
|
|||
else
|
||||
tvProtocol.setText(protocol < 0 ? "" : Integer.toString(protocol));
|
||||
|
||||
tvPort.setText(port < 0 ? "" : Integer.toString(port));
|
||||
tvFlags.setText(flags);
|
||||
|
||||
tvSPort.setText(sport < 0 ? "" : Integer.toString(sport));
|
||||
tvDPort.setText(dport < 0 ? "" : Integer.toString(dport));
|
||||
|
||||
// Application icon
|
||||
ApplicationInfo info = null;
|
||||
PackageManager pm = context.getPackageManager();
|
||||
|
@ -143,32 +153,38 @@ public class LogAdapter extends CursorAdapter {
|
|||
// tvFlags.setText("+APFR");
|
||||
// tvUid.setText("18888");
|
||||
|
||||
synchronized (mapIPHost) {
|
||||
if (mapIPHost.containsKey(whois))
|
||||
tvIP.setText(mapIPHost.get(whois));
|
||||
else {
|
||||
tvIP.setText(whois);
|
||||
new AsyncTask<String, Object, String>() {
|
||||
@Override
|
||||
protected String doInBackground(String... args) {
|
||||
try {
|
||||
// This requires internet permission
|
||||
return InetAddress.getByName(args[0]).getHostName();
|
||||
} catch (UnknownHostException ignored) {
|
||||
return whois;
|
||||
}
|
||||
}
|
||||
// TODO resolve source when inbound
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String host) {
|
||||
synchronized (mapIPHost) {
|
||||
if (!mapIPHost.containsKey(host))
|
||||
mapIPHost.put(host, host);
|
||||
tvSource.setText(source);
|
||||
if (resolve)
|
||||
synchronized (mapIPHost) {
|
||||
if (mapIPHost.containsKey(dest))
|
||||
tvDest.setText(mapIPHost.get(dest));
|
||||
else {
|
||||
tvDest.setText(dest);
|
||||
new AsyncTask<String, Object, String>() {
|
||||
@Override
|
||||
protected String doInBackground(String... args) {
|
||||
try {
|
||||
// This requires internet permission
|
||||
return InetAddress.getByName(args[0]).getHostName();
|
||||
} catch (UnknownHostException ignored) {
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
tvIP.setText(host);
|
||||
}
|
||||
}.execute(whois);
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String host) {
|
||||
synchronized (mapIPHost) {
|
||||
if (!mapIPHost.containsKey(host))
|
||||
mapIPHost.put(host, host);
|
||||
}
|
||||
tvDest.setText(host);
|
||||
}
|
||||
}.execute(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
tvDest.setText(dest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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)
|
||||
*/
|
||||
|
||||
public class Packet {
|
||||
public long time;
|
||||
public int version;
|
||||
public int protocol;
|
||||
public String flags;
|
||||
public String saddr;
|
||||
public int sport;
|
||||
public String daddr;
|
||||
public int dport;
|
||||
public int uid;
|
||||
public boolean allowed;
|
||||
|
||||
public Packet() {
|
||||
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ import android.widget.RemoteViews;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
@ -783,26 +784,11 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
|
||||
// Called from native code
|
||||
private void logPacket(
|
||||
long time,
|
||||
int version,
|
||||
String daddr,
|
||||
int protocol,
|
||||
int dport,
|
||||
String flags,
|
||||
int uid,
|
||||
boolean allowed) {
|
||||
private void logPacket(Packet packet) {
|
||||
new DatabaseHelper(SinkholeService.this).insertLog(
|
||||
time,
|
||||
version,
|
||||
daddr,
|
||||
protocol,
|
||||
dport,
|
||||
flags,
|
||||
uid,
|
||||
packet,
|
||||
(last_connected ? last_metered ? 2 : 1 : 0),
|
||||
last_interactive,
|
||||
allowed).close();
|
||||
last_interactive).close();
|
||||
}
|
||||
|
||||
private BroadcastReceiver interactiveStateReceiver = new BroadcastReceiver() {
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
// TODO non blocking send/write/close, handle EAGAIN/EWOULDBLOCK
|
||||
|
||||
// It is assumed that no packets will get lost and that packets arrive in order
|
||||
// http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/index.html
|
||||
|
||||
// Global variables
|
||||
|
||||
|
@ -60,6 +59,36 @@ char *pcap_fn = NULL;
|
|||
|
||||
// JNI
|
||||
|
||||
jclass clsPacket;
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
log_android(ANDROID_LOG_INFO, "JNI load");
|
||||
|
||||
JNIEnv *env;
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *packet = "eu/faircode/netguard/Packet";
|
||||
clsPacket = jniGlobalRef(env, jniFindClass(env, packet));
|
||||
|
||||
// TODO find methods
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
log_android(ANDROID_LOG_INFO, "JNI unload");
|
||||
|
||||
JNIEnv *env;
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK)
|
||||
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
|
||||
else {
|
||||
(*env)->DeleteGlobalRef(env, clsPacket);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_eu_faircode_netguard_SinkholeService_jni_1init(JNIEnv *env) {
|
||||
udp_session = NULL;
|
||||
|
@ -852,7 +881,7 @@ void handle_ip(const struct arguments *args, const uint8_t *buffer, const uint16
|
|||
// Log traffic
|
||||
if (args->log) {
|
||||
if (!args->filter || syn || log || protocol != IPPROTO_TCP)
|
||||
log_packet(args, version, dest, protocol, dport, flags, uid, allowed);
|
||||
log_packet(args, version, protocol, flags, source, sport, dest, dport, uid, allowed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1422,13 +1451,15 @@ int write_udp(const struct arguments *args, const struct udp_session *cur,
|
|||
udp->check = 0;
|
||||
udp->len = htons(sizeof(struct udphdr) + datalen);
|
||||
|
||||
char to[20];
|
||||
inet_ntop(AF_INET, &(ip->daddr), to, sizeof(to));
|
||||
char source[20];
|
||||
char dest[20];
|
||||
inet_ntop(AF_INET, &(ip->saddr), source, sizeof(source));
|
||||
inet_ntop(AF_INET, &(ip->daddr), dest, sizeof(dest));
|
||||
|
||||
// Send packet
|
||||
log_android(ANDROID_LOG_DEBUG,
|
||||
"Sending UDP to tun %s/%u data %u",
|
||||
to, ntohs(udp->dest), datalen);
|
||||
"Sending UDP to tun from %s/%u to %s/%u data %u",
|
||||
source, ntohs(udp->source), dest, ntohs(udp->dest), datalen);
|
||||
|
||||
int res = write(tun, buffer, len);
|
||||
|
||||
|
@ -1440,7 +1471,8 @@ int write_udp(const struct arguments *args, const struct udp_session *cur,
|
|||
log_android(ANDROID_LOG_INFO, "tun UDP write %f", mselapsed);
|
||||
#endif
|
||||
|
||||
log_packet(args, cur->version, to, ip->protocol, ntohs(udp->dest), "", cur->uid, 1);
|
||||
log_packet(args, cur->version, ip->protocol, "",
|
||||
source, ntohs(udp->source), dest, ntohs(udp->dest), cur->uid, 1);
|
||||
|
||||
// Write pcap record
|
||||
if (pcap_fn != NULL)
|
||||
|
@ -1707,6 +1739,59 @@ uint16_t calc_checksum(uint8_t *buffer, uint16_t length) {
|
|||
return (uint16_t) (~sum);
|
||||
}
|
||||
|
||||
// http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
|
||||
// http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/index.html
|
||||
|
||||
jobject jniGlobalRef(JNIEnv *env, jobject cls) {
|
||||
jobject gcls = (*env)->NewGlobalRef(env, cls);
|
||||
if (gcls == NULL)
|
||||
log_android(ANDROID_LOG_ERROR, "Global ref failed (out of memory?)");
|
||||
return gcls;
|
||||
}
|
||||
|
||||
jclass jniFindClass(JNIEnv *env, const char *name) {
|
||||
jclass cls = (*env)->FindClass(env, name);
|
||||
if (cls == NULL)
|
||||
log_android(ANDROID_LOG_ERROR, "Class %s not found", name);
|
||||
else
|
||||
jniCheckException(env);
|
||||
return cls;
|
||||
}
|
||||
|
||||
jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature) {
|
||||
jmethodID method = (*env)->GetMethodID(env, cls, name, signature);
|
||||
if (method == NULL)
|
||||
log_android(ANDROID_LOG_ERROR, "Method %s%s", name, signature);
|
||||
return method;
|
||||
}
|
||||
|
||||
jfieldID jniGetFieldID(JNIEnv *env, jclass cls, const char *name, const char *type) {
|
||||
jfieldID field = (*env)->GetFieldID(env, cls, name, type);
|
||||
if (field == NULL)
|
||||
log_android(ANDROID_LOG_ERROR, "Field %s type %s not found", name, type);
|
||||
return field;
|
||||
}
|
||||
|
||||
jobject jniNewObject(JNIEnv *env, jclass cls, jmethodID constructor, const char *name) {
|
||||
jobject object = (*env)->NewObject(env, cls, constructor);
|
||||
if (object == NULL)
|
||||
log_android(ANDROID_LOG_ERROR, "Create object %s failed", name);
|
||||
else
|
||||
jniCheckException(env);
|
||||
return object;
|
||||
}
|
||||
|
||||
int jniCheckException(JNIEnv *env) {
|
||||
jthrowable ex = (*env)->ExceptionOccurred(env);
|
||||
if (ex) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, ex);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log_android(int prio, const char *fmt, ...) {
|
||||
if (prio >= loglevel) {
|
||||
char line[1024];
|
||||
|
@ -1721,10 +1806,12 @@ void log_android(int prio, const char *fmt, ...) {
|
|||
void log_packet(
|
||||
const struct arguments *args,
|
||||
jint version,
|
||||
const char *dest,
|
||||
jint protocol,
|
||||
jint dport,
|
||||
const char *flags,
|
||||
const char *source,
|
||||
jint sport,
|
||||
const char *dest,
|
||||
jint dport,
|
||||
jint uid,
|
||||
jboolean allowed) {
|
||||
#ifdef PROFILE
|
||||
|
@ -1735,37 +1822,43 @@ void log_packet(
|
|||
|
||||
JNIEnv *env = args->env;
|
||||
jobject instance = args->instance;
|
||||
jclass cls = (*env)->GetObjectClass(env, instance);
|
||||
char *signature = "(JILjava/lang/String;IILjava/lang/String;IZ)V";
|
||||
jmethodID mid = (*env)->GetMethodID(env, cls, "logPacket", signature);
|
||||
if (mid == 0)
|
||||
log_android(ANDROID_LOG_ERROR, "Method logPacket%s not found", signature);
|
||||
else {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
jlong t = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
|
||||
jstring jdest = (*env)->NewStringUTF(env, dest);
|
||||
jstring jflags = (*env)->NewStringUTF(env, flags);
|
||||
(*env)->CallVoidMethod(env, instance, mid,
|
||||
t,
|
||||
version,
|
||||
jdest,
|
||||
protocol,
|
||||
dport,
|
||||
jflags,
|
||||
uid,
|
||||
allowed);
|
||||
(*env)->DeleteLocalRef(env, jdest);
|
||||
(*env)->DeleteLocalRef(env, jflags);
|
||||
|
||||
jthrowable ex = (*env)->ExceptionOccurred(env);
|
||||
if (ex) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
(*env)->DeleteLocalRef(env, ex);
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, cls);
|
||||
jclass clsService = (*env)->GetObjectClass(env, instance);
|
||||
|
||||
const char *signature = "(Leu/faircode/netguard/Packet;)V";
|
||||
jmethodID logPacket = jniGetMethodID(env, clsService, "logPacket", signature);
|
||||
|
||||
const char *packet = "eu/faircode/netguard/Packet";
|
||||
jmethodID initPacket = jniGetMethodID(env, clsPacket, "<init>", "()V");
|
||||
jobject objPacket = jniNewObject(env, clsPacket, initPacket, packet);
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
jlong t = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
|
||||
jstring jflags = (*env)->NewStringUTF(env, flags);
|
||||
jstring jsource = (*env)->NewStringUTF(env, source);
|
||||
jstring jdest = (*env)->NewStringUTF(env, dest);
|
||||
|
||||
const char *string = "Ljava/lang/String;";
|
||||
(*env)->SetLongField(env, objPacket, jniGetFieldID(env, clsPacket, "time", "J"), t);
|
||||
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "version", "I"), version);
|
||||
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "protocol", "I"), protocol);
|
||||
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "flags", string), jflags);
|
||||
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "saddr", string), jsource);
|
||||
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "sport", "I"), sport);
|
||||
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "daddr", string), jdest);
|
||||
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "dport", "I"), dport);
|
||||
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "uid", "I"), uid);
|
||||
(*env)->SetBooleanField(env, objPacket, jniGetFieldID(env, clsPacket, "allowed", "Z"), allowed);
|
||||
|
||||
(*env)->CallVoidMethod(env, instance, logPacket, objPacket);
|
||||
jniCheckException(env);
|
||||
|
||||
(*env)->DeleteLocalRef(env, jdest);
|
||||
(*env)->DeleteLocalRef(env, jsource);
|
||||
(*env)->DeleteLocalRef(env, jflags);
|
||||
(*env)->DeleteLocalRef(env, objPacket);
|
||||
(*env)->DeleteLocalRef(env, clsService);
|
||||
|
||||
#ifdef PROFILE
|
||||
gettimeofday(&end, NULL);
|
||||
|
|
|
@ -144,14 +144,28 @@ jint get_uid(const int protocol, const int version,
|
|||
|
||||
uint16_t calc_checksum(uint8_t *buffer, uint16_t length);
|
||||
|
||||
jobject jniGlobalRef(JNIEnv *env, jobject cls);
|
||||
|
||||
jclass jniFindClass(JNIEnv *env, const char *name);
|
||||
|
||||
jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature);
|
||||
|
||||
jfieldID jniGetFieldID(JNIEnv *env, jclass cls, const char *name, const char *type);
|
||||
|
||||
jobject jniNewObject(JNIEnv *env, jclass cls, jmethodID constructor, const char *name);
|
||||
|
||||
int jniCheckException(JNIEnv *env);
|
||||
|
||||
void log_android(int prio, const char *fmt, ...);
|
||||
|
||||
void log_packet(const struct arguments *args,
|
||||
jint version,
|
||||
const char *dest,
|
||||
jint protocol,
|
||||
jint dport,
|
||||
const char *flags,
|
||||
const char *source,
|
||||
jint sport,
|
||||
const char *dest,
|
||||
jint dport,
|
||||
jint uid,
|
||||
jboolean allowed);
|
||||
|
||||
|
|
|
@ -26,38 +26,59 @@
|
|||
android:layout_height="16dip"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvProtocol"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="end"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPort"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="end"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFlags"
|
||||
android:layout_width="40dp"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvProtocol"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFlags"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSPort"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDPort"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivIcon"
|
||||
android:layout_width="16dip"
|
||||
android:layout_height="16dip"
|
||||
android:layout_gravity="center_vertical" />
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvUid"
|
||||
|
@ -68,13 +89,26 @@
|
|||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvIP"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSource"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDest"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Small"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
android:checkable="true"
|
||||
android:checked="true"
|
||||
android:title="@string/menu_live" />
|
||||
<item
|
||||
android:id="@+id/menu_log_resolve"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:title="@string/menu_resolve" />
|
||||
<item
|
||||
android:id="@+id/menu_log_clear"
|
||||
android:title="@string/menu_clear" />
|
||||
|
|
|
@ -26,6 +26,7 @@ These issues are caused by bugs in Android, or in the software provided by the m
|
|||
|
||||
<string name="menu_enabled">Enabled</string>
|
||||
<string name="menu_live">Live updates</string>
|
||||
<string name="menu_resolve">Resolve host names</string>
|
||||
<string name="menu_pcap_enabled">PCAP enabled</string>
|
||||
<string name="menu_pcap_export">PCAP export</string>
|
||||
<string name="menu_clear">Clear</string>
|
||||
|
|
Loading…
Reference in New Issue