Native SYN fixes/improvements

This commit is contained in:
M66B 2016-01-12 09:45:58 +01:00
parent 806196bc69
commit 84ea3d5f6e
3 changed files with 114 additions and 67 deletions

View File

@ -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

View File

@ -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();

View File

@ -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,53 +79,89 @@ 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));
// Check connection state if (cur->state == TCP_CLOSE || cur->time + TIMEOUTPKT < now) {
fd_set wfds; __android_log_print(ANDROID_LOG_DEBUG, TAG, "Close/timeout %s/%d lport=%d",
FD_ZERO(&wfds); dest, ntohs(cur->dest), cur->lport);
FD_SET(cur->socket, &wfds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int ready = select(1, NULL, &wfds, NULL, &tv);
if (ready < 0) {
// TODO
__android_log_print(ANDROID_LOG_ERROR, TAG, "select error %d: %s", errno,
strerror(errno));
continue;
}
// Connected shutdown(cur->socket, SHUT_RDWR);
if (ready == 1) {
__android_log_print(ANDROID_LOG_INFO, TAG, "Established");
// Send ACK
cur->state = TCP_ESTABLISHED;
if (last == NULL) if (last == NULL)
connection = cur->next; connection = cur->next;
else else
last->next = cur->next; last->next = cur->next;
free(cur->packet);
free(cur);
} else {
// TODO
__android_log_print(ANDROID_LOG_ERROR, TAG, "Connecting");
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
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(cur->socket, &wfds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int ready = select(cur->socket + 1, NULL, &wfds, NULL, &tv);
if (ready < 0) {
// TODO
__android_log_print(ANDROID_LOG_ERROR, TAG, "select error %d: %s",
errno, strerror(errno));
continue;
}
// Connected
if (ready == 1) {
__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
cur->state = TCP_ESTABLISHED;
} else {
// TODO
__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);