mirror of https://github.com/M66B/NetGuard.git
Native better pcap file handling
This commit is contained in:
parent
e8063ddbdb
commit
a8da87fa9a
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue