mirror of https://github.com/M66B/NetGuard.git
Native SYN fixes/improvements
This commit is contained in:
parent
806196bc69
commit
84ea3d5f6e
|
@ -26,7 +26,6 @@
|
||||||
# logPacket(int version, String saddr, int sport, String daddr, int dport, int protocol, String flags, int uid)
|
# logPacket(int version, String saddr, int sport, String daddr, int dport, int protocol, String flags, int uid)
|
||||||
-keep class eu.faircode.netguard.SinkholeService {
|
-keep class eu.faircode.netguard.SinkholeService {
|
||||||
void logPacket(int, java.lang.String, int, java.lang.String, int, int, java.lang.String, int);
|
void logPacket(int, java.lang.String, int, java.lang.String, int, int, java.lang.String, int);
|
||||||
void protectSocket(int);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Support library
|
#Support library
|
||||||
|
|
|
@ -750,15 +750,6 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
last_interactive).close();
|
last_interactive).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void protectSocket(int socket) {
|
|
||||||
try {
|
|
||||||
if (!protect(socket))
|
|
||||||
Log.e(TAG, "Failed to protect socket");
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopReceiving() {
|
private void stopReceiving() {
|
||||||
if (receiveThread != null)
|
if (receiveThread != null)
|
||||||
receiveThread.interrupt();
|
receiveThread.interrupt();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#define TAG "NetGuard.JNI"
|
#define TAG "NetGuard.JNI"
|
||||||
#define MAXPKT 32768
|
#define MAXPKT 32768
|
||||||
|
#define TIMEOUTPKT 30
|
||||||
|
|
||||||
struct packet {
|
struct packet {
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -20,12 +21,14 @@ struct packet {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct connection {
|
struct connection {
|
||||||
|
time_t time;
|
||||||
int32_t saddr;
|
int32_t saddr;
|
||||||
__be16 source;
|
__be16 source;
|
||||||
int32_t daddr;
|
int32_t daddr;
|
||||||
__be16 dest;
|
__be16 dest;
|
||||||
int state;
|
int state;
|
||||||
int socket;
|
int socket;
|
||||||
|
int lport;
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
struct connection *next;
|
struct connection *next;
|
||||||
};
|
};
|
||||||
|
@ -36,7 +39,7 @@ void decode(JNIEnv *env, jobject instance, jbyte *, int);
|
||||||
|
|
||||||
int getUid(int, int, void *, int);
|
int getUid(int, int, void *, int);
|
||||||
|
|
||||||
void handle_tcp4(JNIEnv *, jobject, void *, int);
|
void handle_tcp(JNIEnv *, jobject, jbyte *, int);
|
||||||
|
|
||||||
void poll();
|
void poll();
|
||||||
|
|
||||||
|
@ -76,14 +79,33 @@ Java_eu_faircode_netguard_SinkholeService_jni_1receive(JNIEnv *env, jobject inst
|
||||||
// Private functions
|
// Private functions
|
||||||
|
|
||||||
void poll() {
|
void poll() {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
struct connection *last = NULL;
|
struct connection *last = NULL;
|
||||||
struct connection *cur = connection;
|
struct connection *cur = connection;
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
if (cur->state == TCP_SYN_RECV) {
|
|
||||||
// Log
|
// Log
|
||||||
char dest[20];
|
char dest[20];
|
||||||
inet_ntop(AF_INET, &(cur->daddr), dest, sizeof(dest));
|
inet_ntop(AF_INET, &(cur->daddr), dest, sizeof(dest));
|
||||||
__android_log_print(ANDROID_LOG_DEBUG, TAG, "SYN poll %s/%d", dest, ntohs(cur->dest));
|
|
||||||
|
if (cur->state == TCP_CLOSE || cur->time + TIMEOUTPKT < now) {
|
||||||
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Close/timeout %s/%d lport=%d",
|
||||||
|
dest, ntohs(cur->dest), cur->lport);
|
||||||
|
|
||||||
|
shutdown(cur->socket, SHUT_RDWR);
|
||||||
|
|
||||||
|
if (last == NULL)
|
||||||
|
connection = cur->next;
|
||||||
|
else
|
||||||
|
last->next = cur->next;
|
||||||
|
|
||||||
|
free(cur->packet);
|
||||||
|
free(cur);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (cur->state == TCP_SYN_RECV) {
|
||||||
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Poll %s/%d lport=%d",
|
||||||
|
dest, ntohs(cur->dest), cur->lport);
|
||||||
|
|
||||||
// Check connection state
|
// Check connection state
|
||||||
fd_set wfds;
|
fd_set wfds;
|
||||||
|
@ -92,37 +114,54 @@ void poll() {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
int ready = select(1, NULL, &wfds, NULL, &tv);
|
int ready = select(cur->socket + 1, NULL, &wfds, NULL, &tv);
|
||||||
if (ready < 0) {
|
if (ready < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "select error %d: %s", errno,
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "select error %d: %s",
|
||||||
strerror(errno));
|
errno, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connected
|
// Connected
|
||||||
if (ready == 1) {
|
if (ready == 1) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, TAG, "Established");
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Established ready=%d", ready);
|
||||||
|
|
||||||
|
int serr;
|
||||||
|
int optlen = sizeof(serr);
|
||||||
|
if (getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen) < 0) {
|
||||||
|
// TODO
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "getsockopt error %d: %s",
|
||||||
|
errno, strerror(errno));
|
||||||
|
cur->state = TCP_CLOSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (serr) {
|
||||||
|
// TODO
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "SO_ERROR %d: %s",
|
||||||
|
serr, strerror(serr));
|
||||||
|
cur->state = TCP_CLOSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Send ACK
|
// Send ACK
|
||||||
cur->state = TCP_ESTABLISHED;
|
cur->state = TCP_ESTABLISHED;
|
||||||
|
|
||||||
if (last == NULL)
|
|
||||||
connection = cur->next;
|
|
||||||
else
|
|
||||||
last->next = cur->next;
|
|
||||||
free(cur->packet);
|
|
||||||
free(cur);
|
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "Connecting");
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "Connecting ready=%d", ready);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_tcp4(JNIEnv *env, jobject instance, void *buffer, int len) {
|
void handle_tcp(JNIEnv *env, jobject instance, jbyte *buffer, int len) {
|
||||||
|
// Check version
|
||||||
|
jbyte version = (*buffer) >> 4;
|
||||||
|
if (version != 4)
|
||||||
|
return;
|
||||||
|
|
||||||
// Copy buffer
|
// Copy buffer
|
||||||
jbyte *copy = malloc(len); // TODO free
|
jbyte *copy = malloc(len); // TODO free
|
||||||
memcpy(copy, buffer, len);
|
memcpy(copy, buffer, len);
|
||||||
|
@ -146,10 +185,11 @@ void handle_tcp4(JNIEnv *env, jobject instance, void *buffer, int len) {
|
||||||
|
|
||||||
if (cur == NULL) {
|
if (cur == NULL) {
|
||||||
if (tcphdr->syn) {
|
if (tcphdr->syn) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, TAG, "SYN %s/%d", dest, ntohs(tcphdr->dest));
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "SYN %s/%d", dest, ntohs(tcphdr->dest));
|
||||||
|
|
||||||
// Register connection
|
// Register connection
|
||||||
struct connection *syn = malloc(sizeof(struct connection));
|
struct connection *syn = malloc(sizeof(struct connection));
|
||||||
|
syn->time = time(NULL);
|
||||||
syn->saddr = iphdr->saddr;
|
syn->saddr = iphdr->saddr;
|
||||||
syn->source = tcphdr->source;
|
syn->source = tcphdr->source;
|
||||||
syn->daddr = iphdr->daddr;
|
syn->daddr = iphdr->daddr;
|
||||||
|
@ -168,60 +208,79 @@ void handle_tcp4(JNIEnv *env, jobject instance, void *buffer, int len) {
|
||||||
// Get TCP socket
|
// Get TCP socket
|
||||||
if ((syn->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
if ((syn->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "socket error %d: %s", errno,
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "socket error %d: %s",
|
||||||
strerror(errno));
|
errno, strerror(errno));
|
||||||
syn->state = TCP_CLOSE;
|
syn->state = TCP_CLOSE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set non blocking
|
// Set non blocking
|
||||||
int flags = fcntl(syn->socket, F_GETFL, 0);
|
int flags = fcntl(syn->socket, F_GETFL, 0);
|
||||||
if (fcntl(syn->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
|
if (flags < 0 || fcntl(syn->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "fcntl error %d: %s", errno,
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "fcntl error %d: %s",
|
||||||
strerror(errno));
|
errno, strerror(errno));
|
||||||
syn->state = TCP_CLOSE;
|
syn->state = TCP_CLOSE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protect
|
// Protect
|
||||||
jclass cls = (*env)->GetObjectClass(env, instance);
|
jclass cls = (*env)->GetObjectClass(env, instance);
|
||||||
// TODO: call VpnService.protect
|
jmethodID mid = (*env)->GetMethodID(env, cls, "protect", "(I)Z");
|
||||||
jmethodID mid = (*env)->GetMethodID(env, cls, "protectSocket", "(I)V");
|
|
||||||
if (mid == 0) {
|
if (mid == 0) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "protectSocket not found");
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "protect not found");
|
||||||
syn->state = TCP_CLOSE;
|
syn->state = TCP_CLOSE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(*env)->CallVoidMethod(env, instance, mid, syn->socket);
|
jboolean isProtected = (*env)->CallBooleanMethod(env, instance, mid, syn->socket);
|
||||||
// TODO handle exceptions
|
if (!isProtected)
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "protect failed");
|
||||||
|
|
||||||
|
jthrowable ex = (*env)->ExceptionOccurred(env);
|
||||||
|
if (ex) {
|
||||||
|
(*env)->ExceptionDescribe(env);
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
(*env)->DeleteLocalRef(env, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target address
|
// Build target address
|
||||||
struct sockaddr_in a;
|
struct sockaddr_in a;
|
||||||
memset(&a, 0, sizeof(struct sockaddr_in));
|
memset(&a, 0, sizeof(struct sockaddr_in));
|
||||||
a.sin_family = AF_INET;
|
a.sin_family = AF_INET;
|
||||||
a.sin_port = tcphdr->dest;
|
a.sin_port = tcphdr->dest;
|
||||||
a.sin_addr.s_addr = iphdr->daddr;
|
a.sin_addr.s_addr = iphdr->daddr;
|
||||||
|
|
||||||
|
// Initiate connect
|
||||||
int err = connect(syn->socket, &a, sizeof(struct sockaddr_in));
|
int err = connect(syn->socket, &a, sizeof(struct sockaddr_in));
|
||||||
if (err < 0 && errno != EINPROGRESS) {
|
if (err < 0 && errno != EINPROGRESS) {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "connect error %d: %s", errno,
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "connect error %d: %s",
|
||||||
strerror(errno));
|
errno, strerror(errno));
|
||||||
syn->state = TCP_CLOSE;
|
syn->state = TCP_CLOSE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, TAG, "Connecting to %s/%d", dest,
|
// Get local port
|
||||||
ntohs(tcphdr->dest));
|
struct sockaddr_in sin;
|
||||||
|
int sinlen = sizeof(sin);
|
||||||
|
if (getsockname(syn->socket, &sin, &sinlen) < 0)
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, TAG, "getsockname error %d: %s",
|
||||||
|
errno, strerror(errno));
|
||||||
|
else
|
||||||
|
syn->lport = ntohs(sin.sin_port);
|
||||||
|
|
||||||
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Connecting to %s/%d lport=%d",
|
||||||
|
dest, ntohs(tcphdr->dest), syn->lport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
cur->time = time(NULL);
|
||||||
|
|
||||||
if (tcphdr->syn) {
|
if (tcphdr->syn) {
|
||||||
// TODO
|
// TODO
|
||||||
__android_log_print(ANDROID_LOG_INFO, TAG, "SYNx2 %s/%d", dest, ntohs(tcphdr->dest));
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "SYNx2 %s/%d", dest, ntohs(tcphdr->dest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,13 +375,11 @@ void decode(JNIEnv *env, jobject instance, jbyte *buffer, int length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Packet v%d %s/%d -> %s/%d proto %d flags %s uid %d",
|
||||||
__android_log_print(ANDROID_LOG_INFO, TAG, "Packet v%d %s/%d -> %s/%d proto %d flags %s uid %d",
|
|
||||||
version, source, sport, dest, dport, protocol, flags, uid);
|
version, source, sport, dest, dport, protocol, flags, uid);
|
||||||
poll();
|
poll();
|
||||||
if (protocol == IPPROTO_TCP && version == 4)
|
if (protocol == IPPROTO_TCP)
|
||||||
handle_tcp4(env, instance, buffer, length);
|
handle_tcp(env, instance, buffer, length);
|
||||||
*/
|
|
||||||
|
|
||||||
// Call back
|
// Call back
|
||||||
jclass cls = (*env)->GetObjectClass(env, instance);
|
jclass cls = (*env)->GetObjectClass(env, instance);
|
||||||
|
|
Loading…
Reference in New Issue