Native better pcap file handling

This commit is contained in:
M66B 2016-01-22 13:06:50 +01:00
parent e8063ddbdb
commit a8da87fa9a
6 changed files with 91 additions and 76 deletions

View File

@ -186,14 +186,15 @@ public class ActivityLog extends AppCompatActivity {
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 pcap_enabled = prefs.getBoolean("pcap", false);
File pcap_file = new File(getCacheDir(), "netguard.pcap");
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).setChecked(pcap_enabled);
menu.findItem(R.id.menu_pcap_enabled).setEnabled(log || filter);
menu.findItem(R.id.menu_pcap_export).setEnabled(pcap && export);
menu.findItem(R.id.menu_pcap_export).setEnabled(pcap_file.exists() && export);
return super.onPrepareOptionsMenu(menu);
}
@ -201,6 +202,7 @@ public class ActivityLog extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
File pcap_file = new File(getCacheDir(), "netguard.pcap");
switch (item.getItemId()) {
case R.id.menu_log_enabled:
@ -227,23 +229,29 @@ public class ActivityLog extends AppCompatActivity {
lvLog.setAdapter(adapter);
return true;
case R.id.menu_log_clear:
dh.clear();
if (!live) {
adapter.changeCursor(dh.getLog());
}
return true;
case R.id.menu_pcap_enabled:
item.setChecked(!item.isChecked());
prefs.edit().putBoolean("pcap", item.isChecked()).apply();
SinkholeService.setPcap(item.isChecked(), this);
SinkholeService.setPcap(item.isChecked() ? pcap_file : null);
return true;
case R.id.menu_pcap_export:
startActivityForResult(getIntentPCAPDocument(), REQUEST_PCAP);
return true;
case R.id.menu_log_clear:
dh.clear();
adapter.changeCursor(dh.getLog());
if (prefs.getBoolean("pcap", false)) {
SinkholeService.setPcap(null);
pcap_file.delete();
SinkholeService.setPcap(pcap_file);
} else {
if (pcap_file.exists())
pcap_file.delete();
}
return true;
case R.id.menu_log_support:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://github.com/M66B/NetGuard/blob/master/FAQ.md#FAQ27"));

View File

@ -124,11 +124,8 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
private static native void jni_pcap(String name);
public static void setPcap(boolean enabled, Context context) {
File pcap = new File(context.getCacheDir(), "netguard.pcap");
if (pcap.exists())
pcap.delete();
jni_pcap(enabled ? pcap.getAbsolutePath() : null);
public static void setPcap(File pcap) {
jni_pcap(pcap == null ? null : pcap.getAbsolutePath());
}
static {
@ -952,7 +949,8 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
// Native init
jni_init();
setPcap(prefs.getBoolean("pcap", false), this);
boolean pcap = prefs.getBoolean("pcap", false);
setPcap(pcap ? new File(getCacheDir(), "netguard.pcap") : null);
prefs.registerOnSharedPreferenceChangeListener(this);

View File

@ -53,10 +53,11 @@ static JavaVM *jvm;
pthread_t thread_id;
int stopping = 0;
int signaled = 0;
struct udp_session *udp_session = NULL;
struct tcp_session *tcp_session = NULL;
int loglevel = 0;
char *pcap_fn = NULL;
FILE *pcap_file = NULL;
// JNI
@ -94,7 +95,8 @@ JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1init(JNIEnv *env) {
udp_session = NULL;
tcp_session = NULL;
pcap_fn = NULL;
loglevel = ANDROID_LOG_WARN;
pcap_file = NULL;
}
JNIEXPORT void JNICALL
@ -174,29 +176,33 @@ Java_eu_faircode_netguard_SinkholeService_jni_1done(JNIEnv *env, jobject instanc
log_android(ANDROID_LOG_INFO, "Done");
clear_sessions();
if (pcap_fn != NULL)
free(pcap_fn);
}
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1pcap(JNIEnv *env, jclass type, jstring name_) {
// TODO limit pcap file size
// TODO keep pcap file open
if (name_ == NULL) {
pcap_fn = NULL;
if (pcap_file != NULL) {
if (fclose(pcap_file))
log_android(ANDROID_LOG_ERROR, "PCAP fclose error %d: %s", errno,
strerror(errno));
}
pcap_file = NULL;
log_android(ANDROID_LOG_INFO, "PCAP disabled");
}
else {
const char *name = (*env)->GetStringUTFChars(env, name_, 0);
log_android(ANDROID_LOG_INFO, "PCAP file %s", name);
const char *tmp = malloc(strlen(name) + 1);
strcpy(tmp, name);
pcap_fn = tmp;
write_pcap_hdr();
pcap_file = fopen(name, "ab+");
if (pcap_file == NULL)
log_android(ANDROID_LOG_ERROR, "PCAP fopen error %d: %s", errno, strerror(errno));
else {
uint8_t flags = fcntl(fileno(pcap_file), F_GETFL, 0);
if (flags < 0 || fcntl(fileno(pcap_file), F_SETFL, flags | O_NONBLOCK) < 0)
log_android(ANDROID_LOG_ERROR, "PCAP fcntl O_NONBLOCK error %d: %s",
errno, strerror(errno));
write_pcap_hdr();
}
(*env)->ReleaseStringUTFChars(env, name_, name);
}
@ -539,7 +545,7 @@ int check_tun(const struct arguments *args, fd_set *rfds, fd_set *wfds,
}
else if (length > 0) {
// Write pcap record
if (pcap_fn != NULL)
if (pcap_file != NULL)
write_pcap_rec(buffer, length);
// Handle IP from tun
@ -1478,7 +1484,7 @@ int write_udp(const struct arguments *args, const struct udp_session *cur,
source, ntohs(udp->source), dest, ntohs(udp->dest), cur->uid, 1);
// Write pcap record
if (pcap_fn != NULL)
if (pcap_file != NULL)
write_pcap_rec(buffer, len);
free(buffer);
@ -1577,7 +1583,7 @@ int write_tcp(const struct arguments *args, const struct tcp_session *cur,
#endif
// Write pcap record
if (pcap_fn != NULL)
if (pcap_file != NULL)
write_pcap_rec(buffer, len);
free(buffer);
@ -1872,38 +1878,6 @@ void log_packet(
#endif
}
void write_pcap(const void *ptr, size_t len) {
#ifdef PROFILE
float mselapsed;
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
FILE *fd = fopen(pcap_fn, "ab");
if (fd == NULL)
log_android(ANDROID_LOG_ERROR, "fopen %s error %d: %s",
pcap_fn, errno, strerror(errno));
else {
if (fwrite(ptr, len, 1, fd) < 1)
log_android(ANDROID_LOG_ERROR, "fwrite %s error %d: %s",
pcap_fn, errno, strerror(errno));
else
log_android(ANDROID_LOG_DEBUG, "PCAP write %d", len);
if (fclose(fd))
log_android(ANDROID_LOG_ERROR, "fclose %s error %d: %s",
pcap_fn, errno, strerror(errno));
}
#ifdef PROFILE
gettimeofday(&end, NULL);
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
(end.tv_usec - start.tv_usec) / 1000.0;
if (mselapsed > 1)
log_android(ANDROID_LOG_INFO, "pcap write %f", mselapsed);
#endif
}
void write_pcap_hdr() {
struct pcap_hdr_s pcap_hdr;
pcap_hdr.magic_number = 0xa1b2c3d4;
@ -1911,7 +1885,7 @@ void write_pcap_hdr() {
pcap_hdr.version_minor = 4;
pcap_hdr.thiszone = 0;
pcap_hdr.sigfigs = 0;
pcap_hdr.snaplen = MAX_PCAP;
pcap_hdr.snaplen = MAX_PCAP_RECORD;
pcap_hdr.network = LINKTYPE_RAW;
write_pcap(&pcap_hdr, sizeof(struct pcap_hdr_s));
}
@ -1922,7 +1896,7 @@ void write_pcap_rec(const uint8_t *buffer, uint16_t length) {
log_android(ANDROID_LOG_ERROR, "clock_gettime error %d: %s", errno, strerror(errno));
// TODO use stack
int plen = (length < MAX_PCAP ? length : MAX_PCAP);
int plen = (length < MAX_PCAP_RECORD ? length : MAX_PCAP_RECORD);
struct pcaprec_hdr_s *pcap_rec = malloc(sizeof(struct pcaprec_hdr_s) + plen);
pcap_rec->ts_sec = ts.tv_sec;
@ -1936,6 +1910,41 @@ void write_pcap_rec(const uint8_t *buffer, uint16_t length) {
free(pcap_rec);
}
void write_pcap(const void *ptr, size_t len) {
#ifdef PROFILE
float mselapsed;
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
if (fwrite(ptr, len, 1, pcap_file) < 1)
log_android(ANDROID_LOG_ERROR, "PCAP fwrite error %d: %s", errno, strerror(errno));
else {
long fsize = ftell(pcap_file);
log_android(ANDROID_LOG_DEBUG, "PCAP wrote %d @%ld", len, fsize);
if (fsize > MAX_PCAP_FILE) {
log_android(ANDROID_LOG_INFO, "PCAP truncate @%ld", fsize);
if (ftruncate(fileno(pcap_file), sizeof(struct pcap_hdr_s)))
log_android(ANDROID_LOG_ERROR, "PCAP ftruncate error %d: %s",
errno, strerror(errno));
else {
if (!lseek(fileno(pcap_file), sizeof(struct pcap_hdr_s), SEEK_SET))
log_android(ANDROID_LOG_ERROR, "PCAP ftruncate error %d: %s",
errno, strerror(errno));
}
}
}
#ifdef PROFILE
gettimeofday(&end, NULL);
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
(end.tv_usec - start.tv_usec) / 1000.0;
if (mselapsed > 1)
log_android(ANDROID_LOG_INFO, "pcap write %f", mselapsed);
#endif
}
const char *strstate(const int state) {
char buf[20];
switch (state) {
@ -1964,7 +1973,6 @@ const char *strstate(const int state) {
default:
sprintf(buf, "TCP_%d", state);
return buf;
}
}

View File

@ -21,7 +21,8 @@
#define UID_DELAYTRY 10 // milliseconds
#define UID_MAXTRY 3
#define MAX_PCAP 80
#define MAX_PCAP_FILE (1024 * 1024) // bytes
#define MAX_PCAP_RECORD 80 // bytes
struct arguments {
JNIEnv *env;
@ -169,12 +170,12 @@ void log_packet(const struct arguments *args,
jint uid,
jboolean allowed);
void write_pcap(const void *ptr, size_t len);
void write_pcap_hdr();
void write_pcap_rec(const uint8_t *buffer, uint16_t len);
void write_pcap(const void *ptr, size_t len);
const char *strstate(const int state);
char *hex(const u_int8_t *data, const u_int16_t len);

View File

@ -14,9 +14,6 @@
android:checkable="true"
android:checked="false"
android:title="@string/menu_resolve" />
<item
android:id="@+id/menu_log_clear"
android:title="@string/menu_clear" />
<item
android:id="@+id/menu_pcap_enabled"
android:checkable="true"
@ -24,6 +21,9 @@
<item
android:id="@+id/menu_pcap_export"
android:title="@string/menu_pcap_export" />
<item
android:id="@+id/menu_log_clear"
android:title="@string/menu_clear" />
<item
android:id="@+id/menu_log_support"
android:title="@string/menu_support" />

View File

@ -24,7 +24,7 @@ These issues are caused by bugs in Android, or in the software provided by the m
<string name="menu_support">Support</string>
<string name="menu_about">About</string>
<string name="menu_enabled">Enabled</string>
<string name="menu_enabled">Log 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>