Native refactoring

This commit is contained in:
M66B 2016-01-17 17:39:11 +01:00
parent f624815db8
commit b61cc13d6d
1 changed files with 140 additions and 134 deletions

View File

@ -86,22 +86,22 @@ typedef struct pcaprec_hdr_s {
#define LINKTYPE_RAW 101 #define LINKTYPE_RAW 101
void pcap_write(const void *, size_t);
void *handle_events(void *); void *handle_events(void *);
void check_sockets(const struct arguments *, fd_set *, fd_set *, fd_set *);
void handle_ip(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);
void handle_tcp(JNIEnv *, jobject, const struct arguments *args, void handle_tcp(JNIEnv *, jobject, const struct arguments *args,
const uint8_t *, const uint16_t, int uid); const uint8_t *, const uint16_t, int uid);
int openSocket(JNIEnv *, jobject, const struct sockaddr_in *); int open_socket(JNIEnv *, jobject, const struct sockaddr_in *);
int getLocalPort(const int); int get_local_port(const int);
int writeTCP(const struct session *, uint8_t *, uint16_t, uint16_t, int, int, int, int); int write_tcp(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 get_uid(const int, const int, const void *, const uint16_t);
uint16_t checksum(uint8_t *, uint16_t); uint16_t checksum(uint8_t *, uint16_t);
@ -111,6 +111,8 @@ const char *strstate(const int state);
char *hex(const u_int8_t *, const u_int16_t); char *hex(const u_int8_t *, const u_int16_t);
void pcap_write(const void *, size_t);
// Global variables // Global variables
static JavaVM *jvm; static JavaVM *jvm;
@ -151,21 +153,6 @@ Java_eu_faircode_netguard_SinkholeService_jni_1init(JNIEnv *env, jobject instanc
(*env)->ReleaseStringUTFChars(env, pcap_, pcap); (*env)->ReleaseStringUTFChars(env, pcap_, pcap);
} }
void pcap_write(const void *ptr, size_t len) {
FILE *fd = fopen(pcap_fn, "ab");
if (fd == NULL)
ng_log(ANDROID_LOG_ERROR, "fopen %s error %d: %s", pcap_fn, errno, strerror(errno));
else {
if (fwrite(ptr, len, 1, fd) < 1)
ng_log(ANDROID_LOG_ERROR, "fwrite %s error %d: %s", pcap_fn, errno, strerror(errno));
else
ng_log(ANDROID_LOG_DEBUG, "PCAP write %d", len);
if (fclose(fd))
ng_log(ANDROID_LOG_ERROR, "fclose %s error %d: %s", pcap_fn, errno, strerror(errno));
}
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1start(JNIEnv *env, jobject instance, Java_eu_faircode_netguard_SinkholeService_jni_1start(JNIEnv *env, jobject instance,
jint tun) { jint tun) {
@ -292,7 +279,7 @@ 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) {
if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) { // FIN if (write_tcp(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)));
@ -437,104 +424,7 @@ void *handle_events(void *a) {
} }
// Check sockets // Check sockets
struct session *cur = session; check_sockets(args, &rfds, &wfds, &efds);
while (cur != NULL) {
if (FD_ISSET(cur->socket, &efds)) {
// Socket exception
int serr;
socklen_t optlen = sizeof(int);
int err = getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen);
if (err < 0)
ng_log(ANDROID_LOG_ERROR, "getsockopt lport %u error %d: %s",
cur->lport, errno, strerror(errno));
if (err < 0 || serr) {
ng_log(ANDROID_LOG_ERROR, "lport %u SO_ERROR %d: %s",
cur->lport, serr, strerror(serr));
if (err < 0 || (serr && serr != EINTR)) {
if (writeTCP(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
ng_log(ANDROID_LOG_ERROR, "write RST error %d: %s",
errno, strerror((errno)));
}
}
}
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_INFO, "Connected %s/%u lport %u",
dest, ntohs(cur->dest), cur->lport);
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 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) {
// Socket error
ng_log(ANDROID_LOG_ERROR, "recv lport %u error %d: %s",
cur->lport, errno, strerror(errno));
if (errno != EINTR) {
if (writeTCP(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
ng_log(ANDROID_LOG_ERROR, "write RST error %d: %s",
errno, strerror((errno)));
}
}
else if (bytes == 0) {
// Socket peer closed
ng_log(ANDROID_LOG_DEBUG, "recv empty lport %u state %s",
cur->lport, strstate(cur->state));
if (writeTCP(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) // FIN
ng_log(ANDROID_LOG_ERROR, "write FIN lport %u error %d: %s",
cur->lport, errno, strerror((errno)));
else {
cur->local_seq++; // local FIN
if (cur->state == TCP_SYN_RECV || cur->state == TCP_ESTABLISHED)
cur->state = TCP_FIN_WAIT1;
else // close wait
cur->state = TCP_LAST_ACK;
ng_log(ANDROID_LOG_DEBUG, "Half close state %s",
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
}
}
}
}
cur = cur->next;
}
} }
} }
@ -549,6 +439,107 @@ void *handle_events(void *a) {
// TODO conditionally report to Java // TODO conditionally report to Java
} }
void check_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) {
struct session *cur = session;
while (cur != NULL) {
if (FD_ISSET(cur->socket, efds)) {
// Socket exception
int serr;
socklen_t optlen = sizeof(int);
int err = getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen);
if (err < 0)
ng_log(ANDROID_LOG_ERROR, "getsockopt lport %u error %d: %s",
cur->lport, errno, strerror(errno));
if (err < 0 || serr) {
ng_log(ANDROID_LOG_ERROR, "lport %u SO_ERROR %d: %s",
cur->lport, serr, strerror(serr));
if (err < 0 || (serr && serr != EINTR)) {
if (write_tcp(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
ng_log(ANDROID_LOG_ERROR, "write RST error %d: %s",
errno, strerror((errno)));
}
}
}
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_INFO, "Connected %s/%u lport %u",
dest, ntohs(cur->dest), cur->lport);
if (write_tcp(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 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) {
// Socket error
ng_log(ANDROID_LOG_ERROR, "recv lport %u error %d: %s",
cur->lport, errno, strerror(errno));
if (errno != EINTR) {
if (write_tcp(cur, NULL, 0, 0, 0, 0, 1, args->tun) < 0) // RST
ng_log(ANDROID_LOG_ERROR, "write RST error %d: %s",
errno, strerror((errno)));
}
}
else if (bytes == 0) {
// Socket peer closed
ng_log(ANDROID_LOG_DEBUG, "recv empty lport %u state %s",
cur->lport, strstate(cur->state));
if (write_tcp(cur, NULL, 0, 0, 0, 1, 0, args->tun) < 0) // FIN
ng_log(ANDROID_LOG_ERROR, "write FIN lport %u error %d: %s",
cur->lport, errno, strerror((errno)));
else {
cur->local_seq++; // local FIN
if (cur->state == TCP_SYN_RECV || cur->state == TCP_ESTABLISHED)
cur->state = TCP_FIN_WAIT1;
else // close wait
cur->state = TCP_LAST_ACK;
ng_log(ANDROID_LOG_DEBUG, "Half close state %s",
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 (write_tcp(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
}
}
}
}
cur = cur->next;
}
}
void handle_ip(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;
@ -647,14 +638,14 @@ void handle_ip(JNIEnv *env, jobject instance, const struct arguments *args,
int tries = 0; int tries = 0;
while (tries++ < UIDTRIES && uid < 0) { while (tries++ < UIDTRIES && uid < 0) {
// Lookup uid // Lookup uid
uid = getUid(protocol, version, saddr, sport); uid = get_uid(protocol, version, saddr, sport);
if (uid < 0 && version == 4) { if (uid < 0 && version == 4) {
int8_t saddr128[16]; int8_t saddr128[16];
memset(saddr128, 0, 10); memset(saddr128, 0, 10);
saddr128[10] = 0xFF; saddr128[10] = 0xFF;
saddr128[11] = 0xFF; saddr128[11] = 0xFF;
memcpy(saddr128 + 12, saddr, 4); memcpy(saddr128 + 12, saddr, 4);
uid = getUid(protocol, 6, saddr128, sport); uid = get_uid(protocol, 6, saddr128, sport);
} }
if (uid < 0 && tries < UIDTRIES) { if (uid < 0 && tries < UIDTRIES) {
ng_log("get uid try %d", tries); ng_log("get uid try %d", tries);
@ -769,14 +760,14 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
daddr.sin_addr.s_addr = iphdr->daddr; daddr.sin_addr.s_addr = iphdr->daddr;
// Open socket // Open socket
syn->socket = openSocket(env, instance, &daddr); syn->socket = open_socket(env, instance, &daddr);
if (syn->socket < 0) { if (syn->socket < 0) {
syn->state = TCP_TIME_WAIT; syn->state = TCP_TIME_WAIT;
// Remote will retry // Remote will retry
free(syn); free(syn);
} }
else { else {
syn->lport = getLocalPort(syn->socket); syn->lport = get_local_port(syn->socket);
ng_log(ANDROID_LOG_DEBUG, "Connecting to %s/%u lport %u", ng_log(ANDROID_LOG_DEBUG, "Connecting to %s/%u lport %u",
dest, ntohs(tcphdr->dest), syn->lport); dest, ntohs(tcphdr->dest), syn->lport);
@ -796,7 +787,7 @@ 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;
if (writeTCP(&rst, NULL, 0, 0, 0, 0, 1, args->tun) < 0) if (write_tcp(&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",
errno, strerror((errno))); errno, strerror((errno)));
@ -858,7 +849,7 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
} }
if (ok) { if (ok) {
if (writeTCP(cur, NULL, 0, 1 + datalen, 0, 0, 0, args->tun) < 0) // ACK if (write_tcp(cur, NULL, 0, 1 + datalen, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, "write ACK error %d: %s", ng_log(ANDROID_LOG_ERROR, "write ACK error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
else { else {
@ -885,7 +876,7 @@ 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);
if (writeTCP(cur, NULL, 0, confirm, 0, 0, 0, args->tun) < 0) // ACK if (write_tcp(cur, NULL, 0, confirm, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, "write ACK error %d: %s", ng_log(ANDROID_LOG_ERROR, "write ACK error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
} }
@ -922,7 +913,7 @@ 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 {
if (writeTCP(cur, NULL, 0, datalen, 0, 0, 0, args->tun) < 0) // ACK if (write_tcp(cur, NULL, 0, datalen, 0, 0, 0, args->tun) < 0) // ACK
ng_log(ANDROID_LOG_ERROR, "write data error %d: %s", ng_log(ANDROID_LOG_ERROR, "write data error %d: %s",
errno, strerror((errno))); errno, strerror((errno)));
else else
@ -972,7 +963,7 @@ void handle_tcp(JNIEnv *env, jobject instance, const struct arguments *args,
} }
} }
int openSocket(JNIEnv *env, jobject instance, const struct sockaddr_in *daddr) { int open_socket(JNIEnv *env, jobject instance, const struct sockaddr_in *daddr) {
int sock = -1; int sock = -1;
// Get TCP socket // Get TCP socket
@ -1025,7 +1016,7 @@ int openSocket(JNIEnv *env, jobject instance, const struct sockaddr_in *daddr) {
return sock; return sock;
} }
int getLocalPort(const int sock) { int get_local_port(const int sock) {
struct sockaddr_in sin; struct sockaddr_in sin;
int len = sizeof(sin); int len = sizeof(sin);
if (getsockname(sock, &sin, &len) < 0) { if (getsockname(sock, &sin, &len) < 0) {
@ -1035,9 +1026,9 @@ int getLocalPort(const int sock) {
return ntohs(sin.sin_port); return ntohs(sin.sin_port);
} }
int writeTCP(const struct session *cur, int write_tcp(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) {
// Build packet // Build packet
uint16_t len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen; uint16_t len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen;
u_int8_t *buffer = calloc(len, 1); u_int8_t *buffer = calloc(len, 1);
@ -1133,7 +1124,7 @@ int writeTCP(const struct session *cur,
return res; return res;
} }
jint getUid(const int protocol, const int version, const void *saddr, const uint16_t sport) { jint get_uid(const int protocol, const int version, const void *saddr, const uint16_t sport) {
char line[250]; char line[250];
int fields; int fields;
int32_t addr32; int32_t addr32;
@ -1272,3 +1263,18 @@ char *hex(const u_int8_t *data, const u_int16_t len) {
} }
return hexout; return hexout;
} }
void pcap_write(const void *ptr, size_t len) {
FILE *fd = fopen(pcap_fn, "ab");
if (fd == NULL)
ng_log(ANDROID_LOG_ERROR, "fopen %s error %d: %s", pcap_fn, errno, strerror(errno));
else {
if (fwrite(ptr, len, 1, fd) < 1)
ng_log(ANDROID_LOG_ERROR, "fwrite %s error %d: %s", pcap_fn, errno, strerror(errno));
else
ng_log(ANDROID_LOG_DEBUG, "PCAP write %d", len);
if (fclose(fd))
ng_log(ANDROID_LOG_ERROR, "fclose %s error %d: %s", pcap_fn, errno, strerror(errno));
}
}