Native socket eof/error handling

This commit is contained in:
M66B 2016-01-17 16:26:37 +01:00
parent e525ec7050
commit 49b15e261d
1 changed files with 78 additions and 94 deletions

View File

@ -98,8 +98,6 @@ int openSocket(JNIEnv *, jobject, const struct sockaddr_in *);
int getLocalPort(const int); int getLocalPort(const int);
int canWrite(const int);
int writeTCP(const struct session *, uint8_t *, uint16_t, uint16_t, int, int, int, int); int writeTCP(const struct session *, uint8_t *, uint16_t, uint16_t, int, int, int, int);
jint getUid(const int, const int, const void *, const uint16_t); jint getUid(const int, const int, const void *, const uint16_t);
@ -298,7 +296,6 @@ void *handle_events(void *a) {
if (cur->state == TCP_SYN_RECV || if (cur->state == TCP_SYN_RECV ||
cur->state == TCP_ESTABLISHED || cur->state == TCP_ESTABLISHED ||
cur->state == TCP_CLOSE_WAIT) { cur->state == TCP_CLOSE_WAIT) {
// TODO can write
if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) { // FIN if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) { // FIN
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"write FIN lport %u error %d: %s", "write FIN lport %u error %d: %s",
@ -343,6 +340,7 @@ void *handle_events(void *a) {
} else if (cur->state != TCP_TIME_WAIT) { } else if (cur->state != TCP_TIME_WAIT) {
if (cur->state == TCP_LISTEN) { if (cur->state == TCP_LISTEN) {
FD_SET(cur->socket, &efds);
FD_SET(cur->socket, &wfds); FD_SET(cur->socket, &wfds);
if (cur->socket > max) if (cur->socket > max)
max = cur->socket; max = cur->socket;
@ -350,6 +348,7 @@ void *handle_events(void *a) {
else if (cur->state == TCP_ESTABLISHED || else if (cur->state == TCP_ESTABLISHED ||
cur->state == TCP_SYN_RECV || cur->state == TCP_SYN_RECV ||
cur->state == TCP_CLOSE_WAIT) { cur->state == TCP_CLOSE_WAIT) {
FD_SET(cur->socket, &efds);
FD_SET(cur->socket, &rfds); FD_SET(cur->socket, &rfds);
if (cur->socket > max) if (cur->socket > max)
max = cur->socket; max = cur->socket;
@ -447,105 +446,104 @@ void *handle_events(void *a) {
// Check sockets // Check sockets
struct session *cur = session; struct session *cur = session;
while (cur != NULL) { while (cur != NULL) {
// Check socket exception
if (FD_ISSET(cur->socket, &efds)) { if (FD_ISSET(cur->socket, &efds)) {
// Socket exception
int serr; int serr;
socklen_t optlen = sizeof(serr); socklen_t optlen = sizeof(int);
if (getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen) < 0) { int err = getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen);
if (err < 0)
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"getsockopt lport %u error %d: %s", "getsockopt lport %u error %d: %s",
cur->lport, errno, strerror(errno)); cur->lport, errno, strerror(errno));
// TODO initiate finish if (err < 0 || serr) {
cur->state = TCP_TIME_WAIT; // will close socket
cur = cur->next;
continue;
}
if (serr) {
ng_log(ANDROID_LOG_ERROR, "lport %u SO_ERROR %d: %s", ng_log(ANDROID_LOG_ERROR, "lport %u SO_ERROR %d: %s",
cur->lport, serr, strerror(serr)); cur->lport, serr, strerror(serr));
// TODO initiate FIN if (err < 0 || (serr && serr != EINTR)) {
if (serr != EINTR) if (writeTCP(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
cur->state = TCP_TIME_WAIT; // will close socket ng_log(ANDROID_LOG_ERROR,
cur = cur->next; "write RST error %d: %s",
continue; errno, strerror((errno)));
}
}
if (cur->state == TCP_LISTEN) {
// Check socket connect
if (FD_ISSET(cur->socket, &wfds) && canWrite(args->tun)) {
// Log
char dest[20];
inet_ntop(AF_INET, &(cur->daddr), dest, sizeof(dest));
ng_log(ANDROID_LOG_DEBUG, "Connected lport %u %s/%u",
cur->lport, dest, ntohs(cur->dest));
// TODO can write
if (writeTCP(cur, NULL, 0, 1, 1, 0, 0, args->tun) < 0) { // SYN+ACK
ng_log(ANDROID_LOG_ERROR,
"write SYN+ACK error %d: %s",
errno, strerror((errno)));
// Remote will retry
cur->state = TCP_TIME_WAIT; // will close socket
cur = cur->next;
continue;
} else {
cur->local_seq++; // local SYN
cur->remote_seq++; // remote SYN
cur->state = TCP_SYN_RECV;
} }
} }
} }
else {
// Assume socket okay
if (cur->state == TCP_LISTEN) {
// Check socket connect
if (FD_ISSET(cur->socket, &wfds)) {
// Log
char dest[20];
inet_ntop(AF_INET, &(cur->daddr), dest, sizeof(dest));
ng_log(ANDROID_LOG_DEBUG, "Connected lport %u %s/%u",
cur->lport, dest, ntohs(cur->dest));
else if (cur->state == TCP_SYN_RECV || if (writeTCP(cur, NULL, 0, 1, 1, 0, 0, args->tun) < 0) { // SYN+ACK
cur->state == TCP_ESTABLISHED || ng_log(ANDROID_LOG_ERROR,
cur->state == TCP_CLOSE_WAIT) { "write SYN+ACK error %d: %s",
// Check socket read errno, strerror((errno)));
if (FD_ISSET(cur->socket, &rfds)) { // Remote will retry
// TODO window size cur->state = TCP_TIME_WAIT; // will close socket
uint8_t buffer[MAXPKT]; cur = cur->next;
ssize_t bytes = recv(cur->socket, buffer, MAXPKT, 0); continue;
if (bytes <= 0) { } else {
// Socket remotely closed / error cur->local_seq++; // local SYN
cur->remote_seq++; // remote SYN
cur->state = TCP_SYN_RECV;
}
}
}
else if (cur->state == TCP_SYN_RECV ||
cur->state == TCP_ESTABLISHED ||
cur->state == TCP_CLOSE_WAIT) {
// Check socket read
if (FD_ISSET(cur->socket, &rfds)) {
// TODO window size
uint8_t buffer[MAXPKT];
ssize_t bytes = recv(cur->socket, buffer, MAXPKT, 0);
if (bytes < 0) { if (bytes < 0) {
// Socket error
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"recv lport %u error %d: %s", "recv lport %u error %d: %s",
cur->lport, errno, strerror(errno)); cur->lport, errno, strerror(errno));
if (errno == EINTR) { if (errno != EINTR) {
cur = cur->next; if (writeTCP(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
continue; ng_log(ANDROID_LOG_ERROR,
"write RST error %d: %s",
errno, strerror((errno)));
} }
} }
else else if (bytes == 0) {
// Socket peer closed
ng_log(ANDROID_LOG_DEBUG, ng_log(ANDROID_LOG_DEBUG,
"recv empty lport %u state %s", "recv empty lport %u state %s",
cur->lport, strstate(cur->state)); cur->lport, strstate(cur->state));
// TODO can write if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) // FIN
if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) // FIN ng_log(ANDROID_LOG_ERROR,
ng_log(ANDROID_LOG_ERROR, "write FIN lport %u error %d: %s",
"write FIN lport %u error %d: %s", cur->lport, errno, strerror((errno)));
cur->lport, errno, strerror((errno))); else {
else { cur->local_seq++; // local FIN
cur->local_seq++; // local FIN if (cur->state == TCP_SYN_RECV || cur->state == TCP_ESTABLISHED)
if (cur->state == TCP_SYN_RECV || cur->state == TCP_ESTABLISHED) cur->state = TCP_FIN_WAIT1;
cur->state = TCP_FIN_WAIT1; else // close wait
else // close wait cur->state = TCP_LAST_ACK;
cur->state = TCP_LAST_ACK; ng_log(ANDROID_LOG_DEBUG, "Half close state %s",
ng_log(ANDROID_LOG_DEBUG, "Half close state %s", strstate(cur->state));
strstate(cur->state)); }
} else {
// Socket read
ng_log(ANDROID_LOG_DEBUG,
"recv lport %u bytes %d state %s",
cur->lport, bytes, strstate(cur->state));
if (writeTCP(cur, buffer, bytes, 0, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR,
"write ACK lport %u error %d: %s",
cur->lport, errno, strerror((errno)));
else
cur->local_seq += bytes; // received from socket
} }
} else {
ng_log(ANDROID_LOG_DEBUG,
"recv lport %u bytes %d state %s",
cur->lport, bytes, strstate(cur->state));
// TODO can write
if (writeTCP(cur, buffer, bytes, 0, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR,
"write ACK lport %u error %d: %s",
cur->lport, errno, strerror((errno)));
else
cur->local_seq += bytes; // received from socket
} }
} }
} }
@ -808,7 +806,6 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
rst.daddr = iphdr->daddr; rst.daddr = iphdr->daddr;
rst.dest = tcphdr->dest; rst.dest = tcphdr->dest;
// TODO can write
if (writeTCP(&rst, NULL, 0, 0, 0, 0, 1, args->tun) < 0) if (writeTCP(&rst, NULL, 0, 0, 0, 0, 1, args->tun) < 0)
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"write RST error %d: %s", "write RST error %d: %s",
@ -872,7 +869,6 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
} }
if (ok) { if (ok) {
// TODO can write
if (writeTCP(cur, NULL, 0, 1 + datalen, 0, 0, 0, args->tun) < 0) // ACK if (writeTCP(cur, NULL, 0, 1 + datalen, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"write ACK error %d: %s", "write ACK error %d: %s",
@ -901,7 +897,6 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
int confirm = cur->local_seq - ntohl(tcphdr->ack_seq); int confirm = cur->local_seq - ntohl(tcphdr->ack_seq);
ng_log(ANDROID_LOG_INFO, "Simultaneous close %d", confirm); ng_log(ANDROID_LOG_INFO, "Simultaneous close %d", confirm);
// TODO can write
if (writeTCP(cur, NULL, 0, confirm, 0, 0, 0, args->tun) < 0) // ACK if (writeTCP(cur, NULL, 0, confirm, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"write ACK error %d: %s", "write ACK error %d: %s",
@ -940,7 +935,6 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
errno, strerror(errno)); errno, strerror(errno));
// Remote will retry // Remote will retry
} else { } else {
// TODO can write
if (writeTCP(cur, NULL, 0, datalen, 0, 0, 0, args->tun) < 0) // ACK if (writeTCP(cur, NULL, 0, datalen, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, ng_log(ANDROID_LOG_ERROR,
"write data error %d: %s", "write data error %d: %s",
@ -1059,16 +1053,6 @@ int getLocalPort(const int sock) {
return ntohs(sin.sin_port); return ntohs(sin.sin_port);
} }
int canWrite(const int fd) {
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
fd_set wfds;
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
return (select(fd + 1, NULL, &wfds, NULL, &tv) > 0);
}
int writeTCP(const struct session *cur, int writeTCP(const struct session *cur,
uint8_t *data, uint16_t datalen, uint16_t confirm, uint8_t *data, uint16_t datalen, uint16_t confirm,
int syn, int fin, int rst, int tun) { int syn, int fin, int rst, int tun) {