Native RST, error checking

This commit is contained in:
M66B 2016-01-15 10:28:31 +01:00
parent ab9ecde817
commit aeb9591884
1 changed files with 97 additions and 84 deletions

View File

@ -13,24 +13,16 @@
#include <netinet/udp.h> #include <netinet/udp.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
// 3 way handshake
// -> SYN seq=x
// <- SYN-ACK ack=x+1 seq=y
// -> ACK=y+1 seq=x+1
// https://www.gasmi.net/hpd/
// Ethernet frame: 0800 2086 354b 00e0 f726 3fe9 0800
// http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable
// TODO TCP fragmentation // TODO TCP fragmentation
// TODO TCP push // TODO TCP push
// TODO log allowed traffic
// TODO header file // TODO header file
// TODO debug switches // TODO debug switches
#define TAG "NetGuard.JNI" #define TAG "NetGuard.JNI"
#define MAXPKT 32678 #define MAXPKT 32678
// TODO TCP parameters // TODO TCP parameters
#define SELECTWAIT 10
#define TCPTIMEOUT 30 #define TCPTIMEOUT 30
#define TCPTTL 64 #define TCPTTL 64
#define TCPWINDOW 2048 #define TCPWINDOW 2048
@ -48,6 +40,7 @@ struct data {
struct connection { struct connection {
time_t time; time_t time;
int uid;
uint32_t remote_seq; // confirmed bytes received, host notation uint32_t remote_seq; // confirmed bytes received, host notation
uint32_t local_seq; // confirmed bytes sent, host notation uint32_t local_seq; // confirmed bytes sent, host notation
int32_t saddr; // network notation int32_t saddr; // network notation
@ -63,7 +56,8 @@ struct connection {
void *handle_events(void *); void *handle_events(void *);
void handle_tcp(JNIEnv *, jobject, const struct arguments *args, const uint8_t *, const uint16_t); void handle_tcp(JNIEnv *, jobject, const struct arguments *args,
const uint8_t *, const uint16_t, int uid);
int openSocket(JNIEnv *, jobject, const struct sockaddr_in *); int openSocket(JNIEnv *, jobject, const struct sockaddr_in *);
@ -73,7 +67,7 @@ int canWrite(const int);
int writeTCP(const struct connection *, struct data *, uint16_t, int, int, int, int); int writeTCP(const struct connection *, struct data *, uint16_t, int, int, int, int);
void decode(JNIEnv *, jobject, const struct arguments *, const uint8_t *, const uint16_t); void handle_ip(JNIEnv *, jobject, const struct arguments *, const uint8_t *, const uint16_t);
jint getUid(const int, const int, const void *, const uint16_t); jint getUid(const int, const int, const void *, const uint16_t);
@ -211,27 +205,16 @@ void *handle_events(void *a) {
struct connection *last = NULL; struct connection *last = NULL;
struct connection *cur = connection; struct connection *cur = connection;
while (cur != NULL) { while (cur != NULL) {
if (cur->time + TCPTIMEOUT < now) { if (cur->state == TCP_CLOSE || cur->time + TCPTIMEOUT < now) {
// Log // Log
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, "Idle %s/%u lport %u open %d", __android_log_print(ANDROID_LOG_DEBUG, TAG, "Idle %s/%u lport %u close %d",
dest, ntohs(cur->dest), cur->lport, dest, ntohs(cur->dest), cur->lport,
(cur->state != TCP_CLOSE)); (cur->state == TCP_CLOSE));
if (cur->state == TCP_CLOSE) { if (close(cur->socket))
int serr; __android_log_print(ANDROID_LOG_ERROR, TAG, "close error %d: %s",
socklen_t optlen = sizeof(serr);
if (getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen) < 0)
__android_log_print(ANDROID_LOG_WARN, TAG, "getsockopt error %d: %s",
errno, strerror(errno)); errno, strerror(errno));
if (serr)
__android_log_print(ANDROID_LOG_WARN, TAG, "SO_ERROR %d: %s",
serr, strerror(serr));
else
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Socket was properly closed");
}
else
shutdown(cur->socket, SHUT_RDWR);
struct data *prev; struct data *prev;
struct data *sent = cur->sent; struct data *sent = cur->sent;
@ -270,7 +253,7 @@ void *handle_events(void *a) {
cur = cur->next; cur = cur->next;
} }
ts.tv_sec = 10; ts.tv_sec = SELECTWAIT;
ts.tv_nsec = 0; ts.tv_nsec = 0;
sigemptyset(&emptyset); sigemptyset(&emptyset);
int ready = pselect(max + 1, &rfds, &wfds, &efds, &ts, &emptyset); int ready = pselect(max + 1, &rfds, &wfds, &efds, &ts, &emptyset);
@ -309,7 +292,7 @@ void *handle_events(void *a) {
break; break;
} }
if (length > 0) if (length > 0)
decode(env, args->instance, args, buffer, length); handle_ip(env, args->instance, args, buffer, length);
else { else {
__android_log_print(ANDROID_LOG_ERROR, TAG, "tun empty read"); __android_log_print(ANDROID_LOG_ERROR, TAG, "tun empty read");
break; break;
@ -327,7 +310,6 @@ void *handle_events(void *a) {
__android_log_print(ANDROID_LOG_ERROR, TAG, "getsockopt error %d: %s", __android_log_print(ANDROID_LOG_ERROR, TAG, "getsockopt error %d: %s",
errno, strerror(errno)); errno, strerror(errno));
// TODO initiate finish // TODO initiate finish
shutdown(cur->socket, SHUT_RDWR);
cur->state = TCP_CLOSE; cur->state = TCP_CLOSE;
cur = cur->next; cur = cur->next;
continue; continue;
@ -336,7 +318,6 @@ void *handle_events(void *a) {
__android_log_print(ANDROID_LOG_ERROR, TAG, "SO_ERROR %d: %s", __android_log_print(ANDROID_LOG_ERROR, TAG, "SO_ERROR %d: %s",
serr, strerror(serr)); serr, strerror(serr));
// TODO initiate FIN // TODO initiate FIN
shutdown(cur->socket, SHUT_RDWR);
cur->state = TCP_CLOSE; cur->state = TCP_CLOSE;
cur = cur->next; cur = cur->next;
continue; continue;
@ -352,12 +333,13 @@ void *handle_events(void *a) {
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Established %s/%u lport %u", __android_log_print(ANDROID_LOG_DEBUG, TAG, "Established %s/%u lport %u",
dest, ntohs(cur->dest), cur->lport); dest, ntohs(cur->dest), cur->lport);
// TODO can write
if (writeTCP(cur, NULL, 1, 1, 0, 0, args->tun) < 0) { // SYN if (writeTCP(cur, NULL, 1, 1, 0, 0, args->tun) < 0) { // SYN
__android_log_print(ANDROID_LOG_DEBUG, TAG, "write SYN error %d: %s", __android_log_print(ANDROID_LOG_ERROR, TAG, "write SYN error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
// Remote will retry
shutdown(cur->socket, SHUT_RDWR);
cur->state = TCP_CLOSE; cur->state = TCP_CLOSE;
cur = cur->next;
continue;
} else } else
cur->state = TCP_SYN_SENT; cur->state = TCP_SYN_SENT;
} }
@ -373,7 +355,6 @@ void *handle_events(void *a) {
errno, strerror(errno)); errno, strerror(errno));
if (errno != EINTR) { if (errno != EINTR) {
// TODO initiate FIN // TODO initiate FIN
shutdown(cur->socket, SHUT_RDWR);
cur->state = TCP_CLOSE; cur->state = TCP_CLOSE;
cur = cur->next; cur = cur->next;
continue; continue;
@ -381,12 +362,16 @@ void *handle_events(void *a) {
} }
else if (bytes == 0) { else if (bytes == 0) {
if (cur->state == TCP_ESTABLISHED) { if (cur->state == TCP_ESTABLISHED) {
__android_log_print(ANDROID_LOG_WARN, TAG, "recv socket empty");
// TODO initiate FIN // TODO initiate FIN
__android_log_print(ANDROID_LOG_WARN, TAG, "recv socket empty");
cur->state = TCP_CLOSE;
cur = cur->next;
continue;
} }
else if (cur->state == TCP_CLOSE_WAIT) { else if (cur->state == TCP_CLOSE_WAIT) {
// TODO can write
if (writeTCP(cur, NULL, 1, 0, 1, 0, args->tun) < 0) // FIN if (writeTCP(cur, NULL, 1, 0, 1, 0, args->tun) < 0) // FIN
__android_log_print(ANDROID_LOG_DEBUG, TAG, __android_log_print(ANDROID_LOG_ERROR, TAG,
"write FIN error %d: %s", "write FIN error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
else { else {
@ -405,10 +390,10 @@ void *handle_events(void *a) {
data->len = bytes; data->len = bytes;
data->data = malloc(bytes); data->data = malloc(bytes);
memcpy(data->data, buffer, bytes); memcpy(data->data, buffer, bytes);
// canWrite(args->tun)
// TODO can write
if (writeTCP(cur, data, 0, 0, 0, 0, args->tun) < 0) // ACK if (writeTCP(cur, data, 0, 0, 0, 0, args->tun) < 0) // ACK
__android_log_print(ANDROID_LOG_DEBUG, TAG, __android_log_print(ANDROID_LOG_ERROR, TAG,
"write ACK error %d: %s", "write ACK error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
else else
@ -443,7 +428,7 @@ void *handle_events(void *a) {
} }
void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args, void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
const uint8_t *buffer, uint16_t length) { const uint8_t *buffer, uint16_t length, int uid) {
// Check version // Check version
uint8_t version = (*buffer) >> 4; uint8_t version = (*buffer) >> 4;
if (version != 4) if (version != 4)
@ -491,8 +476,9 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
__android_log_print(ANDROID_LOG_DEBUG, TAG, "New SYN"); __android_log_print(ANDROID_LOG_DEBUG, TAG, "New SYN");
// Register connection // Register connection
struct connection *syn = malloc(sizeof(struct connection)); // TODO check/free struct connection *syn = malloc(sizeof(struct connection)); // TODO free
syn->time = time(NULL); syn->time = time(NULL);
syn->uid = uid;
syn->remote_seq = ntohl(tcphdr->seq); // ISN remote syn->remote_seq = ntohl(tcphdr->seq); // ISN remote
syn->local_seq = rand(); // ISN local syn->local_seq = rand(); // ISN local
syn->saddr = iphdr->saddr; syn->saddr = iphdr->saddr;
@ -534,8 +520,27 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
last->next = syn; last->next = syn;
} }
} }
else else {
__android_log_print(ANDROID_LOG_WARN, TAG, "Unknown connection"); __android_log_print(ANDROID_LOG_WARN, TAG, "Unknown connection");
struct connection *rst = malloc(sizeof(struct connection));
rst->time = time(NULL);
rst->remote_seq = ntohl(tcphdr->seq); // ISN remote
rst->local_seq = rand(); // ISN local
rst->saddr = iphdr->saddr;
rst->source = tcphdr->source;
rst->daddr = iphdr->daddr;
rst->dest = tcphdr->dest;
rst->state = TCP_CLOSE;
rst->sent = NULL;
rst->next = NULL;
// TODO can write
if (writeTCP(rst, NULL, 0, 0, 0, 1, args->tun) < 0)
__android_log_print(ANDROID_LOG_ERROR, TAG,
"write RST error %d: %s",
errno, strerror((errno)));
free(rst);
}
} }
else { else {
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Existing connection lport %u", cur->lport); __android_log_print(ANDROID_LOG_DEBUG, TAG, "Existing connection lport %u", cur->lport);
@ -564,7 +569,7 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
else if (cur->state == TCP_ESTABLISHED) { else if (cur->state == TCP_ESTABLISHED) {
// TODO proper wrap around // TODO proper wrap around
if (ntohl(tcphdr->seq) + 1 == cur->remote_seq) if (ntohl(tcphdr->seq) + 1 == cur->remote_seq)
// TODO respond to keepalive? // TODO respond to keep alive?
__android_log_print(ANDROID_LOG_DEBUG, TAG, "Keep alive"); __android_log_print(ANDROID_LOG_DEBUG, TAG, "Keep alive");
else if (ntohl(tcphdr->seq) < cur->remote_seq) else if (ntohl(tcphdr->seq) < cur->remote_seq)
__android_log_print(ANDROID_LOG_WARN, TAG, "Processed ack"); __android_log_print(ANDROID_LOG_WARN, TAG, "Processed ack");
@ -578,9 +583,10 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
__android_log_print(ANDROID_LOG_ERROR, TAG, "send error %d: %s", __android_log_print(ANDROID_LOG_ERROR, TAG, "send error %d: %s",
errno, strerror(errno)); errno, strerror(errno));
else { else {
// TODO can write
if (writeTCP(cur, NULL, data->len, 0, 0, 0, args->tun) < 0) // ACK if (writeTCP(cur, NULL, data->len, 0, 0, 0, args->tun) < 0) // ACK
__android_log_print(ANDROID_LOG_DEBUG, TAG, __android_log_print(ANDROID_LOG_ERROR, TAG,
"write ACK error %d: %s", "write data error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
else else
cur->remote_seq += data->len; cur->remote_seq += data->len;
@ -604,12 +610,12 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
} }
else else
__android_log_print(ANDROID_LOG_WARN, TAG, "ACK Invalid state %d", cur->state); __android_log_print(ANDROID_LOG_WARN, TAG, "Invalid ACK state %d", cur->state);
} }
if (tcphdr->fin) { if (tcphdr->fin) {
if (cur->state == TCP_ESTABLISHED) { if (cur->state == TCP_ESTABLISHED) {
if (shutdown(cur->socket, SHUT_RDWR)) if (shutdown(cur->socket, SHUT_RD))
__android_log_print(ANDROID_LOG_ERROR, TAG, "shutdown error %d: %s", __android_log_print(ANDROID_LOG_ERROR, TAG, "shutdown error %d: %s",
errno, strerror(errno)); errno, strerror(errno));
else else
@ -617,11 +623,10 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
cur->state = TCP_CLOSE_WAIT; cur->state = TCP_CLOSE_WAIT;
} }
else else
__android_log_print(ANDROID_LOG_WARN, TAG, "FIN Invalid state %d", cur->state); __android_log_print(ANDROID_LOG_WARN, TAG, "Invalid FIN state %d", cur->state);
} }
if (tcphdr->rst) { if (tcphdr->rst) {
shutdown(cur->socket, SHUT_RDWR);
cur->state = TCP_CLOSE; cur->state = TCP_CLOSE;
} }
} }
@ -710,7 +715,7 @@ int writeTCP(const struct connection *cur,
int syn, int fin, int rst, int tun) { int syn, int fin, int rst, int tun) {
// Build packet // Build packet
uint16_t datalen = (data == NULL ? 0 : data->len); uint16_t datalen = (data == NULL ? 0 : data->len);
uint16_t len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen; // no data uint16_t len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen;
u_int8_t *buffer = calloc(len, 1); u_int8_t *buffer = calloc(len, 1);
struct iphdr *ip = buffer; struct iphdr *ip = buffer;
struct tcphdr *tcp = buffer + sizeof(struct iphdr); struct tcphdr *tcp = buffer + sizeof(struct iphdr);
@ -751,7 +756,7 @@ int writeTCP(const struct connection *cur,
pseudo->ippseudo_dst.s_addr = ip->daddr; pseudo->ippseudo_dst.s_addr = ip->daddr;
pseudo->ippseudo_pad = 0; pseudo->ippseudo_pad = 0;
pseudo->ippseudo_p = ip->protocol; pseudo->ippseudo_p = ip->protocol;
pseudo->ippseudo_len = htons(sizeof(struct tcphdr) + datalen); // no data pseudo->ippseudo_len = htons(sizeof(struct tcphdr) + datalen);
// Copy TCP header + data // Copy TCP header + data
memcpy(csum + sizeof(struct ippseudo), tcp, sizeof(struct tcphdr)); memcpy(csum + sizeof(struct ippseudo), tcp, sizeof(struct tcphdr));
@ -779,7 +784,7 @@ int writeTCP(const struct connection *cur,
return res; return res;
} }
void decode(JNIEnv *env, jobject instance, const struct arguments *args, void handle_ip(JNIEnv *env, jobject instance, const struct arguments *args,
const uint8_t *buffer, const uint16_t length) { const uint8_t *buffer, const uint16_t length) {
uint8_t protocol; uint8_t protocol;
void *saddr; void *saddr;
@ -838,6 +843,7 @@ void decode(JNIEnv *env, jobject instance, const struct arguments *args,
inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest)); inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest));
// Get ports & flags // Get ports & flags
int syn = 0;
uint16_t sport = -1; uint16_t sport = -1;
uint16_t dport = -1; uint16_t dport = -1;
if (protocol == IPPROTO_TCP) { if (protocol == IPPROTO_TCP) {
@ -846,8 +852,10 @@ void decode(JNIEnv *env, jobject instance, const struct arguments *args,
sport = ntohs(tcp->source); sport = ntohs(tcp->source);
dport = ntohs(tcp->dest); dport = ntohs(tcp->dest);
if (tcp->syn) if (tcp->syn) {
syn = 1;
flags[flen++] = 'S'; flags[flen++] = 'S';
}
if (tcp->ack) if (tcp->ack)
flags[flen++] = 'A'; flags[flen++] = 'A';
if (tcp->psh) if (tcp->psh)
@ -894,9 +902,10 @@ void decode(JNIEnv *env, jobject instance, const struct arguments *args,
version, source, sport, dest, dport, protocol, flags, uid); version, source, sport, dest, dport, protocol, flags, uid);
if (protocol == IPPROTO_TCP) if (protocol == IPPROTO_TCP)
handle_tcp(env, instance, args, buffer, length); handle_tcp(env, instance, args, buffer, length, uid);
// Call back // Call back
if ((protocol == IPPROTO_TCP && syn) || protocol == IPPROTO_UDP) {
jclass cls = (*env)->GetObjectClass(env, instance); jclass cls = (*env)->GetObjectClass(env, instance);
jmethodID mid = (*env)->GetMethodID(env, cls, "logPacket", jmethodID mid = (*env)->GetMethodID(env, cls, "logPacket",
"(ILjava/lang/String;ILjava/lang/String;IILjava/lang/String;IZ)V"); "(ILjava/lang/String;ILjava/lang/String;IILjava/lang/String;IZ)V");
@ -925,6 +934,7 @@ void decode(JNIEnv *env, jobject instance, const struct arguments *args,
} }
} }
(*env)->DeleteLocalRef(env, cls); (*env)->DeleteLocalRef(env, cls);
}
} }
jint getUid(const int protocol, const int version, const void *saddr, const uint16_t sport) { jint getUid(const int protocol, const int version, const void *saddr, const uint16_t sport) {
@ -947,7 +957,8 @@ jint getUid(const int protocol, const int version, const void *saddr, const uint
// Open proc file // Open proc file
FILE *fd = fopen(fn, "r"); FILE *fd = fopen(fn, "r");
if (fd == NULL) { if (fd == NULL) {
__android_log_print(ANDROID_LOG_ERROR, TAG, "Error opening %s", fn); __android_log_print(ANDROID_LOG_ERROR, TAG, "fopen %s error %d: %s",
fn, errno, strerror(errno));
return -1; return -1;
} }
@ -982,7 +993,9 @@ jint getUid(const int protocol, const int version, const void *saddr, const uint
} }
} }
fclose(fd); if (fclose(fd))
__android_log_print(ANDROID_LOG_ERROR, TAG, "fclose %s error %d: %s",
fn, errno, strerror(errno));
return -1; return -1;
} }