Native log extra data (currently qnames only)

This commit is contained in:
M66B 2016-01-26 11:41:03 +01:00
parent 071124d3fc
commit f061cb8f42
6 changed files with 271 additions and 188 deletions

View File

@ -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 = 7;
private static final int DB_VERSION = 8;
private static List<LogChangedListener> logChangedListeners = new ArrayList<LogChangedListener>();
@ -44,13 +44,15 @@ public class DatabaseHelper extends SQLiteOpenHelper {
", daddr TEXT" +
", dport INTEGER NULL" +
", uid INTEGER NULL" +
", data TEXT" +
", allowed INTEGER NULL" +
", connection INTEGER NULL" +
", interactive 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)");
db.execSQL("CREATE INDEX idx_log_source ON log(saddr)");
db.execSQL("CREATE INDEX idx_log_dest ON log(daddr)");
db.execSQL("CREATE INDEX idx_log_uid ON log(uid)");
}
@Override
@ -87,6 +89,15 @@ public class DatabaseHelper extends SQLiteOpenHelper {
createTableLog(db);
oldVersion = 7;
}
if (oldVersion < 8) {
db.execSQL("ALTER TABLE log ADD COLUMN data TEXT");
db.execSQL("DROP INDEX idx_log_source");
db.execSQL("DROP INDEX idx_log_dest");
db.execSQL("CREATE INDEX idx_log_source ON log(saddr)");
db.execSQL("CREATE INDEX idx_log_dest ON log(daddr)");
db.execSQL("CREATE INDEX idx_log_uid ON log(uid)");
oldVersion = 8;
}
db.setVersion(DB_VERSION);
@ -127,6 +138,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
else
cv.put("dport", packet.dport);
cv.put("data", packet.data);
if (packet.uid < 0)
cv.putNull("uid");
else

View File

@ -8,6 +8,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -37,6 +38,7 @@ public class LogAdapter extends CursorAdapter {
private int colDest;
private int colDPort;
private int colUid;
private int colData;
private int colAllowed;
private int colConnection;
private int colInteractive;
@ -56,6 +58,7 @@ public class LogAdapter extends CursorAdapter {
colDest = cursor.getColumnIndex("daddr");
colDPort = cursor.getColumnIndex("dport");
colUid = cursor.getColumnIndex("uid");
colData = cursor.getColumnIndex("data");
colAllowed = cursor.getColumnIndex("allowed");
colConnection = cursor.getColumnIndex("connection");
colInteractive = cursor.getColumnIndex("interactive");
@ -86,6 +89,7 @@ public class LogAdapter extends CursorAdapter {
final String dest = cursor.getString(colDest);
int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
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));
@ -100,6 +104,7 @@ public class LogAdapter extends CursorAdapter {
TextView tvDPort = (TextView) view.findViewById(R.id.tvDPort);
ImageView ivIcon = (ImageView) view.findViewById(R.id.ivIcon);
TextView tvUid = (TextView) view.findViewById(R.id.tvUid);
TextView tvData = (TextView) view.findViewById(R.id.tvData);
ImageView ivConnection = (ImageView) view.findViewById(R.id.ivConnection);
ImageView ivInteractive = (ImageView) view.findViewById(R.id.ivInteractive);
@ -199,6 +204,14 @@ public class LogAdapter extends CursorAdapter {
}
else
tvDest.setText(getKnownAddress(dest));
if (TextUtils.isEmpty(data)) {
tvData.setText("");
tvData.setVisibility(View.GONE);
} else {
tvData.setText(data);
tvData.setVisibility(View.VISIBLE);
}
}
public boolean isKnownAddress(String addr) {

View File

@ -28,6 +28,7 @@ public class Packet {
public int sport;
public String daddr;
public int dport;
public String data;
public int uid;
public boolean allowed;

View File

@ -1056,13 +1056,15 @@ void handle_ip(const struct arguments *args, const uint8_t *buffer, const size_t
// Handle allowed traffic
int log = 0;
char data[200];
*data = 0;
if (allowed) {
if (protocol == IPPROTO_UDP) {
allowed = handle_udp(args, buffer, length, uid);
log = (debug || dport != 53);
allowed = handle_udp(args, buffer, length, uid, data);
log = (!allowed || dport != 53 || debug);
} else if (protocol == IPPROTO_TCP) {
allowed = handle_tcp(args, buffer, length, uid);
log = (debug || syn);
allowed = handle_tcp(args, buffer, length, uid, data);
log = (!allowed || syn);
}
else {
allowed = 0;
@ -1072,10 +1074,12 @@ void handle_ip(const struct arguments *args, const uint8_t *buffer, const size_t
// Log traffic
if (args->log && (!args->filter || log))
log_packet(args, version, protocol, flags, source, sport, dest, dport, uid, allowed);
log_packet(args, version, protocol, flags, source, sport, dest, dport, data, uid, allowed);
}
jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid) {
jboolean handle_udp(const struct arguments *args,
const uint8_t *buffer, size_t length,
int uid, char *data) {
// Check version
uint8_t version = (*buffer) >> 4;
@ -1165,9 +1169,19 @@ jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t
}
// Check for DNS
if (ntohs(udphdr->dest) == 53 && check_dns(args, cur, buffer + dataoff, datalen)) {
cur->stop = 1;
return 0;
if (ntohs(udphdr->dest) == 53) {
char qname[DNS_QNAME_MAX + 1];
uint16_t qtype;
uint16_t qclass;
if (get_dns(args, cur, buffer + dataoff, datalen, &qtype, &qclass, qname) >= 0) {
log_android(ANDROID_LOG_INFO, "DNS type %d class %d name %s", qtype, qclass, qname);
sprintf(data, "qtype %d qname %s", qtype, qname);
if (check_dns(args, cur, buffer + dataoff, datalen, qclass, qtype, qname)) {
cur->stop = 1;
return 0;
}
}
}
// TODO check DHCP (tethering)
@ -1200,22 +1214,21 @@ jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t
return 1;
}
int check_dns(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen) {
int get_dns(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen,
uint16_t *qtype, uint16_t *qclass, char *name) {
if (datalen > sizeof(struct dns_header)) {
const struct dns_header *dns = (struct dns_header *) data;
// Check if standard DNS query
// Wireshark: (udp.port eq 53)
const struct dns_header *dns = (struct dns_header *) data;
if (dns->qr == 0 && dns->opcode == 0 && dns->q_count != 0) {
char name[64];
uint8_t noff = 0;
// http://tools.ietf.org/html/rfc1035
uint8_t len;
uint8_t comp = 0;
size_t qdoff = sizeof(struct dns_header);
do {
comp++;
len = *(data + qdoff);
// TODO DNS compression
if (len && qdoff + 1 + len <= datalen) {
@ -1224,80 +1237,85 @@ int check_dns(const struct arguments *args, const struct udp_session *u,
noff += (len + 1);
qdoff += (1 + len);
}
} while (len);
} while (len && comp < 10);
qdoff++;
if (noff > 0 && qdoff + 4 == datalen) {
*(name + noff - 1) = 0;
uint16_t qtype = ntohs(*((uint16_t *) (data + qdoff)));
uint16_t qclass = ntohs(*((uint16_t *) (data + qdoff + 2)));
log_android(ANDROID_LOG_INFO, "DNS type %d class %d name %s", qtype, qclass, name);
if (qclass == DNS_QCLASS_IN && (qtype == DNS_QTYPE_A || qtype == DNS_QTYPE_AAAA)) {
for (int i = 0; i < args->hcount; i++)
if (!strcmp(name, args->hosts[i])) {
log_android(ANDROID_LOG_WARN, "DNS type %d class %d name %s blocked",
qtype, qclass, name);
// Build response
size_t rlen = datalen + sizeof(struct dns_rr) +
(qtype == DNS_QTYPE_A ? 4 : 16);
uint8_t *response = malloc(rlen);
// Copy header & query
memcpy(response, data, datalen);
// Modify header
struct dns_header *rh = (struct dns_header *) response;
rh->qr = 1;
rh->aa = 0;
rh->tc = 0;
rh->rd = 0;
rh->ra = 0;
rh->z = 0;
rh->ad = 0;
rh->cd = 0;
rh->rcode = 0;
rh->ans_count = htons(1);
rh->auth_count = 0;
rh->add_count = 0;
// Build answer
struct dns_rr *answer = (struct dns_rr *) (response + datalen);
answer->qname_ptr = htons(sizeof(struct dns_header) | 0xC000);
answer->qtype = htons(qtype);
answer->qclass = htons(qclass);
answer->ttl = htonl(DNS_TTL);
answer->rdlength = htons(qtype == DNS_QTYPE_A ? 4 : 16);
// Add answer address
uint8_t *addr = response + datalen + sizeof(struct dns_rr);
if (qtype == DNS_QTYPE_A)
inet_pton(AF_INET, "127.0.0.1", addr);
else
inet_pton(AF_INET6, "::1", addr);
// Send response
ssize_t res = write_udp(args, u, response, rlen);
free(response);
if (res < 0)
log_android(ANDROID_LOG_ERROR, "write UDP error %d: %s",
errno, strerror((errno)));
else
return 1;
}
}
*qtype = ntohs(*((uint16_t *) (data + qdoff)));
*qclass = ntohs(*((uint16_t *) (data + qdoff + 2)));
return 0;
}
}
}
return -1;
}
int check_dns(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen,
uint16_t qclass, uint16_t qtype, const char *name) {
if (qclass == DNS_QCLASS_IN && (qtype == DNS_QTYPE_A || qtype == DNS_QTYPE_AAAA)) {
for (int i = 0; i < args->hcount; i++)
if (!strcmp(name, args->hosts[i])) {
log_android(ANDROID_LOG_WARN, "DNS type %d name %s blocked", qtype, name);
// Build response
size_t rlen = datalen + sizeof(struct dns_rr) + (qtype == DNS_QTYPE_A ? 4 : 16);
uint8_t *response = malloc(rlen);
// Copy header & query
memcpy(response, data, datalen);
// Modify copied header
struct dns_header *rh = (struct dns_header *) response;
rh->qr = 1;
rh->aa = 0;
rh->tc = 0;
rh->rd = 0;
rh->ra = 0;
rh->z = 0;
rh->ad = 0;
rh->cd = 0;
rh->rcode = 0;
rh->ans_count = htons(1);
rh->auth_count = 0;
rh->add_count = 0;
// Build answer
struct dns_rr *answer = (struct dns_rr *) (response + datalen);
answer->qname_ptr = htons(sizeof(struct dns_header) | 0xC000);
answer->qtype = htons(qtype);
answer->qclass = htons(qclass);
answer->ttl = htonl(DNS_TTL);
answer->rdlength = htons(qtype == DNS_QTYPE_A ? 4 : 16);
// Add answer address
uint8_t *addr = response + datalen + sizeof(struct dns_rr);
if (qtype == DNS_QTYPE_A)
inet_pton(AF_INET, "127.0.0.1", addr);
else
inet_pton(AF_INET6, "::1", addr);
// Send response
ssize_t res = write_udp(args, u, response, rlen);
free(response);
if (res < 0)
log_android(ANDROID_LOG_ERROR, "write UDP error %d: %s",
errno, strerror((errno)));
else
return 1;
}
}
return 0;
}
jboolean handle_tcp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid) {
jboolean handle_tcp(const struct arguments *args,
const uint8_t *buffer, size_t length,
int uid, char *data) {
#ifdef PROFILE
float mselapsed;
struct timeval start, end;
@ -1926,7 +1944,7 @@ ssize_t write_udp(const struct arguments *args, const struct udp_session *cur,
if (res >= 0) {
if (args->log && (debug || ntohs(cur->dest) != 53))
log_packet(args, cur->version, IPPROTO_UDP, "",
source, ntohs(udp->source), dest, ntohs(udp->dest), cur->uid, 1);
source, ntohs(udp->source), dest, ntohs(udp->dest), "", cur->uid, 1);
// Write pcap record
if (pcap_file != NULL)
@ -2323,6 +2341,7 @@ void log_packet(
jint sport,
const char *dest,
jint dport,
const char *data,
jint uid,
jboolean allowed) {
#ifdef PROFILE
@ -2347,6 +2366,7 @@ void log_packet(
jstring jflags = (*env)->NewStringUTF(env, flags);
jstring jsource = (*env)->NewStringUTF(env, source);
jstring jdest = (*env)->NewStringUTF(env, dest);
jstring jdata = (*env)->NewStringUTF(env, data);
const char *string = "Ljava/lang/String;";
(*env)->SetLongField(env, objPacket, jniGetFieldID(env, clsPacket, "time", "J"), t);
@ -2357,12 +2377,14 @@ void log_packet(
(*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)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "data", string), jdata);
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "uid", "I"), uid);
(*env)->SetBooleanField(env, objPacket, jniGetFieldID(env, clsPacket, "allowed", "Z"), allowed);
(*env)->CallVoidMethod(env, args->instance, logPacket, objPacket);
jniCheckException(env);
(*env)->DeleteLocalRef(env, jdata);
(*env)->DeleteLocalRef(env, jdest);
(*env)->DeleteLocalRef(env, jsource);
(*env)->DeleteLocalRef(env, jflags);

View File

@ -51,10 +51,11 @@ struct udp_session {
__be32 ip4; // network notation
struct in6_addr ip6;
} daddr;
__be16 dest; // network notation
uint8_t stop;
jint socket;
struct udp_session *next;
};
@ -83,9 +84,11 @@ struct tcp_session {
uint8_t state;
jint socket;
struct tcp_session *next;
};
// PCAP
// https://wiki.wireshark.org/Development/LibpcapFileFormat
typedef uint16_t guint16_t;
@ -111,6 +114,15 @@ typedef struct pcaprec_hdr_s {
#define LINKTYPE_RAW 101
// DNS
#define DNS_QTYPE_A 1 // IPv4
#define DNS_QTYPE_AAAA 28 // IPv6
#define DNS_QCLASS_IN 1
#define DNS_QNAME_MAX 63
#define DNS_TTL (10 * 60) // seconds
struct dns_header {
uint16_t id; // identification number
# if __BYTE_ORDER == __LITTLE_ENDIAN
@ -152,11 +164,7 @@ typedef struct dns_rr {
__be16 rdlength;
} __packed;
#define DNS_QTYPE_A 1 // IPv4
#define DNS_QTYPE_AAAA 28 // IPv6
#define DNS_QCLASS_IN 1
#define DNS_TTL (10 * 60) // seconds
// IPv6
struct ip6_hdr_pseudo {
struct in6_addr ip6ph_src;
@ -166,6 +174,8 @@ struct ip6_hdr_pseudo {
u_int8_t ip6ph_nxt;
} __packed;
// Prototypes
void check_allowed(const struct arguments *args);
void clear_sessions();
@ -188,12 +198,21 @@ void check_tcp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds,
void handle_ip(const struct arguments *args, const uint8_t *buffer, size_t length);
jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid);
jboolean handle_udp(const struct arguments *args,
const uint8_t *buffer, size_t length,
int uid, char *data);
jboolean handle_tcp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid);
jboolean handle_tcp(const struct arguments *args,
const uint8_t *buffer, size_t length,
int uid, char *data);
int get_dns(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen,
uint16_t *qtype, uint16_t *qclass, char *name);
int check_dns(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen);
const uint8_t *data, const size_t datalen,
uint16_t qclass, uint16_t qtype, const char *name);
int open_udp_socket(const struct arguments *args, const struct udp_session *cur);
@ -254,6 +273,7 @@ void log_packet(const struct arguments *args,
jint sport,
const char *dest,
jint dport,
const char *data,
jint uid,
jboolean allowed);

View File

@ -3,119 +3,133 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:orientation="vertical"
tools:context=".ActivityLog">
<TextView
android:id="@+id/tvTime"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
<ImageView
android:id="@+id/ivIcon"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/tvUid"
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" />
<ImageView
android:id="@+id/ivConnection"
android:layout_width="16dip"
android:layout_height="16dip"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp" />
<ImageView
android:id="@+id/ivInteractive"
android:layout_width="16dip"
android:layout_height="16dip"
android:layout_gravity="center_vertical" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:orientation="vertical">
android:orientation="horizontal">
<TextView
android:id="@+id/tvProtocol"
android:layout_width="40dp"
android:id="@+id/tvTime"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
<ImageView
android:id="@+id/ivIcon"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/tvFlags"
android:layout_width="40dp"
android:id="@+id/tvUid"
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" />
<ImageView
android:id="@+id/ivConnection"
android:layout_width="16dip"
android:layout_height="16dip"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp" />
<ImageView
android:id="@+id/ivInteractive"
android:layout_width="16dip"
android:layout_height="16dip"
android:layout_gravity="center_vertical" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:orientation="vertical">
<TextView
android:id="@+id/tvProtocol"
android:layout_width="40dp"
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="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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" />
<TextView
android:id="@+id/tvDest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
<TextView
android:id="@+id/tvData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<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" />
<TextView
android:id="@+id/tvDest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
android:layout_marginStart="50dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"
android:textSize="12sp" />
</LinearLayout>