2016-01-18 21:22:54 +00:00
|
|
|
/*
|
|
|
|
This file is part of NetGuard.
|
|
|
|
|
|
|
|
NetGuard is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
NetGuard is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
|
|
|
*/
|
|
|
|
|
2016-01-09 11:10:11 +00:00
|
|
|
#include <jni.h>
|
2016-01-13 08:23:21 +00:00
|
|
|
#include <android/log.h>
|
|
|
|
|
2016-01-09 20:17:42 +00:00
|
|
|
#include <stdio.h>
|
2016-01-15 09:08:18 +00:00
|
|
|
#include <stdlib.h>
|
2016-01-23 11:48:17 +00:00
|
|
|
#include <ctype.h>
|
2016-01-10 07:14:47 +00:00
|
|
|
#include <time.h>
|
2016-01-09 15:56:23 +00:00
|
|
|
#include <unistd.h>
|
2016-01-13 08:23:21 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
|
2016-01-09 15:56:23 +00:00
|
|
|
#include <arpa/inet.h>
|
2016-01-09 11:10:11 +00:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip6.h>
|
2016-01-09 15:56:23 +00:00
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/tcp.h>
|
2016-01-09 11:10:11 +00:00
|
|
|
|
2016-01-17 16:41:54 +00:00
|
|
|
#include "netguard.h"
|
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
// #define PROFILE 1
|
2016-01-18 18:37:52 +00:00
|
|
|
|
2016-01-20 09:07:09 +00:00
|
|
|
// TODO TCP options
|
2016-01-12 20:15:25 +00:00
|
|
|
// TODO TCP fragmentation
|
2016-01-20 09:07:09 +00:00
|
|
|
// TODO TCPv6
|
2016-01-17 13:20:07 +00:00
|
|
|
// TODO UDPv6
|
2016-01-21 11:36:28 +00:00
|
|
|
// TODO non blocking send/write/close, handle EAGAIN/EWOULDBLOCK
|
2016-01-15 11:57:32 +00:00
|
|
|
|
2016-01-16 08:07:04 +00:00
|
|
|
// It is assumed that no packets will get lost and that packets arrive in order
|
2016-01-19 19:58:51 +00:00
|
|
|
|
2016-01-12 20:15:25 +00:00
|
|
|
// Global variables
|
2016-01-12 12:15:21 +00:00
|
|
|
|
2016-01-13 08:23:21 +00:00
|
|
|
static JavaVM *jvm;
|
|
|
|
pthread_t thread_id;
|
2016-01-24 21:46:25 +00:00
|
|
|
pthread_mutex_t lock;
|
2016-01-23 19:46:27 +00:00
|
|
|
jboolean stopping = 0;
|
|
|
|
jboolean signaled = 0;
|
2016-01-22 12:06:50 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
struct udp_session *udp_session = NULL;
|
2016-01-20 11:35:51 +00:00
|
|
|
struct tcp_session *tcp_session = NULL;
|
2016-01-23 14:50:18 +00:00
|
|
|
|
2016-01-19 16:54:07 +00:00
|
|
|
int loglevel = 0;
|
2016-01-22 12:06:50 +00:00
|
|
|
FILE *pcap_file = NULL;
|
2016-01-11 22:06:35 +00:00
|
|
|
|
2016-01-13 08:23:21 +00:00
|
|
|
// JNI
|
2016-01-11 22:06:35 +00:00
|
|
|
|
2016-01-22 09:37:57 +00:00
|
|
|
jclass clsPacket;
|
|
|
|
|
|
|
|
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|
|
|
log_android(ANDROID_LOG_INFO, "JNI load");
|
|
|
|
|
|
|
|
JNIEnv *env;
|
|
|
|
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
|
|
|
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *packet = "eu/faircode/netguard/Packet";
|
|
|
|
clsPacket = jniGlobalRef(env, jniFindClass(env, packet));
|
|
|
|
|
|
|
|
return JNI_VERSION_1_6;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
|
|
|
log_android(ANDROID_LOG_INFO, "JNI unload");
|
|
|
|
|
|
|
|
JNIEnv *env;
|
|
|
|
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK)
|
|
|
|
log_android(ANDROID_LOG_INFO, "JNI load GetEnv failed");
|
|
|
|
else {
|
|
|
|
(*env)->DeleteGlobalRef(env, clsPacket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 14:02:32 +00:00
|
|
|
JNIEXPORT void JNICALL
|
2016-01-18 18:37:52 +00:00
|
|
|
Java_eu_faircode_netguard_SinkholeService_jni_1init(JNIEnv *env) {
|
2016-01-20 13:11:04 +00:00
|
|
|
udp_session = NULL;
|
2016-01-20 11:35:51 +00:00
|
|
|
tcp_session = NULL;
|
2016-01-22 12:06:50 +00:00
|
|
|
loglevel = ANDROID_LOG_WARN;
|
|
|
|
pcap_file = NULL;
|
2016-01-24 21:46:25 +00:00
|
|
|
|
|
|
|
if (pthread_mutex_init(&lock, NULL))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_init failed");
|
2016-01-17 09:42:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-09 11:10:11 +00:00
|
|
|
JNIEXPORT void JNICALL
|
2016-01-19 19:58:51 +00:00
|
|
|
Java_eu_faircode_netguard_SinkholeService_jni_1start(
|
|
|
|
JNIEnv *env, jobject instance,
|
2016-01-22 15:13:33 +00:00
|
|
|
jint tun, jintArray uids_,
|
2016-01-23 11:48:17 +00:00
|
|
|
jstring hosts_,
|
2016-01-19 19:58:51 +00:00
|
|
|
jboolean log, jboolean filter,
|
|
|
|
jint loglevel_) {
|
|
|
|
|
2016-01-18 12:07:00 +00:00
|
|
|
loglevel = loglevel_;
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Starting tun=%d log %d filter %d level %d",
|
2016-01-19 16:54:07 +00:00
|
|
|
tun, log, filter, loglevel_);
|
2016-01-18 18:37:52 +00:00
|
|
|
|
2016-01-18 20:54:45 +00:00
|
|
|
// Set blocking
|
2016-01-23 19:46:27 +00:00
|
|
|
int flags = fcntl(tun, F_GETFL, 0);
|
2016-01-18 20:54:45 +00:00
|
|
|
if (flags < 0 || fcntl(tun, F_SETFL, flags & ~O_NONBLOCK) < 0)
|
2016-01-19 08:49:47 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "fcntl tun ~O_NONBLOCK error %d: %s",
|
|
|
|
errno, strerror(errno));
|
2016-01-12 16:19:27 +00:00
|
|
|
|
2016-01-14 06:46:23 +00:00
|
|
|
if (pthread_kill(thread_id, 0) == 0)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Already running thread %lu", thread_id);
|
2016-01-14 06:46:23 +00:00
|
|
|
else {
|
|
|
|
jint rs = (*env)->GetJavaVM(env, &jvm);
|
|
|
|
if (rs != JNI_OK)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "GetJavaVM failed");
|
2016-01-14 06:46:23 +00:00
|
|
|
|
2016-01-19 19:58:51 +00:00
|
|
|
// Get arguments
|
2016-01-14 06:46:23 +00:00
|
|
|
struct arguments *args = malloc(sizeof(struct arguments));
|
2016-01-24 11:50:40 +00:00
|
|
|
// args->env = will be set in thread
|
2016-01-14 06:46:23 +00:00
|
|
|
args->instance = (*env)->NewGlobalRef(env, instance);
|
|
|
|
args->tun = tun;
|
2016-01-23 11:48:17 +00:00
|
|
|
|
|
|
|
args->ucount = (*env)->GetArrayLength(env, uids_);
|
|
|
|
args->uids = malloc(args->ucount * sizeof(jint));
|
2016-01-22 15:13:33 +00:00
|
|
|
jint *uids = (*env)->GetIntArrayElements(env, uids_, NULL);
|
2016-01-23 11:48:17 +00:00
|
|
|
memcpy(args->uids, uids, args->ucount * sizeof(jint));
|
2016-01-22 15:13:33 +00:00
|
|
|
(*env)->ReleaseIntArrayElements(env, uids_, uids, 0);
|
2016-01-23 11:48:17 +00:00
|
|
|
|
2016-01-19 16:54:07 +00:00
|
|
|
args->log = log;
|
|
|
|
args->filter = filter;
|
2016-01-19 19:58:51 +00:00
|
|
|
|
2016-01-23 11:48:17 +00:00
|
|
|
if (hosts_ == NULL) {
|
|
|
|
args->hcount = 0;
|
|
|
|
args->hosts = NULL;
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "No hosts file");
|
2016-01-23 11:48:17 +00:00
|
|
|
} else {
|
|
|
|
const char *hosts = (*env)->GetStringUTFChars(env, hosts_, 0);
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "hosts file %s", hosts);
|
2016-01-23 11:48:17 +00:00
|
|
|
read_hosts(hosts, args);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, hosts_, hosts);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < args->ucount; i++)
|
2016-01-22 15:13:33 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "Allowed uid %d", args->uids[i]);
|
2016-01-19 19:58:51 +00:00
|
|
|
|
2016-01-24 06:47:32 +00:00
|
|
|
// Terminate sessions not allowed anymore
|
|
|
|
check_allowed(args);
|
|
|
|
|
2016-01-19 19:58:51 +00:00
|
|
|
// Start native thread
|
|
|
|
int err = pthread_create(&thread_id, NULL, handle_events, (void *) args);
|
2016-01-17 13:20:07 +00:00
|
|
|
if (err == 0)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Started thread %lu", thread_id);
|
2016-01-17 13:20:07 +00:00
|
|
|
else
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_create error %d: %s", err, strerror(err));
|
2016-01-14 06:46:23 +00:00
|
|
|
}
|
2016-01-12 12:15:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-09 11:10:11 +00:00
|
|
|
JNIEXPORT void JNICALL
|
2016-01-17 05:35:26 +00:00
|
|
|
Java_eu_faircode_netguard_SinkholeService_jni_1stop(JNIEnv *env, jobject instance,
|
|
|
|
jint tun, jboolean clear) {
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Stop tun %d clear %d", tun, (int) clear);
|
2016-01-14 06:46:23 +00:00
|
|
|
if (pthread_kill(thread_id, 0) == 0) {
|
2016-01-22 09:43:59 +00:00
|
|
|
stopping = 1;
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "Kill thread %lu", thread_id);
|
2016-01-13 11:15:46 +00:00
|
|
|
int err = pthread_kill(thread_id, SIGUSR1);
|
|
|
|
if (err != 0)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "pthread_kill error %d: %s", err, strerror(err));
|
2016-01-14 06:46:23 +00:00
|
|
|
else {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "Join thread %lu", thread_id);
|
2016-01-14 06:46:23 +00:00
|
|
|
pthread_join(thread_id, NULL);
|
|
|
|
if (err != 0)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "pthread_join error %d: %s", err, strerror(err));
|
2016-01-14 06:46:23 +00:00
|
|
|
}
|
2016-01-24 11:50:40 +00:00
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
if (clear)
|
|
|
|
clear_sessions();
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Stopped thread %lu", thread_id);
|
2016-01-13 11:15:46 +00:00
|
|
|
} else
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Not running");
|
2016-01-09 11:10:11 +00:00
|
|
|
}
|
|
|
|
|
2016-01-17 09:42:21 +00:00
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
Java_eu_faircode_netguard_SinkholeService_jni_1done(JNIEnv *env, jobject instance) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Done");
|
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
clear_sessions();
|
2016-01-24 21:46:25 +00:00
|
|
|
|
|
|
|
if (pthread_mutex_destroy(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_destroy failed");
|
2016-01-17 09:42:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
Java_eu_faircode_netguard_SinkholeService_jni_1pcap(JNIEnv *env, jclass type, jstring name_) {
|
2016-01-24 21:46:25 +00:00
|
|
|
if (pthread_mutex_lock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed");
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
if (name_ == NULL) {
|
2016-01-22 12:06:50 +00:00
|
|
|
if (pcap_file != NULL) {
|
2016-01-24 21:46:25 +00:00
|
|
|
int flags = fcntl(fileno(pcap_file), F_GETFL, 0);
|
|
|
|
if (flags < 0 || fcntl(fileno(pcap_file), F_SETFL, flags & ~O_NONBLOCK) < 0)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fcntl ~O_NONBLOCK error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
|
|
|
|
if (fsync(fileno(pcap_file)))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fsync error %d: %s", errno, strerror(errno));
|
|
|
|
|
2016-01-22 12:06:50 +00:00
|
|
|
if (fclose(pcap_file))
|
2016-01-24 11:50:40 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fclose error %d: %s", errno, strerror(errno));
|
2016-01-24 21:46:25 +00:00
|
|
|
|
|
|
|
pcap_file = NULL;
|
2016-01-22 12:06:50 +00:00
|
|
|
}
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "PCAP disabled");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const char *name = (*env)->GetStringUTFChars(env, name_, 0);
|
|
|
|
log_android(ANDROID_LOG_INFO, "PCAP file %s", name);
|
|
|
|
|
2016-01-22 12:06:50 +00:00
|
|
|
pcap_file = fopen(name, "ab+");
|
|
|
|
if (pcap_file == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fopen error %d: %s", errno, strerror(errno));
|
|
|
|
else {
|
2016-01-23 19:46:27 +00:00
|
|
|
int flags = fcntl(fileno(pcap_file), F_GETFL, 0);
|
2016-01-22 12:06:50 +00:00
|
|
|
if (flags < 0 || fcntl(fileno(pcap_file), F_SETFL, flags | O_NONBLOCK) < 0)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fcntl O_NONBLOCK error %d: %s",
|
|
|
|
errno, strerror(errno));
|
2016-01-24 11:50:40 +00:00
|
|
|
|
2016-01-22 12:06:50 +00:00
|
|
|
write_pcap_hdr();
|
|
|
|
}
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
(*env)->ReleaseStringUTFChars(env, name_, name);
|
|
|
|
}
|
2016-01-24 21:46:25 +00:00
|
|
|
|
|
|
|
if (pthread_mutex_unlock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_unlock failed");
|
2016-01-18 18:37:52 +00:00
|
|
|
}
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-11 22:06:35 +00:00
|
|
|
// Private functions
|
|
|
|
|
2016-01-24 06:47:32 +00:00
|
|
|
void check_allowed(const struct arguments *args) {
|
|
|
|
struct udp_session *u = udp_session;
|
|
|
|
while (u != NULL) {
|
|
|
|
int found = 0;
|
|
|
|
for (int i = 0; i < args->ucount; i++)
|
|
|
|
if (u->uid == args->uids[i]) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!found) {
|
2016-01-24 12:39:04 +00:00
|
|
|
u->stop = 1;
|
2016-01-24 06:47:32 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "UDP terminate uid %d", u->uid);
|
|
|
|
}
|
|
|
|
u = u->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tcp_session *t = tcp_session;
|
|
|
|
while (t != NULL) {
|
|
|
|
int found = 0;
|
|
|
|
for (int i = 0; i < args->ucount; i++)
|
|
|
|
if (t->uid == args->uids[i]) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
t->state = TCP_TIME_WAIT;
|
|
|
|
log_android(ANDROID_LOG_WARN, "TCP terminate uid %d", t->uid);
|
|
|
|
}
|
|
|
|
t = t->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
void clear_sessions() {
|
2016-01-20 13:11:04 +00:00
|
|
|
struct udp_session *u = udp_session;
|
|
|
|
while (u != NULL) {
|
|
|
|
close(u->socket);
|
|
|
|
struct udp_session *p = u;
|
|
|
|
u = u->next;
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
udp_session = NULL;
|
|
|
|
|
|
|
|
struct tcp_session *t = tcp_session;
|
|
|
|
while (t != NULL) {
|
|
|
|
close(t->socket);
|
|
|
|
struct tcp_session *p = t;
|
|
|
|
t = t->next;
|
2016-01-20 08:24:34 +00:00
|
|
|
free(p);
|
|
|
|
}
|
2016-01-20 11:35:51 +00:00
|
|
|
tcp_session = NULL;
|
2016-01-20 08:24:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
void handle_signal(int sig, siginfo_t *info, void *context) {
|
|
|
|
log_android(ANDROID_LOG_DEBUG, "Signal %d", sig);
|
2016-01-14 06:46:23 +00:00
|
|
|
signaled = 1;
|
2016-01-13 11:15:46 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
void *handle_events(void *a) {
|
2016-01-13 08:23:21 +00:00
|
|
|
fd_set rfds;
|
|
|
|
fd_set wfds;
|
|
|
|
fd_set efds;
|
2016-01-13 11:15:46 +00:00
|
|
|
struct timespec ts;
|
|
|
|
sigset_t blockset;
|
|
|
|
sigset_t emptyset;
|
|
|
|
struct sigaction sa;
|
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
struct arguments *args = (struct arguments *) a;
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Start events tun=%d thread %lu", args->tun, thread_id);
|
2016-01-18 11:19:40 +00:00
|
|
|
|
|
|
|
// Attach to Java
|
|
|
|
JNIEnv *env;
|
|
|
|
jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
|
|
|
|
if (rs != JNI_OK) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "AttachCurrentThread failed");
|
2016-01-23 19:46:27 +00:00
|
|
|
return NULL;
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
|
|
|
args->env = env;
|
|
|
|
|
2016-01-13 11:15:46 +00:00
|
|
|
// Block SIGUSR1
|
|
|
|
sigemptyset(&blockset);
|
|
|
|
sigaddset(&blockset, SIGUSR1);
|
|
|
|
sigprocmask(SIG_BLOCK, &blockset, NULL);
|
|
|
|
|
|
|
|
/// Handle SIGUSR1
|
2016-01-18 18:37:52 +00:00
|
|
|
sa.sa_sigaction = handle_signal;
|
2016-01-13 11:15:46 +00:00
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sa.sa_flags = SA_RESTART;
|
|
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
|
|
|
2016-01-22 09:43:59 +00:00
|
|
|
stopping = 0;
|
2016-01-14 06:46:23 +00:00
|
|
|
signaled = 0;
|
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
if (pthread_mutex_lock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed");
|
|
|
|
|
2016-01-13 11:15:46 +00:00
|
|
|
// Loop
|
|
|
|
while (1) {
|
2016-01-24 21:46:25 +00:00
|
|
|
if (pthread_mutex_unlock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_unlock failed");
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "Loop thread %lu", thread_id);
|
2016-01-13 08:23:21 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Check sessions
|
|
|
|
check_sessions(args);
|
|
|
|
|
2016-01-13 08:23:21 +00:00
|
|
|
// Select
|
2016-01-18 19:57:49 +00:00
|
|
|
ts.tv_sec = SELECT_TIMEOUT;
|
2016-01-13 11:15:46 +00:00
|
|
|
ts.tv_nsec = 0;
|
|
|
|
sigemptyset(&emptyset);
|
2016-01-20 13:11:04 +00:00
|
|
|
int max = get_selects(args, &rfds, &wfds, &efds);
|
2016-01-20 11:40:26 +00:00
|
|
|
int ready = pselect(max + 1, &rfds, &wfds, &efds,
|
2016-01-20 13:11:04 +00:00
|
|
|
udp_session == NULL && tcp_session == NULL ? NULL : &ts,
|
|
|
|
&emptyset);
|
2016-01-24 21:46:25 +00:00
|
|
|
|
|
|
|
if (pthread_mutex_lock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed");
|
|
|
|
|
2016-01-13 08:23:21 +00:00
|
|
|
if (ready < 0) {
|
2016-01-13 11:15:46 +00:00
|
|
|
if (errno == EINTR) {
|
2016-01-22 09:43:59 +00:00
|
|
|
if (stopping && signaled) { ;
|
2016-01-24 06:47:32 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "pselect signaled tun %d", args->tun);
|
2016-01-24 11:50:40 +00:00
|
|
|
report_exit(args, NULL);
|
2016-01-14 06:46:23 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2016-01-24 06:47:32 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "pselect interrupted %d", args->tun);
|
2016-01-14 06:46:23 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-01-13 11:15:46 +00:00
|
|
|
} else {
|
2016-01-24 11:50:40 +00:00
|
|
|
char error[200];
|
|
|
|
sprintf(error, "pselect tun %d error %d: %s", args->tun, errno, strerror(errno));
|
|
|
|
log_android(ANDROID_LOG_ERROR, error);
|
|
|
|
report_exit(args, error);
|
2016-01-14 06:46:23 +00:00
|
|
|
break;
|
2016-01-13 11:15:46 +00:00
|
|
|
}
|
2016-01-13 08:23:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
// Count sessions
|
2016-01-23 19:46:27 +00:00
|
|
|
int udp = 0;
|
2016-01-20 13:11:04 +00:00
|
|
|
struct udp_session *u = udp_session;
|
|
|
|
while (u != NULL) {
|
2016-01-23 19:46:27 +00:00
|
|
|
udp++;
|
2016-01-20 13:11:04 +00:00
|
|
|
u = u->next;
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
int tcp = 0;
|
2016-01-20 13:11:04 +00:00
|
|
|
struct tcp_session *t = tcp_session;
|
|
|
|
while (t != NULL) {
|
2016-01-23 19:46:27 +00:00
|
|
|
tcp++;
|
2016-01-20 13:11:04 +00:00
|
|
|
t = t->next;
|
2016-01-16 19:58:12 +00:00
|
|
|
}
|
|
|
|
|
2016-01-13 08:23:21 +00:00
|
|
|
if (ready == 0)
|
2016-01-23 19:46:27 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "pselect timeout udp %d tcp %d", udp, tcp);
|
2016-01-13 08:23:21 +00:00
|
|
|
else {
|
2016-01-23 19:46:27 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "pselect udp %d tcp %d ready %d", udp, tcp, ready);
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
struct timeval start, end;
|
|
|
|
float mselapsed;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
2016-01-16 19:58:12 +00:00
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
// Check upstream
|
2016-01-20 13:11:04 +00:00
|
|
|
if (check_tun(args, &rfds, &wfds, &efds) < 0)
|
2016-01-19 19:58:51 +00:00
|
|
|
break;
|
2016-01-12 08:45:58 +00:00
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "tun %f", mselapsed);
|
|
|
|
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Check UDP downstream
|
|
|
|
check_udp_sockets(args, &rfds, &wfds, &efds);
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Check TCP downstream
|
|
|
|
check_tcp_sockets(args, &rfds, &wfds, &efds);
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "sockets %f", mselapsed);
|
|
|
|
#endif
|
2016-01-20 08:24:34 +00:00
|
|
|
}
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
2016-01-17 09:42:21 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
if (pthread_mutex_unlock(&lock))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "pthread_mutex_unlock failed");
|
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
(*env)->DeleteGlobalRef(env, args->instance);
|
2016-01-21 11:55:08 +00:00
|
|
|
|
|
|
|
// Detach from Java
|
2016-01-18 11:19:40 +00:00
|
|
|
rs = (*jvm)->DetachCurrentThread(jvm);
|
|
|
|
if (rs != JNI_OK)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "DetachCurrentThread failed");
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-21 11:55:08 +00:00
|
|
|
// Cleanup
|
2016-01-22 15:13:33 +00:00
|
|
|
free(args->uids);
|
2016-01-23 11:48:17 +00:00
|
|
|
for (int i = 0; i < args->hcount; i++)
|
|
|
|
free(args->hosts[i]);
|
|
|
|
free(args->hosts);
|
2016-01-21 11:55:08 +00:00
|
|
|
free(args);
|
|
|
|
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Stopped events tun=%d thread %lu", args->tun, thread_id);
|
2016-01-23 19:46:27 +00:00
|
|
|
return NULL;
|
2016-01-21 11:55:08 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
void report_exit(const struct arguments *args, const char *reason) {
|
2016-01-22 15:41:27 +00:00
|
|
|
jclass cls = (*args->env)->GetObjectClass(args->env, args->instance);
|
2016-01-24 11:50:40 +00:00
|
|
|
jmethodID mid = jniGetMethodID(args->env, cls, "nativeExit", "(Ljava/lang/String;)V");
|
|
|
|
|
|
|
|
jstring jreason = (reason == NULL ? NULL : (*args->env)->NewStringUTF(args->env, reason));
|
2016-01-22 15:41:27 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
(*args->env)->CallVoidMethod(args->env, args->instance, mid, jreason);
|
2016-01-22 15:41:27 +00:00
|
|
|
jniCheckException(args->env);
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
if (jreason != NULL)
|
|
|
|
(*args->env)->DeleteLocalRef(args->env, jreason);
|
2016-01-22 15:41:27 +00:00
|
|
|
(*args->env)->DeleteLocalRef(args->env, cls);
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
2016-01-17 09:42:21 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
void check_sessions(const struct arguments *args) {
|
2016-01-18 11:19:40 +00:00
|
|
|
time_t now = time(NULL);
|
2016-01-17 09:42:21 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Check UDP sessions
|
2016-01-20 13:11:04 +00:00
|
|
|
struct udp_session *ul = NULL;
|
|
|
|
struct udp_session *u = udp_session;
|
|
|
|
while (u != NULL) {
|
2016-01-24 12:39:04 +00:00
|
|
|
int timeout;
|
|
|
|
if (ntohs(u->dest) == 53)
|
|
|
|
timeout = UDP_TIMEOUT_53;
|
|
|
|
else
|
|
|
|
timeout = UDP_TIMEOUT_ANY;
|
|
|
|
if (u->stop || u->time + timeout < now) {
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
inet_ntop(AF_INET, &u->saddr.ip4, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &u->daddr.ip4, dest, sizeof(dest));
|
2016-01-24 12:39:04 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "UDP idle %d/%d sec stop %d from %s/%u to %s/%u",
|
|
|
|
now - u->time, timeout, u->stop,
|
|
|
|
dest, ntohs(u->dest), source, ntohs(u->source));
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
if (close(u->socket))
|
2016-01-24 06:47:32 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP close %d error %d: %s",
|
|
|
|
u->socket, errno, strerror(errno));
|
2016-01-20 13:11:04 +00:00
|
|
|
|
|
|
|
if (ul == NULL)
|
|
|
|
udp_session = u->next;
|
|
|
|
else
|
|
|
|
ul->next = u->next;
|
|
|
|
|
|
|
|
struct udp_session *c = u;
|
|
|
|
u = u->next;
|
|
|
|
free(c);
|
|
|
|
}
|
2016-01-21 11:04:41 +00:00
|
|
|
else {
|
|
|
|
ul = u;
|
|
|
|
u = u->next;
|
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
}
|
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Check TCP sessions
|
2016-01-20 13:11:04 +00:00
|
|
|
struct tcp_session *tl = NULL;
|
|
|
|
struct tcp_session *t = tcp_session;
|
|
|
|
while (t != NULL) {
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
inet_ntop(AF_INET, &t->saddr.ip4, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &t->daddr.ip4, dest, sizeof(dest));
|
2016-01-21 11:04:41 +00:00
|
|
|
|
|
|
|
// Check connection timeout
|
2016-01-18 19:57:49 +00:00
|
|
|
int timeout = 0;
|
2016-01-20 13:11:04 +00:00
|
|
|
if (t->state == TCP_LISTEN || t->state == TCP_SYN_RECV)
|
2016-01-18 19:57:49 +00:00
|
|
|
timeout = TCP_INIT_TIMEOUT;
|
2016-01-20 13:11:04 +00:00
|
|
|
else if (t->state == TCP_ESTABLISHED)
|
2016-01-18 19:57:49 +00:00
|
|
|
timeout = TCP_IDLE_TIMEOUT;
|
|
|
|
else
|
|
|
|
timeout = TCP_CLOSE_TIMEOUT;
|
2016-01-21 11:04:41 +00:00
|
|
|
if (t->state != TCP_TIME_WAIT && t->state != TCP_CLOSE && t->time + timeout < now) {
|
2016-01-18 11:19:40 +00:00
|
|
|
// TODO send keep alives?
|
2016-01-24 12:39:04 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Idle %d/%d sec from %s/%u to %s/%u state %s",
|
2016-01-24 13:10:02 +00:00
|
|
|
now - t->time, timeout,
|
2016-01-24 12:39:04 +00:00
|
|
|
source, ntohs(t->source), dest, ntohs(t->dest), strstate(t->state));
|
2016-01-12 08:45:58 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, t);
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Check finished connection
|
2016-01-20 13:11:04 +00:00
|
|
|
if (t->state == TCP_TIME_WAIT) {
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Close from %s/%u to %s/%u socket %d",
|
|
|
|
source, ntohs(t->source), dest, ntohs(t->dest), t->socket);
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
if (close(t->socket))
|
2016-01-24 06:47:32 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "close %d error %d: %s",
|
|
|
|
t->socket, errno, strerror(errno));
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
t->time = time(NULL);
|
|
|
|
t->state = TCP_CLOSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup lingering sessions
|
|
|
|
if (t->state == TCP_CLOSE && t->time + TCP_KEEP_TIMEOUT < now) {
|
2016-01-20 13:11:04 +00:00
|
|
|
if (tl == NULL)
|
|
|
|
tcp_session = t->next;
|
2016-01-18 11:19:40 +00:00
|
|
|
else
|
2016-01-20 13:11:04 +00:00
|
|
|
tl->next = t->next;
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
struct tcp_session *c = t;
|
|
|
|
t = t->next;
|
2016-01-18 11:19:40 +00:00
|
|
|
free(c);
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
tl = t;
|
|
|
|
t = t->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_selects(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) {
|
|
|
|
// Initialize
|
|
|
|
FD_ZERO(rfds);
|
|
|
|
FD_ZERO(wfds);
|
|
|
|
FD_ZERO(efds);
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Always select tun
|
|
|
|
FD_SET(args->tun, rfds);
|
|
|
|
FD_SET(args->tun, efds);
|
|
|
|
int max = args->tun;
|
|
|
|
|
|
|
|
// Select UDP sockets
|
|
|
|
struct udp_session *u = udp_session;
|
|
|
|
while (u != NULL) {
|
2016-01-24 12:39:04 +00:00
|
|
|
if (!u->stop) {
|
2016-01-21 16:24:23 +00:00
|
|
|
FD_SET(u->socket, efds);
|
|
|
|
FD_SET(u->socket, rfds);
|
|
|
|
if (u->socket > max)
|
|
|
|
max = u->socket;
|
|
|
|
}
|
2016-01-21 11:04:41 +00:00
|
|
|
u = u->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select TCP sockets
|
|
|
|
struct tcp_session *t = tcp_session;
|
|
|
|
while (t != NULL) {
|
|
|
|
// Select sockets
|
|
|
|
if (t->state == TCP_LISTEN) {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Check for connected / errors
|
2016-01-20 13:11:04 +00:00
|
|
|
FD_SET(t->socket, efds);
|
|
|
|
FD_SET(t->socket, wfds);
|
|
|
|
if (t->socket > max)
|
|
|
|
max = t->socket;
|
2016-01-18 14:29:01 +00:00
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
else if (t->state == TCP_ESTABLISHED ||
|
|
|
|
t->state == TCP_SYN_RECV ||
|
|
|
|
t->state == TCP_CLOSE_WAIT) {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Check for data / errors
|
2016-01-20 13:11:04 +00:00
|
|
|
FD_SET(t->socket, efds);
|
2016-01-22 18:03:32 +00:00
|
|
|
if (t->send_window > 0)
|
|
|
|
FD_SET(t->socket, rfds);
|
2016-01-20 13:11:04 +00:00
|
|
|
if (t->socket > max)
|
|
|
|
max = t->socket;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
2016-01-18 11:19:40 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
t = t->next;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
return max;
|
|
|
|
}
|
2016-01-12 16:19:27 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
int check_tun(const struct arguments *args, fd_set *rfds, fd_set *wfds,
|
2016-01-20 08:24:34 +00:00
|
|
|
fd_set *efds) {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Check tun error
|
2016-01-18 11:19:40 +00:00
|
|
|
if (FD_ISSET(args->tun, efds)) {
|
2016-01-24 11:50:40 +00:00
|
|
|
// TODO get error (how?)
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "tun exception");
|
2016-01-24 11:50:40 +00:00
|
|
|
report_exit(args, "tun exception");
|
|
|
|
return -1;
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
2016-01-13 08:23:21 +00:00
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
// Check tun read
|
|
|
|
if (FD_ISSET(args->tun, rfds)) {
|
2016-01-22 18:03:32 +00:00
|
|
|
uint8_t buffer[TUN_MAXMSG];
|
2016-01-18 19:57:49 +00:00
|
|
|
ssize_t length = read(args->tun, buffer, sizeof(buffer));
|
2016-01-18 11:19:40 +00:00
|
|
|
if (length < 0) {
|
2016-01-24 11:50:40 +00:00
|
|
|
char error[200];
|
|
|
|
sprintf(error, "tun read error %d: %s", errno, strerror(errno));
|
|
|
|
log_android(ANDROID_LOG_ERROR, error);
|
|
|
|
if (errno == EINTR)
|
|
|
|
return 0;
|
|
|
|
else {
|
|
|
|
report_exit(args, error);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
|
|
|
else if (length > 0) {
|
|
|
|
// Write pcap record
|
2016-01-22 12:06:50 +00:00
|
|
|
if (pcap_file != NULL)
|
2016-01-23 19:46:27 +00:00
|
|
|
write_pcap_rec(buffer, (size_t) length);
|
2016-01-18 11:19:40 +00:00
|
|
|
|
|
|
|
// Handle IP from tun
|
2016-01-23 19:46:27 +00:00
|
|
|
handle_ip(args, buffer, (size_t) length);
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-01-18 14:29:01 +00:00
|
|
|
// tun eof
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "tun empty read");
|
2016-01-24 11:50:40 +00:00
|
|
|
report_exit(args, "tun empty read");
|
2016-01-18 14:29:01 +00:00
|
|
|
return -1;
|
2016-01-18 11:19:40 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-18 11:19:40 +00:00
|
|
|
return 0;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
void check_udp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) {
|
|
|
|
struct udp_session *cur = udp_session;
|
|
|
|
while (cur != NULL) {
|
|
|
|
// Check socket error
|
|
|
|
if (FD_ISSET(cur->socket, efds)) {
|
|
|
|
cur->time = time(NULL);
|
2016-01-20 11:14:15 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
int serr = 0;
|
|
|
|
socklen_t optlen = sizeof(int);
|
|
|
|
int err = getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen);
|
|
|
|
if (err < 0)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP getsockopt error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
else if (serr)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP SO_ERROR %d: %s", serr, strerror(serr));
|
|
|
|
|
2016-01-24 12:39:04 +00:00
|
|
|
cur->stop = 1;
|
2016-01-20 13:11:04 +00:00
|
|
|
}
|
2016-01-20 11:14:15 +00:00
|
|
|
else {
|
2016-01-20 13:11:04 +00:00
|
|
|
// Check socket read
|
|
|
|
if (FD_ISSET(cur->socket, rfds)) {
|
|
|
|
cur->time = time(NULL);
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-22 18:03:32 +00:00
|
|
|
uint8_t buffer[UDP4_MAXMSG];
|
2016-01-20 13:11:04 +00:00
|
|
|
ssize_t bytes = recv(cur->socket, buffer, sizeof(buffer), 0);
|
|
|
|
if (bytes < 0) {
|
|
|
|
// Socket error
|
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP recv error %d: %s", errno, strerror(errno));
|
|
|
|
|
2016-01-21 12:43:41 +00:00
|
|
|
if (errno != EINTR)
|
2016-01-24 12:39:04 +00:00
|
|
|
cur->stop = 1;
|
2016-01-20 13:11:04 +00:00
|
|
|
}
|
|
|
|
else if (bytes == 0) {
|
|
|
|
// Socket eof
|
2016-01-21 12:43:41 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "UDP recv empty");
|
2016-01-24 12:39:04 +00:00
|
|
|
cur->stop = 1;
|
2016-01-20 13:11:04 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Socket read data
|
2016-01-24 14:39:56 +00:00
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
if (cur->version == 4)
|
|
|
|
inet_ntop(AF_INET, &cur->daddr.ip4, dest, sizeof(dest));
|
|
|
|
else
|
|
|
|
inet_ntop(AF_INET6, &cur->daddr.ip6, dest, sizeof(dest));
|
2016-01-20 13:11:04 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "UDP recv bytes %d for %s/%u @tun",
|
|
|
|
bytes, dest, ntohs(cur->dest));
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_udp(args, cur, buffer, (size_t) bytes) < 0)
|
2016-01-23 14:50:18 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write UDP error %d: %s",
|
|
|
|
errno, strerror((errno)));
|
2016-01-24 12:39:04 +00:00
|
|
|
else {
|
|
|
|
// Prevent too many open files
|
|
|
|
if (ntohs(cur->dest) == 53)
|
|
|
|
cur->stop = 1;
|
|
|
|
}
|
2016-01-20 11:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
|
|
|
|
cur = cur->next;
|
2016-01-20 08:24:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
void check_tcp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) {
|
2016-01-20 11:35:51 +00:00
|
|
|
struct tcp_session *cur = tcp_session;
|
2016-01-17 16:39:11 +00:00
|
|
|
while (cur != NULL) {
|
2016-01-18 18:37:52 +00:00
|
|
|
int oldstate = cur->state;
|
|
|
|
uint32_t oldlocal = cur->local_seq;
|
|
|
|
uint32_t oldremote = cur->remote_seq;
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Check socket error
|
2016-01-17 16:39:11 +00:00
|
|
|
if (FD_ISSET(cur->socket, efds)) {
|
2016-01-20 11:40:26 +00:00
|
|
|
cur->time = time(NULL);
|
|
|
|
|
2016-01-18 14:29:01 +00:00
|
|
|
int serr = 0;
|
2016-01-17 16:39:11 +00:00
|
|
|
socklen_t optlen = sizeof(int);
|
|
|
|
int err = getsockopt(cur->socket, SOL_SOCKET, SO_ERROR, &serr, &optlen);
|
|
|
|
if (err < 0)
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "getsockopt error %d: %s", errno, strerror(errno));
|
2016-01-18 14:29:01 +00:00
|
|
|
else if (serr)
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "SO_ERROR %d: %s", serr, strerror(serr));
|
2016-01-17 19:40:40 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-17 16:39:11 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Assume socket okay
|
|
|
|
if (cur->state == TCP_LISTEN) {
|
|
|
|
// Check socket connect
|
|
|
|
if (FD_ISSET(cur->socket, wfds)) {
|
2016-01-20 11:40:26 +00:00
|
|
|
cur->time = time(NULL);
|
|
|
|
|
2016-01-17 16:39:11 +00:00
|
|
|
// Log
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
inet_ntop(AF_INET, &cur->saddr.ip4, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &cur->daddr.ip4, dest, sizeof(dest));
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Connected from %s/%u to %s/%u",
|
|
|
|
source, ntohs(cur->source), dest, ntohs(cur->dest));
|
2016-01-17 16:39:11 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_syn_ack(args, cur) >= 0) {
|
2016-01-17 16:39:11 +00:00
|
|
|
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
|
2016-01-22 18:03:32 +00:00
|
|
|
if (FD_ISSET(cur->socket, rfds) && cur->send_window > 0) {
|
2016-01-20 11:40:26 +00:00
|
|
|
cur->time = time(NULL);
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t len = (cur->send_window > TCP_SEND_WINDOW
|
|
|
|
? TCP_SEND_WINDOW
|
|
|
|
: cur->send_window);
|
2016-01-22 18:03:32 +00:00
|
|
|
uint8_t *buffer = malloc(len);
|
|
|
|
ssize_t bytes = recv(cur->socket, buffer, len, 0);
|
2016-01-17 16:39:11 +00:00
|
|
|
if (bytes < 0) {
|
|
|
|
// Socket error
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "recv error %d: %s", errno, strerror(errno));
|
2016-01-17 19:40:40 +00:00
|
|
|
|
2016-01-18 14:29:01 +00:00
|
|
|
if (errno != EINTR)
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-17 16:39:11 +00:00
|
|
|
}
|
|
|
|
else if (bytes == 0) {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Socket eof
|
|
|
|
// TCP: application close
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "recv empty state %s", strstate(cur->state));
|
2016-01-17 16:39:11 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_fin_ack(args, cur, 0) >= 0) {
|
2016-01-17 16:39:11 +00:00
|
|
|
cur->local_seq++; // local FIN
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-17 16:39:11 +00:00
|
|
|
if (cur->state == TCP_SYN_RECV || cur->state == TCP_ESTABLISHED)
|
|
|
|
cur->state = TCP_FIN_WAIT1;
|
2016-01-17 19:40:40 +00:00
|
|
|
else if (cur->state == TCP_CLOSE_WAIT)
|
2016-01-17 16:39:11 +00:00
|
|
|
cur->state = TCP_LAST_ACK;
|
2016-01-17 19:40:40 +00:00
|
|
|
else
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "Unknown state %s",
|
|
|
|
strstate(cur->state));
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Half close state %s",
|
2016-01-18 18:37:52 +00:00
|
|
|
strstate(cur->state));
|
2016-01-17 16:39:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Socket read data
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
2016-01-21 09:37:24 +00:00
|
|
|
"recv bytes %d state %s", bytes, strstate(cur->state));
|
2016-01-17 19:40:40 +00:00
|
|
|
|
2016-01-18 14:29:01 +00:00
|
|
|
// Forward to tun
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_data(args, cur, buffer, (size_t) bytes) >= 0)
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->local_seq += bytes;
|
2016-01-17 16:39:11 +00:00
|
|
|
}
|
2016-01-22 18:03:32 +00:00
|
|
|
|
|
|
|
free(buffer);
|
2016-01-17 16:39:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
if (cur->state != oldstate || cur->local_seq != oldlocal ||
|
|
|
|
cur->remote_seq != oldremote) {
|
2016-01-24 14:39:56 +00:00
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
inet_ntop(AF_INET, &cur->daddr.ip4, dest, sizeof(dest));
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_INFO,
|
2016-01-21 09:37:24 +00:00
|
|
|
"Session %s/%u new state %s local %u remote %u",
|
|
|
|
dest, ntohs(cur->dest), strstate(cur->state),
|
2016-01-18 18:37:52 +00:00
|
|
|
cur->local_seq - cur->local_start,
|
|
|
|
cur->remote_seq - cur->remote_start);
|
|
|
|
}
|
|
|
|
|
2016-01-17 16:39:11 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
void handle_ip(const struct arguments *args, const uint8_t *buffer, const size_t length) {
|
2016-01-15 18:51:07 +00:00
|
|
|
uint8_t protocol;
|
|
|
|
void *saddr;
|
|
|
|
void *daddr;
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-15 18:51:07 +00:00
|
|
|
char flags[10];
|
|
|
|
int flen = 0;
|
|
|
|
uint8_t *payload;
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-15 18:51:07 +00:00
|
|
|
// Get protocol, addresses & payload
|
|
|
|
uint8_t version = (*buffer) >> 4;
|
|
|
|
if (version == 4) {
|
2016-01-23 19:46:27 +00:00
|
|
|
struct iphdr *ip4hdr = (struct iphdr *) buffer;
|
2016-01-15 18:51:07 +00:00
|
|
|
|
|
|
|
protocol = ip4hdr->protocol;
|
|
|
|
saddr = &ip4hdr->saddr;
|
|
|
|
daddr = &ip4hdr->daddr;
|
|
|
|
|
2016-01-18 20:18:23 +00:00
|
|
|
if (ip4hdr->frag_off & IP_MF) {
|
|
|
|
log_android(ANDROID_LOG_ERROR, "IP fragment");
|
2016-01-15 18:51:07 +00:00
|
|
|
flags[flen++] = '+';
|
2016-01-18 20:18:23 +00:00
|
|
|
}
|
2016-01-15 18:51:07 +00:00
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
uint8_t ipoptlen = (uint8_t) ((ip4hdr->ihl - 5) * 4);
|
|
|
|
payload = (uint8_t *) (buffer + sizeof(struct iphdr) + ipoptlen);
|
2016-01-15 18:51:07 +00:00
|
|
|
|
|
|
|
if (ntohs(ip4hdr->tot_len) != length) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "Invalid length %u header length %u",
|
|
|
|
length, ntohs(ip4hdr->tot_len));
|
2016-01-15 18:51:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-22 16:00:50 +00:00
|
|
|
if (loglevel < ANDROID_LOG_WARN) {
|
2016-01-23 19:46:27 +00:00
|
|
|
if (!calc_checksum(0, (uint8_t *) ip4hdr, sizeof(struct iphdr))) {
|
2016-01-22 16:00:50 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "Invalid IP checksum");
|
|
|
|
return;
|
|
|
|
}
|
2016-01-15 18:51:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (version == 6) {
|
2016-01-23 19:46:27 +00:00
|
|
|
struct ip6_hdr *ip6hdr = (struct ip6_hdr *) buffer;
|
2016-01-15 18:51:07 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
// TODO skip extension headers
|
2016-01-15 18:51:07 +00:00
|
|
|
protocol = ip6hdr->ip6_nxt;
|
|
|
|
saddr = &ip6hdr->ip6_src;
|
|
|
|
daddr = &ip6hdr->ip6_dst;
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
payload = (uint8_t *) (buffer + 40);
|
2016-01-15 18:51:07 +00:00
|
|
|
|
|
|
|
// TODO check length
|
|
|
|
// TODO checksum
|
|
|
|
}
|
|
|
|
else {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Unknown version %d", version);
|
2016-01-15 18:51:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
inet_ntop(version == 4 ? AF_INET : AF_INET6, saddr, source, sizeof(source));
|
|
|
|
inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest));
|
|
|
|
|
|
|
|
// Get ports & flags
|
2016-01-23 19:46:27 +00:00
|
|
|
jboolean syn = 0;
|
2016-01-19 20:16:54 +00:00
|
|
|
int32_t sport = -1;
|
|
|
|
int32_t dport = -1;
|
2016-01-15 18:51:07 +00:00
|
|
|
if (protocol == IPPROTO_TCP) {
|
2016-01-23 19:46:27 +00:00
|
|
|
struct tcphdr *tcp = (struct tcphdr *) payload;
|
2016-01-15 18:51:07 +00:00
|
|
|
|
|
|
|
sport = ntohs(tcp->source);
|
|
|
|
dport = ntohs(tcp->dest);
|
|
|
|
|
|
|
|
if (tcp->syn) {
|
|
|
|
syn = 1;
|
|
|
|
flags[flen++] = 'S';
|
|
|
|
}
|
|
|
|
if (tcp->ack)
|
|
|
|
flags[flen++] = 'A';
|
|
|
|
if (tcp->psh)
|
|
|
|
flags[flen++] = 'P';
|
|
|
|
if (tcp->fin)
|
|
|
|
flags[flen++] = 'F';
|
2016-01-17 09:42:21 +00:00
|
|
|
if (tcp->rst)
|
2016-01-15 18:51:07 +00:00
|
|
|
flags[flen++] = 'R';
|
|
|
|
|
|
|
|
// TODO checksum
|
|
|
|
} else if (protocol == IPPROTO_UDP) {
|
2016-01-23 19:46:27 +00:00
|
|
|
struct udphdr *udp = (struct udphdr *) payload;
|
2016-01-15 18:51:07 +00:00
|
|
|
|
|
|
|
sport = ntohs(udp->source);
|
|
|
|
dport = ntohs(udp->dest);
|
|
|
|
|
2016-01-22 16:00:50 +00:00
|
|
|
// TODO checksum (IPv6)
|
2016-01-15 18:51:07 +00:00
|
|
|
}
|
|
|
|
flags[flen] = 0;
|
|
|
|
|
|
|
|
// Get uid
|
|
|
|
jint uid = -1;
|
2016-01-19 20:10:48 +00:00
|
|
|
if ((protocol == IPPROTO_TCP && (!args->filter || syn)) || protocol == IPPROTO_UDP) {
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "get uid %s/%u syn %d", dest, dport, syn);
|
2016-01-18 19:05:58 +00:00
|
|
|
int tries = 0;
|
2016-01-20 09:27:18 +00:00
|
|
|
usleep(1000 * UID_DELAY);
|
2016-01-18 19:57:49 +00:00
|
|
|
while (uid < 0 && tries++ < UID_MAXTRY) {
|
2016-01-19 20:10:48 +00:00
|
|
|
// Check IPv6 table first
|
2016-01-23 19:46:27 +00:00
|
|
|
int dump = (tries == UID_MAXTRY);
|
2016-01-19 20:10:48 +00:00
|
|
|
if (version == 4) {
|
|
|
|
int8_t saddr128[16];
|
|
|
|
memset(saddr128, 0, 10);
|
2016-01-23 19:46:27 +00:00
|
|
|
saddr128[10] = (uint8_t) 0xFF;
|
|
|
|
saddr128[11] = (uint8_t) 0xFF;
|
2016-01-19 20:10:48 +00:00
|
|
|
memcpy(saddr128 + 12, saddr, 4);
|
2016-01-23 19:46:27 +00:00
|
|
|
uid = get_uid(protocol, 6, saddr128, (const uint16_t) sport, dump);
|
2016-01-19 20:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (uid < 0)
|
2016-01-23 19:46:27 +00:00
|
|
|
uid = get_uid(protocol, version, saddr, (const uint16_t) sport, dump);
|
2016-01-18 19:05:58 +00:00
|
|
|
|
|
|
|
// Retry delay
|
2016-01-18 19:57:49 +00:00
|
|
|
if (uid < 0 && tries < UID_MAXTRY) {
|
2016-01-20 09:27:18 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "get uid %s/%u syn %d try %d",
|
|
|
|
dest, dport, syn, tries);
|
|
|
|
usleep(1000 * UID_DELAYTRY);
|
2016-01-18 19:05:58 +00:00
|
|
|
}
|
2016-01-15 18:51:07 +00:00
|
|
|
}
|
2016-01-18 19:05:58 +00:00
|
|
|
|
|
|
|
if (uid < 0)
|
2016-01-19 08:49:47 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "uid not found");
|
2016-01-15 18:51:07 +00:00
|
|
|
}
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
|
|
|
"Packet v%d %s/%u -> %s/%u proto %d flags %s uid %d",
|
|
|
|
version, source, sport, dest, dport, protocol, flags, uid);
|
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "handle ip %f", mselapsed);
|
|
|
|
#endif
|
2016-01-15 18:51:07 +00:00
|
|
|
|
2016-01-19 19:58:51 +00:00
|
|
|
// Check if allowed
|
2016-01-24 11:50:40 +00:00
|
|
|
jboolean
|
|
|
|
allowed = (jboolean)
|
|
|
|
!syn;
|
2016-01-19 20:25:01 +00:00
|
|
|
if (syn && args->filter && uid >= 0) {
|
2016-01-23 11:48:17 +00:00
|
|
|
for (int i = 0; i < args->ucount; i++)
|
2016-01-22 15:13:33 +00:00
|
|
|
if (args->uids[i] == uid) {
|
2016-01-19 19:58:51 +00:00
|
|
|
allowed = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-19 20:16:54 +00:00
|
|
|
// Handle allowed traffic
|
2016-01-21 16:24:23 +00:00
|
|
|
int log = 0;
|
2016-01-19 19:58:51 +00:00
|
|
|
if (allowed) {
|
2016-01-20 08:24:34 +00:00
|
|
|
if (protocol == IPPROTO_UDP)
|
2016-01-20 13:11:04 +00:00
|
|
|
allowed = handle_udp(args, buffer, length, uid);
|
2016-01-21 16:24:23 +00:00
|
|
|
else if (protocol == IPPROTO_TCP) {
|
2016-01-19 19:58:51 +00:00
|
|
|
allowed = handle_tcp(args, buffer, length, uid);
|
2016-01-22 15:13:33 +00:00
|
|
|
if (!allowed && loglevel < ANDROID_LOG_WARN)
|
2016-01-21 16:24:23 +00:00
|
|
|
log = 1;
|
|
|
|
}
|
2016-01-19 19:58:51 +00:00
|
|
|
else
|
|
|
|
allowed = 0;
|
|
|
|
}
|
2016-01-15 18:51:07 +00:00
|
|
|
|
2016-01-19 20:16:54 +00:00
|
|
|
// Log traffic
|
2016-01-19 16:54:07 +00:00
|
|
|
if (args->log) {
|
2016-01-21 16:24:23 +00:00
|
|
|
if (!args->filter || syn || log || protocol != IPPROTO_TCP)
|
2016-01-22 09:37:57 +00:00
|
|
|
log_packet(args, version, protocol, flags, source, sport, dest, dport, uid, allowed);
|
2016-01-19 16:54:07 +00:00
|
|
|
}
|
2016-01-15 18:51:07 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid) {
|
2016-01-20 08:24:34 +00:00
|
|
|
// Check version
|
|
|
|
uint8_t version = (*buffer) >> 4;
|
|
|
|
|
|
|
|
// Get headers
|
2016-01-24 21:46:25 +00:00
|
|
|
struct iphdr *ip4;
|
|
|
|
struct ip6_hdr *ip6 = NULL;
|
|
|
|
struct udphdr *udphdr;
|
|
|
|
size_t dataoff;
|
|
|
|
if (version == 4) {
|
|
|
|
ip4 = (struct iphdr *) buffer;
|
|
|
|
uint8_t ipoptlen = (uint8_t) ((ip4->ihl - 5) * 4);
|
|
|
|
udphdr = (struct udphdr *) (buffer + sizeof(struct iphdr) + ipoptlen);
|
|
|
|
dataoff = sizeof(struct iphdr) + ipoptlen + sizeof(struct udphdr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ip6 = (struct ip6_hdr *) buffer;
|
|
|
|
// TODO extension headers
|
|
|
|
udphdr = (struct udphdr *) (buffer + sizeof(struct ip6_hdr));
|
|
|
|
dataoff = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
|
|
|
|
}
|
2016-01-20 08:24:34 +00:00
|
|
|
|
|
|
|
// Get data
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t datalen = length - dataoff;
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Search session
|
|
|
|
struct udp_session *last = NULL;
|
|
|
|
struct udp_session *cur = udp_session;
|
2016-01-24 21:46:25 +00:00
|
|
|
while (cur != NULL &&
|
|
|
|
!(cur->source == udphdr->source && cur->dest == udphdr->dest &&
|
|
|
|
(version == 4 ? cur->saddr.ip4 == ip4->saddr &&
|
|
|
|
cur->daddr.ip4 == ip4->daddr
|
|
|
|
: memcmp(&cur->saddr.ip6, &ip6->ip6_src, 16) == 0 &&
|
|
|
|
memcmp(&cur->daddr.ip6, &ip6->ip6_dst, 16) == 0))) {
|
2016-01-20 13:11:04 +00:00
|
|
|
last = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-24 21:46:25 +00:00
|
|
|
if (version == 4) {
|
|
|
|
inet_ntop(AF_INET, &ip4->saddr, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &ip4->daddr, dest, sizeof(dest));
|
|
|
|
} else {
|
|
|
|
inet_ntop(AF_INET6, &ip6->ip6_src, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET6, &ip6->ip6_dst, dest, sizeof(dest));
|
|
|
|
}
|
2016-01-23 14:50:18 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Create new session if needed
|
|
|
|
if (cur == NULL) {
|
2016-01-24 12:39:04 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "UDP new session from %s/%u to %s/%u",
|
2016-01-23 14:50:18 +00:00
|
|
|
source, ntohs(udphdr->source), dest, ntohs(udphdr->dest));
|
2016-01-23 08:39:21 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Register session
|
|
|
|
struct udp_session *u = malloc(sizeof(struct udp_session));
|
|
|
|
u->uid = uid;
|
2016-01-24 21:46:25 +00:00
|
|
|
u->version = version;
|
|
|
|
if (version == 4) {
|
|
|
|
u->saddr.ip4 = (__be32) ip4->saddr;
|
|
|
|
u->daddr.ip4 = (__be32) ip4->daddr;
|
|
|
|
} else {
|
|
|
|
memcpy(&u->saddr.ip6, &ip6->ip6_src, 16);
|
|
|
|
memcpy(&u->daddr.ip6, &ip6->ip6_dst, 16);
|
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
u->source = udphdr->source;
|
|
|
|
u->dest = udphdr->dest;
|
2016-01-24 12:39:04 +00:00
|
|
|
u->stop = 0;
|
2016-01-20 13:11:04 +00:00
|
|
|
u->next = NULL;
|
|
|
|
|
|
|
|
// Open UDP socket
|
2016-01-24 21:46:25 +00:00
|
|
|
u->socket = socket(version == 4 ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
2016-01-20 13:11:04 +00:00
|
|
|
if (u->socket < 0) {
|
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP socket error %d: %s", errno, strerror(errno));
|
2016-01-24 12:39:04 +00:00
|
|
|
u->stop = 1;
|
2016-01-20 13:11:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
2016-01-24 21:46:25 +00:00
|
|
|
// Check for broadcast
|
|
|
|
// TODO IPv6 broadcast
|
|
|
|
if (version == 4) {
|
|
|
|
uint32_t broadcast4 = INADDR_BROADCAST;
|
|
|
|
if (memcmp(&ip4->daddr, &broadcast4, sizeof(broadcast4)) == 0) {
|
|
|
|
log_android(ANDROID_LOG_WARN, "UDP broadcast");
|
|
|
|
int on = 1;
|
|
|
|
if (setsockopt(u->socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP setsockopt error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
}
|
2016-01-22 19:48:58 +00:00
|
|
|
}
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
protect_socket(args, u->socket);
|
|
|
|
|
|
|
|
if (last == NULL)
|
|
|
|
udp_session = u;
|
|
|
|
else
|
|
|
|
last->next = u;
|
|
|
|
|
2016-01-21 16:24:23 +00:00
|
|
|
cur = u;
|
2016-01-20 13:11:04 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
// Check for DNS
|
2016-01-24 21:46:25 +00:00
|
|
|
if (ntohs(udphdr->dest) == 53 && check_dns(args, cur, buffer + dataoff, datalen)) {
|
|
|
|
cur->stop = 1;
|
2016-01-23 14:50:18 +00:00
|
|
|
return 0;
|
2016-01-24 21:46:25 +00:00
|
|
|
}
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-24 06:47:32 +00:00
|
|
|
// TODO check DHCP (tethering)
|
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "UDP forward from tun %s/%u to %s/%u data %d",
|
2016-01-20 11:14:15 +00:00
|
|
|
source, ntohs(udphdr->source), dest, ntohs(udphdr->dest), datalen);
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-21 16:24:23 +00:00
|
|
|
cur->time = time(NULL);
|
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
struct sockaddr_in server4;
|
|
|
|
struct sockaddr_in6 server6;
|
|
|
|
if (version == 4) {
|
|
|
|
server4.sin_family = (__kernel_sa_family_t) AF_INET;
|
|
|
|
server4.sin_addr.s_addr = (__be32) ip4->daddr;
|
|
|
|
server4.sin_port = udphdr->dest;
|
|
|
|
} else {
|
|
|
|
server6.sin6_family = (__kernel_sa_family_t) AF_INET6;
|
|
|
|
memcpy(&server6.sin6_addr, &ip6->ip6_dst, 16);
|
|
|
|
server6.sin6_port = udphdr->dest;
|
|
|
|
}
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
if (sendto(cur->socket, buffer + dataoff, datalen, MSG_NOSIGNAL,
|
2016-01-24 21:46:25 +00:00
|
|
|
(const struct sockaddr *) version == 4 ? &server4 : &server6,
|
|
|
|
version == 4 ? sizeof(server4) : sizeof(server6)) != datalen) {
|
2016-01-24 15:03:46 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "UDP sendto error %d: %s", errno, strerror(errno));
|
2016-01-24 12:39:04 +00:00
|
|
|
cur->stop = 1;
|
2016-01-20 08:24:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
int check_dns(const struct arguments *args, const struct udp_session *u,
|
2016-01-24 21:46:25 +00:00
|
|
|
const uint8_t *data, const size_t datalen) {
|
|
|
|
if (datalen > sizeof(struct dns_header)) {
|
|
|
|
const struct dns_header *dns = (struct dns_header *) data;
|
2016-01-23 14:50:18 +00:00
|
|
|
uint16_t flags = ntohs(dns->flags);
|
|
|
|
|
|
|
|
// Check if standard query
|
2016-01-24 21:46:25 +00:00
|
|
|
// Wireshark: (udp.port eq 53)
|
|
|
|
if ((flags & DNS_QR) == 0 && (flags & DNS_OP) == 0 && ntohs(dns->qdcount) > 0) {
|
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
char name[64];
|
|
|
|
uint8_t noff = 0;
|
|
|
|
|
|
|
|
// http://tools.ietf.org/html/rfc1035
|
|
|
|
uint8_t len;
|
2016-01-24 21:46:25 +00:00
|
|
|
size_t qdoff = sizeof(struct dns_header);
|
2016-01-23 14:50:18 +00:00
|
|
|
do {
|
2016-01-24 21:46:25 +00:00
|
|
|
len = *(data + qdoff);
|
|
|
|
// TODO DNS compression
|
|
|
|
if (len && qdoff + 1 + len <= datalen) {
|
|
|
|
memcpy(name + noff, data + qdoff + 1, len);
|
2016-01-23 14:50:18 +00:00
|
|
|
*(name + noff + len) = '.';
|
|
|
|
noff += (len + 1);
|
2016-01-24 13:54:38 +00:00
|
|
|
qdoff += (1 + len);
|
2016-01-23 14:50:18 +00:00
|
|
|
}
|
2016-01-24 21:46:25 +00:00
|
|
|
} while (len);
|
2016-01-23 14:50:18 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
qdoff++;
|
|
|
|
if (noff > 0 && qdoff + 4 <= datalen) {
|
2016-01-23 14:50:18 +00:00
|
|
|
*(name + noff - 1) = 0;
|
2016-01-24 21:46:25 +00:00
|
|
|
uint16_t qtype = ntohs(*((uint16_t *) (data + qdoff)));
|
|
|
|
uint16_t qclass = ntohs(*((uint16_t *) (data + qdoff + 2)));
|
2016-01-23 14:50:18 +00:00
|
|
|
qdoff += 4;
|
|
|
|
|
2016-01-24 14:39:56 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "DNS type %d class %d name %s", qtype, qclass, name);
|
2016-01-24 13:54:38 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
if (qclass == DNS_QCLASS_IN && (qtype == DNS_QTYPE_A || qtype == DNS_QTYPE_AAAA)) {
|
2016-01-23 14:50:18 +00:00
|
|
|
for (int i = 0; i < args->hcount; i++)
|
|
|
|
if (!strcmp(name, args->hosts[i])) {
|
|
|
|
log_android(ANDROID_LOG_WARN, "DNS %s blocked", name);
|
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
if (qtype == DNS_QTYPE_AAAA) {
|
|
|
|
// TODO DNS v6 reply
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
struct dns_response reply;
|
|
|
|
reply.qname_ptr = htons(sizeof(struct dns_header) | 0xC000);
|
|
|
|
reply.qtype = htons(qtype);
|
|
|
|
reply.qclass = htons(qclass);
|
|
|
|
reply.ttl = htonl(DNS_TTL); // seconds
|
2016-01-24 21:46:25 +00:00
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
reply.rdlength = htons(sizeof(reply.rdata));
|
2016-01-24 21:46:25 +00:00
|
|
|
inet_aton("127.0.0.1", (struct in_addr *) &reply.rdata);
|
2016-01-23 14:50:18 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
size_t qsize = qdoff; // header + query
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t rsize = qsize + sizeof(struct dns_response);
|
2016-01-23 14:50:18 +00:00
|
|
|
uint8_t *response = malloc(rsize);
|
2016-01-24 21:46:25 +00:00
|
|
|
memcpy(response, data, qsize); // header + query
|
2016-01-23 14:50:18 +00:00
|
|
|
memcpy(response + qsize, &reply, sizeof(struct dns_response));
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
struct dns_header *rh = (struct dns_header *) response;
|
2016-01-23 14:50:18 +00:00
|
|
|
rh->flags = htons(DNS_QR);
|
2016-01-24 21:46:25 +00:00
|
|
|
rh->ancount = htons(0);
|
2016-01-23 14:50:18 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_udp(args, u, response, rsize) < 0)
|
2016-01-23 14:50:18 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write UDP error %d: %s",
|
|
|
|
errno, strerror((errno)));
|
2016-01-24 21:46:25 +00:00
|
|
|
else
|
|
|
|
return 1;
|
2016-01-23 14:50:18 +00:00
|
|
|
}
|
2016-01-24 21:46:25 +00:00
|
|
|
}
|
2016-01-23 14:50:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
jboolean handle_tcp(const struct arguments *args, const uint8_t *buffer, size_t length, int uid) {
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-12 08:45:58 +00:00
|
|
|
// Check version
|
2016-01-14 14:02:32 +00:00
|
|
|
uint8_t version = (*buffer) >> 4;
|
2016-01-12 08:45:58 +00:00
|
|
|
if (version != 4)
|
2016-01-19 19:58:51 +00:00
|
|
|
return 0;
|
2016-01-12 08:45:58 +00:00
|
|
|
|
2016-01-11 22:06:35 +00:00
|
|
|
// Get headers
|
2016-01-23 19:46:27 +00:00
|
|
|
struct iphdr *iphdr = (struct iphdr *) buffer;
|
|
|
|
uint8_t ipoptlen = (uint8_t) ((iphdr->ihl - 5) * 4);
|
|
|
|
struct tcphdr *tcphdr = (struct tcphdr *) (buffer + sizeof(struct iphdr) + ipoptlen);
|
|
|
|
uint8_t tcpoptlen = (uint8_t) ((tcphdr->doff - 5) * 4);
|
2016-01-21 11:55:08 +00:00
|
|
|
if (tcpoptlen)
|
2016-01-20 09:27:18 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "optlen %d", tcpoptlen);
|
2016-01-12 18:44:56 +00:00
|
|
|
|
|
|
|
// Get data
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t dataoff = sizeof(struct iphdr) + ipoptlen + sizeof(struct tcphdr) + tcpoptlen;
|
|
|
|
size_t datalen = length - dataoff;
|
2016-01-11 22:06:35 +00:00
|
|
|
|
2016-01-16 08:07:04 +00:00
|
|
|
// Search session
|
2016-01-20 11:35:51 +00:00
|
|
|
struct tcp_session *last = NULL;
|
|
|
|
struct tcp_session *cur = tcp_session;
|
2016-01-24 21:46:25 +00:00
|
|
|
while (cur != NULL && !(cur->saddr.ip4 == iphdr->saddr && cur->source == tcphdr->source &&
|
|
|
|
cur->daddr.ip4 == iphdr->daddr && cur->dest == tcphdr->dest)) {
|
2016-01-11 22:06:35 +00:00
|
|
|
last = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-21 09:37:24 +00:00
|
|
|
inet_ntop(AF_INET, &(iphdr->saddr), source, sizeof(source));
|
2016-01-11 22:06:35 +00:00
|
|
|
inet_ntop(AF_INET, &(iphdr->daddr), dest, sizeof(dest));
|
2016-01-21 09:37:24 +00:00
|
|
|
|
|
|
|
log_android(ANDROID_LOG_DEBUG, "Received from %s/%u for %s/%u seq %u ack %u window %u data %d",
|
|
|
|
source, ntohs(tcphdr->source),
|
2016-01-18 18:37:52 +00:00
|
|
|
dest, ntohs(tcphdr->dest),
|
|
|
|
ntohl(tcphdr->seq) - (cur == NULL ? 0 : cur->remote_start),
|
|
|
|
ntohl(tcphdr->ack_seq) - (cur == NULL ? 0 : cur->local_start),
|
|
|
|
ntohs(tcphdr->window), datalen);
|
2016-01-11 22:06:35 +00:00
|
|
|
|
|
|
|
if (cur == NULL) {
|
|
|
|
if (tcphdr->syn) {
|
2016-01-22 18:03:32 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "New session from %s/%u to %s/%u window %u uid %d",
|
2016-01-21 09:37:24 +00:00
|
|
|
source, ntohs(tcphdr->source),
|
2016-01-22 18:03:32 +00:00
|
|
|
dest, ntohs(tcphdr->dest),
|
|
|
|
ntohs(tcphdr->window), uid);
|
2016-01-11 22:06:35 +00:00
|
|
|
|
2016-01-16 08:07:04 +00:00
|
|
|
// Register session
|
2016-01-20 11:35:51 +00:00
|
|
|
struct tcp_session *syn = malloc(sizeof(struct tcp_session));
|
2016-01-12 08:45:58 +00:00
|
|
|
syn->time = time(NULL);
|
2016-01-15 09:28:31 +00:00
|
|
|
syn->uid = uid;
|
2016-01-20 15:52:38 +00:00
|
|
|
syn->version = 4;
|
2016-01-22 18:03:32 +00:00
|
|
|
syn->send_window = ntohs(tcphdr->window);
|
2016-01-14 14:02:32 +00:00
|
|
|
syn->remote_seq = ntohl(tcphdr->seq); // ISN remote
|
2016-01-23 19:46:27 +00:00
|
|
|
syn->local_seq = (uint32_t) rand(); // ISN local
|
2016-01-17 05:48:33 +00:00
|
|
|
syn->remote_start = syn->remote_seq;
|
|
|
|
syn->local_start = syn->local_seq;
|
2016-01-24 21:46:25 +00:00
|
|
|
syn->saddr.ip4 = (__be32) iphdr->saddr;
|
2016-01-11 22:06:35 +00:00
|
|
|
syn->source = tcphdr->source;
|
2016-01-24 21:46:25 +00:00
|
|
|
syn->daddr.ip4 = (__be32) iphdr->daddr;
|
2016-01-11 22:06:35 +00:00
|
|
|
syn->dest = tcphdr->dest;
|
2016-01-16 11:32:55 +00:00
|
|
|
syn->state = TCP_LISTEN;
|
2016-01-11 22:06:35 +00:00
|
|
|
syn->next = NULL;
|
2016-01-14 09:11:38 +00:00
|
|
|
|
2016-01-15 11:13:12 +00:00
|
|
|
// TODO handle SYN data?
|
2016-01-18 14:29:01 +00:00
|
|
|
if (datalen)
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "SYN session from %s/%u to %s/%u data %u",
|
|
|
|
source, ntohs(tcphdr->source),
|
2016-01-18 18:37:52 +00:00
|
|
|
dest, ntohs(tcphdr->dest), datalen);
|
2016-01-13 09:26:06 +00:00
|
|
|
|
|
|
|
// Open socket
|
2016-01-21 12:21:13 +00:00
|
|
|
syn->socket = open_socket(syn, args);
|
2016-01-15 07:48:18 +00:00
|
|
|
if (syn->socket < 0) {
|
2016-01-15 20:40:37 +00:00
|
|
|
syn->state = TCP_TIME_WAIT;
|
2016-01-18 14:29:01 +00:00
|
|
|
// Remote might retry
|
2016-01-15 07:48:18 +00:00
|
|
|
free(syn);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
2016-01-15 07:48:18 +00:00
|
|
|
}
|
2016-01-11 22:06:35 +00:00
|
|
|
else {
|
2016-01-23 19:46:27 +00:00
|
|
|
int32_t lport = get_local_port(syn->socket);
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Open from %s/%u to %s/%u socket %d lport %u ",
|
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(tcphdr->dest),
|
|
|
|
syn->socket, lport);
|
2016-01-11 22:06:35 +00:00
|
|
|
|
2016-01-15 07:48:18 +00:00
|
|
|
if (last == NULL)
|
2016-01-20 11:35:51 +00:00
|
|
|
tcp_session = syn;
|
2016-01-15 07:48:18 +00:00
|
|
|
else
|
|
|
|
last->next = syn;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-15 09:28:31 +00:00
|
|
|
else {
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Unknown session from %s/%u to %s/%u uid %d",
|
|
|
|
source, ntohs(tcphdr->source),
|
2016-01-18 18:37:52 +00:00
|
|
|
dest, ntohs(tcphdr->dest), uid);
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-20 11:35:51 +00:00
|
|
|
struct tcp_session rst;
|
|
|
|
memset(&rst, 0, sizeof(struct tcp_session));
|
2016-01-20 15:52:38 +00:00
|
|
|
rst.version = 4;
|
2016-01-21 09:37:24 +00:00
|
|
|
rst.local_seq = 0;
|
|
|
|
rst.remote_seq = ntohl(tcphdr->seq);
|
2016-01-24 21:46:25 +00:00
|
|
|
rst.saddr.ip4 = (__be32) iphdr->saddr;
|
2016-01-17 09:42:21 +00:00
|
|
|
rst.source = tcphdr->source;
|
2016-01-24 21:46:25 +00:00
|
|
|
rst.daddr.ip4 = (__be32) iphdr->daddr;
|
2016-01-17 09:42:21 +00:00
|
|
|
rst.dest = tcphdr->dest;
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, &rst);
|
2016-01-19 19:58:51 +00:00
|
|
|
|
|
|
|
return 0;
|
2016-01-15 09:28:31 +00:00
|
|
|
}
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "new session %f", mselapsed);
|
|
|
|
#endif
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-01-18 14:29:01 +00:00
|
|
|
// Session found
|
2016-01-21 11:04:41 +00:00
|
|
|
if (cur->state == TCP_CLOSE) {
|
|
|
|
log_android(ANDROID_LOG_WARN,
|
|
|
|
"Closed session from %s/%u to %s/%u state %s local %u remote %u",
|
|
|
|
source, ntohs(tcphdr->source),
|
|
|
|
dest, ntohs(cur->dest), strstate(cur->state),
|
|
|
|
cur->local_seq - cur->local_start,
|
|
|
|
cur->remote_seq - cur->remote_start);
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
int oldstate = cur->state;
|
|
|
|
uint32_t oldlocal = cur->local_seq;
|
|
|
|
uint32_t oldremote = cur->remote_seq;
|
2016-01-16 11:32:55 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
2016-01-22 18:03:32 +00:00
|
|
|
"Session from %s/%u to %s/%u state %s local %u remote %u window %u",
|
2016-01-21 11:04:41 +00:00
|
|
|
source, ntohs(tcphdr->source),
|
|
|
|
dest, ntohs(cur->dest), strstate(cur->state),
|
|
|
|
cur->local_seq - cur->local_start,
|
2016-01-22 18:03:32 +00:00
|
|
|
cur->remote_seq - cur->remote_start,
|
|
|
|
ntohs(tcphdr->window));
|
2016-01-12 08:45:58 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
cur->time = time(NULL);
|
2016-01-22 18:03:32 +00:00
|
|
|
cur->send_window = ntohs(tcphdr->window);
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Do not change order of conditions
|
2016-01-16 13:50:02 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
// Forward data to socket
|
|
|
|
int ok = 1;
|
|
|
|
if (ntohl(tcphdr->seq) == cur->remote_seq && datalen) {
|
|
|
|
log_android(ANDROID_LOG_DEBUG, "send socket data %u", datalen);
|
2016-01-21 12:21:13 +00:00
|
|
|
|
2016-01-22 18:24:54 +00:00
|
|
|
int more = (tcphdr->psh ? 0 : MSG_MORE);
|
|
|
|
if (send(cur->socket, buffer + dataoff, datalen, MSG_NOSIGNAL | more) < 0) {
|
2016-01-21 12:21:13 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "send error %d: %s", errno, strerror(errno));
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
2016-01-22 15:13:33 +00:00
|
|
|
|
|
|
|
if (tcphdr->fin ||
|
|
|
|
cur->state == TCP_FIN_WAIT1 ||
|
|
|
|
cur->state == TCP_FIN_WAIT2 ||
|
|
|
|
cur->state == TCP_CLOSING)
|
|
|
|
cur->remote_seq += datalen; // FIN will send ACK or no ACK
|
2016-01-20 18:27:13 +00:00
|
|
|
else {
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_ack(args, cur, datalen) >= 0)
|
2016-01-22 15:13:33 +00:00
|
|
|
cur->remote_seq += datalen;
|
|
|
|
else
|
|
|
|
ok = 0;
|
2016-01-20 18:27:13 +00:00
|
|
|
}
|
2016-01-16 13:50:02 +00:00
|
|
|
}
|
2016-01-14 21:48:05 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
if (ok) {
|
|
|
|
if (tcphdr->rst) {
|
|
|
|
// No sequence check
|
|
|
|
log_android(ANDROID_LOG_INFO, "Received RST from %s/%u to %s/%u state %s",
|
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state));
|
|
|
|
cur->state = TCP_TIME_WAIT;
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (ntohl(tcphdr->ack_seq) == cur->local_seq &&
|
|
|
|
ntohl(tcphdr->seq) == cur->remote_seq) {
|
|
|
|
|
|
|
|
if (tcphdr->syn) {
|
|
|
|
log_android(ANDROID_LOG_WARN,
|
|
|
|
"Repeated SYN from %s/%u to %s/%u state %s",
|
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state));
|
|
|
|
// The socket is likely not opened yet
|
|
|
|
// Note: perfect, ordered packet receive assumed
|
|
|
|
|
|
|
|
} else if (tcphdr->fin /* ACK */) {
|
|
|
|
// Shutdown socket for writing
|
|
|
|
if (shutdown(cur->socket, SHUT_WR)) {
|
|
|
|
log_android(ANDROID_LOG_ERROR, "shutdown WR error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
// Data might be lost
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_ack(args, cur, 1) >= 0) {
|
2016-01-21 11:04:41 +00:00
|
|
|
cur->remote_seq += 1; // FIN
|
|
|
|
if (cur->state == TCP_ESTABLISHED /* && !tcphdr->ack */)
|
|
|
|
cur->state = TCP_CLOSE_WAIT;
|
|
|
|
else if (cur->state == TCP_FIN_WAIT1 && tcphdr->ack)
|
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
else if (cur->state == TCP_FIN_WAIT1 && !tcphdr->ack)
|
|
|
|
cur->state = TCP_CLOSING;
|
|
|
|
else if (cur->state == TCP_FIN_WAIT2 /* && !tcphdr->ack */)
|
|
|
|
cur->state = TCP_TIME_WAIT;
|
2016-01-21 16:24:23 +00:00
|
|
|
else {
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR,
|
|
|
|
"Invalid FIN from %s/%u to %s/%u state %s ACK %d",
|
|
|
|
source, ntohs(tcphdr->source),
|
|
|
|
dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state), tcphdr->ack);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
2016-01-21 16:24:23 +00:00
|
|
|
else {
|
2016-01-24 11:50:40 +00:00
|
|
|
write_rst(args, cur);
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-01-21 09:37:24 +00:00
|
|
|
}
|
2016-01-20 09:07:09 +00:00
|
|
|
}
|
2016-01-21 09:37:24 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
else if (tcphdr->ack) {
|
|
|
|
if (cur->state == TCP_SYN_RECV)
|
|
|
|
cur->state = TCP_ESTABLISHED;
|
|
|
|
else if (cur->state == TCP_ESTABLISHED) {
|
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
|
|
|
"New ACK from %s/%u to %s/%u state %s data %u",
|
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state), datalen);
|
|
|
|
}
|
|
|
|
else if (cur->state == TCP_LAST_ACK) {
|
|
|
|
// socket has been shutdown already
|
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
}
|
|
|
|
else if (cur->state == TCP_FIN_WAIT1)
|
|
|
|
cur->state = TCP_FIN_WAIT2;
|
|
|
|
else if (cur->state == TCP_CLOSING)
|
|
|
|
cur->state = TCP_TIME_WAIT;
|
2016-01-21 16:24:23 +00:00
|
|
|
else {
|
2016-01-21 11:04:41 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR,
|
|
|
|
"Invalid ACK from %s/%u to %s/%u state %s",
|
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state));
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-01-21 09:37:24 +00:00
|
|
|
}
|
2016-01-21 11:04:41 +00:00
|
|
|
|
2016-01-21 16:24:23 +00:00
|
|
|
else {
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR,
|
2016-01-21 11:04:41 +00:00
|
|
|
"Unknown packet from %s/%u to %s/%u state %s",
|
2016-01-21 09:37:24 +00:00
|
|
|
source, ntohs(tcphdr->source), dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state));
|
2016-01-21 16:24:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2016-01-20 18:27:13 +00:00
|
|
|
}
|
2016-01-21 09:37:24 +00:00
|
|
|
else {
|
2016-01-21 11:34:31 +00:00
|
|
|
char *msg;
|
2016-01-23 19:46:27 +00:00
|
|
|
static char previous[] = "Previous";
|
|
|
|
static char repeated[] = "Repeated";
|
|
|
|
static char invalid[] = "Invalid";
|
|
|
|
static char keepalive[] = "Keep alive";
|
2016-01-21 11:34:31 +00:00
|
|
|
|
|
|
|
// TODO proper wrap around
|
2016-01-23 19:46:27 +00:00
|
|
|
jboolean allowed = 1;
|
2016-01-21 11:04:41 +00:00
|
|
|
if (tcphdr->ack && ((uint32_t) ntohl(tcphdr->seq) + 1) == cur->remote_seq)
|
2016-01-21 11:34:31 +00:00
|
|
|
msg = keepalive;
|
|
|
|
else if (ntohl(tcphdr->seq) == cur->remote_seq &&
|
|
|
|
ntohl(tcphdr->ack_seq) < cur->local_seq)
|
|
|
|
msg = previous;
|
|
|
|
else if (ntohl(tcphdr->seq) < cur->remote_seq &&
|
|
|
|
ntohl(tcphdr->ack_seq) == cur->local_seq)
|
|
|
|
msg = repeated;
|
2016-01-21 16:24:23 +00:00
|
|
|
else {
|
2016-01-21 11:34:31 +00:00
|
|
|
msg = invalid;
|
2016-01-21 16:24:23 +00:00
|
|
|
allowed = 0;
|
|
|
|
}
|
2016-01-21 11:34:31 +00:00
|
|
|
|
|
|
|
char flags[10];
|
|
|
|
int flen = 0;
|
|
|
|
if (tcphdr->syn)
|
|
|
|
flags[flen++] = 'S';
|
|
|
|
if (tcphdr->ack)
|
|
|
|
flags[flen++] = 'A';
|
|
|
|
if (tcphdr->fin)
|
|
|
|
flags[flen++] = 'F';
|
|
|
|
flags[flen] = 0;
|
|
|
|
|
|
|
|
log_android(tcphdr->fin ? ANDROID_LOG_WARN : ANDROID_LOG_INFO,
|
|
|
|
"%s %s from %s/%u to %s/%u state %s seq %u/%u ack %u/%u data %d",
|
|
|
|
msg, flags,
|
|
|
|
source, ntohs(tcphdr->source),
|
|
|
|
dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state),
|
|
|
|
ntohl(tcphdr->seq) - cur->remote_start,
|
|
|
|
cur->remote_seq - cur->remote_start,
|
|
|
|
ntohl(tcphdr->ack_seq) - cur->local_start,
|
|
|
|
cur->local_seq - cur->local_start,
|
|
|
|
datalen);
|
2016-01-21 16:24:23 +00:00
|
|
|
|
|
|
|
return allowed;
|
2016-01-21 09:37:24 +00:00
|
|
|
}
|
2016-01-20 09:07:09 +00:00
|
|
|
}
|
2016-01-17 13:30:21 +00:00
|
|
|
}
|
2016-01-16 11:32:55 +00:00
|
|
|
|
2016-01-21 11:04:41 +00:00
|
|
|
if (cur->state != oldstate || cur->local_seq != oldlocal ||
|
|
|
|
cur->remote_seq != oldremote)
|
|
|
|
log_android(ANDROID_LOG_INFO,
|
2016-01-22 18:03:32 +00:00
|
|
|
"Session from %s/%u to %s/%u new state %s local %u remote %u window %u",
|
2016-01-21 11:04:41 +00:00
|
|
|
source, ntohs(tcphdr->source),
|
|
|
|
dest, ntohs(cur->dest),
|
|
|
|
strstate(cur->state),
|
|
|
|
cur->local_seq - cur->local_start,
|
2016-01-22 18:03:32 +00:00
|
|
|
cur->remote_seq - cur->remote_start,
|
|
|
|
ntohs(tcphdr->window));
|
2016-01-21 11:04:41 +00:00
|
|
|
}
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "existing session %f", mselapsed);
|
|
|
|
#endif
|
2016-01-13 09:26:06 +00:00
|
|
|
}
|
2016-01-19 19:58:51 +00:00
|
|
|
|
|
|
|
return 1;
|
2016-01-13 09:26:06 +00:00
|
|
|
}
|
|
|
|
|
2016-01-21 12:21:13 +00:00
|
|
|
int open_socket(const struct tcp_session *cur, const struct arguments *args) {
|
2016-01-23 19:46:27 +00:00
|
|
|
int sock;
|
2016-01-13 09:26:06 +00:00
|
|
|
|
2016-01-18 14:29:01 +00:00
|
|
|
// Build target address
|
|
|
|
struct sockaddr_in daddr;
|
|
|
|
memset(&daddr, 0, sizeof(struct sockaddr_in));
|
|
|
|
daddr.sin_family = AF_INET;
|
|
|
|
daddr.sin_port = cur->dest;
|
2016-01-24 21:46:25 +00:00
|
|
|
daddr.sin_addr.s_addr = cur->daddr.ip4;
|
2016-01-18 14:29:01 +00:00
|
|
|
|
2016-01-13 09:26:06 +00:00
|
|
|
// Get TCP socket
|
2016-01-24 11:50:40 +00:00
|
|
|
// TODO socket options?
|
2016-01-13 09:26:06 +00:00
|
|
|
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "socket error %d: %s", errno, strerror(errno));
|
2016-01-13 09:26:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Protect
|
2016-01-20 08:24:34 +00:00
|
|
|
if (protect_socket(args, sock) < 0)
|
2016-01-13 09:26:06 +00:00
|
|
|
return -1;
|
2016-01-12 12:15:21 +00:00
|
|
|
|
2016-01-18 20:54:45 +00:00
|
|
|
// Set non blocking
|
2016-01-23 19:46:27 +00:00
|
|
|
int flags = fcntl(sock, F_GETFL, 0);
|
2016-01-18 20:54:45 +00:00
|
|
|
if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "fcntl socket O_NONBLOCK error %d: %s",
|
|
|
|
errno, strerror(errno));
|
2016-01-13 10:11:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-01-13 09:26:06 +00:00
|
|
|
// Initiate connect
|
2016-01-23 19:46:27 +00:00
|
|
|
int err = connect(sock, (const struct sockaddr *) &daddr, sizeof(struct sockaddr_in));
|
2016-01-13 09:26:06 +00:00
|
|
|
if (err < 0 && errno != EINPROGRESS) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "connect error %d: %s", errno, strerror(errno));
|
2016-01-13 09:26:06 +00:00
|
|
|
return -1;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
2016-01-13 09:26:06 +00:00
|
|
|
|
2016-01-13 18:25:15 +00:00
|
|
|
// Set blocking
|
2016-01-14 14:02:32 +00:00
|
|
|
if (fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) < 0) {
|
2016-01-19 08:49:47 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "fcntl socket ~O_NONBLOCK error %d: %s",
|
|
|
|
errno, strerror(errno));
|
2016-01-13 18:25:15 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-01-13 09:26:06 +00:00
|
|
|
return sock;
|
2016-01-11 22:06:35 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
int32_t get_local_port(const int sock) {
|
2016-01-13 09:26:06 +00:00
|
|
|
struct sockaddr_in sin;
|
2016-01-23 19:46:27 +00:00
|
|
|
socklen_t len = sizeof(sin);
|
|
|
|
if (getsockname(sock, (struct sockaddr *) &sin, &len) < 0) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "getsockname error %d: %s", errno, strerror(errno));
|
2016-01-13 09:26:06 +00:00
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
return ntohs(sin.sin_port);
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
int write_syn_ack(const struct arguments *args, struct tcp_session *cur) {
|
|
|
|
if (write_tcp(args, cur, NULL, 0, 1, 1, 1, 0, 0) < 0) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write SYN+ACK error %d: %s",
|
|
|
|
errno, strerror((errno)));
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
int write_ack(const struct arguments *args, struct tcp_session *cur, size_t bytes) {
|
|
|
|
if (write_tcp(args, cur, NULL, 0, bytes, 0, 1, 0, 0) < 0) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write ACK error %d: %s",
|
|
|
|
errno, strerror((errno)));
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
int write_data(const struct arguments *args, struct tcp_session *cur,
|
2016-01-24 11:50:40 +00:00
|
|
|
const uint8_t *buffer, size_t length) {
|
|
|
|
if (write_tcp(args, cur, buffer, length, 0, 0, 1, 0, 0) < 0) {
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write data ACK error %d: %s", errno, strerror((errno)));
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->state = TCP_TIME_WAIT;
|
2016-01-20 19:07:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
int write_fin_ack(const struct arguments *args, struct tcp_session *cur, size_t bytes) {
|
|
|
|
if (write_tcp(args, cur, NULL, 0, bytes, 0, 1, 1, 0) < 0) {
|
2016-01-23 19:46:27 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write FIN+ACK error %d: %s", errno, strerror((errno)));
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
void write_rst(const struct arguments *args, struct tcp_session *cur) {
|
2016-01-18 19:05:58 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "Sending RST");
|
2016-01-24 11:50:40 +00:00
|
|
|
if (write_tcp(args, cur, NULL, 0, 0, 0, 0, 0, 1) < 0)
|
2016-01-21 09:37:24 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "write RST error %d: %s", errno, strerror((errno)));
|
2016-01-18 14:29:01 +00:00
|
|
|
cur->state = TCP_TIME_WAIT;
|
|
|
|
}
|
2016-01-17 19:40:40 +00:00
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
ssize_t write_udp(const struct arguments *args, const struct udp_session *cur,
|
2016-01-24 11:50:40 +00:00
|
|
|
uint8_t *data, size_t datalen) {
|
2016-01-20 13:11:04 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
size_t len;
|
|
|
|
u_int8_t *buffer;
|
|
|
|
struct udphdr *udp;
|
|
|
|
uint16_t csum;
|
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
|
|
|
char dest[INET6_ADDRSTRLEN + 1];
|
2016-01-20 13:11:04 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
// Build packet
|
|
|
|
if (cur->version == 4) {
|
|
|
|
len = sizeof(struct iphdr) + sizeof(struct udphdr) + datalen;
|
|
|
|
buffer = calloc(len, 1);
|
|
|
|
struct iphdr *ip4 = (struct iphdr *) buffer;
|
|
|
|
udp = (struct udphdr *) (buffer + sizeof(struct iphdr));
|
|
|
|
if (datalen)
|
|
|
|
memcpy(buffer + sizeof(struct iphdr) + sizeof(struct udphdr), data, datalen);
|
|
|
|
|
|
|
|
// Build IP header
|
|
|
|
ip4->version = 4;
|
|
|
|
ip4->ihl = sizeof(struct iphdr) >> 2;
|
|
|
|
ip4->tot_len = htons(len);
|
|
|
|
ip4->ttl = IPDEFTTL;
|
|
|
|
ip4->protocol = IPPROTO_UDP;
|
|
|
|
ip4->saddr = cur->daddr.ip4;
|
|
|
|
ip4->daddr = cur->saddr.ip4;
|
|
|
|
|
|
|
|
// Calculate IP checksum
|
|
|
|
ip4->check = ~calc_checksum(0, (uint8_t *) ip4, sizeof(struct iphdr));
|
|
|
|
|
|
|
|
inet_ntop(AF_INET, &ip4->saddr, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &ip4->daddr, dest, sizeof(dest));
|
|
|
|
|
|
|
|
// Calculate TCP checksum
|
|
|
|
struct ippseudo pseudo;
|
|
|
|
pseudo.ippseudo_src.s_addr = (__be32) ip4->saddr;
|
|
|
|
pseudo.ippseudo_dst.s_addr = (__be32) ip4->daddr;
|
|
|
|
pseudo.ippseudo_pad = 0;
|
|
|
|
pseudo.ippseudo_p = ip4->protocol;
|
|
|
|
pseudo.ippseudo_len = htons(sizeof(struct udphdr) + datalen);
|
|
|
|
|
|
|
|
csum = calc_checksum(0, (uint8_t *) &pseudo, sizeof(struct ippseudo));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
len = sizeof(struct ip6_hdr) + sizeof(struct udphdr) + datalen;
|
|
|
|
buffer = calloc(len, 1);
|
|
|
|
struct ip6_hdr *ip6 = (struct ip6_hdr *) buffer;
|
|
|
|
udp = (struct udphdr *) (buffer + sizeof(struct ip6_hdr));
|
|
|
|
if (datalen)
|
|
|
|
memcpy(buffer + sizeof(struct ip6_hdr) + sizeof(struct udphdr), data, datalen);
|
|
|
|
|
|
|
|
ip6->ip6_ctlun.ip6_un2_vfc = 6;
|
|
|
|
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = 0;
|
|
|
|
ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(len - sizeof(struct ip6_hdr));
|
|
|
|
ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
|
|
|
|
ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = IPDEFTTL;
|
|
|
|
memcpy(&ip6->ip6_src, &cur->saddr.ip6, 16);
|
|
|
|
memcpy(&ip6->ip6_dst, &cur->daddr.ip6, 16);
|
|
|
|
|
|
|
|
inet_ntop(AF_INET, &ip6->ip6_src, source, sizeof(source));
|
|
|
|
inet_ntop(AF_INET, &ip6->ip6_dst, dest, sizeof(dest));
|
|
|
|
|
|
|
|
struct ip6_hdr_pseudo pseudo;
|
|
|
|
memset(&pseudo, 0, sizeof(pseudo));
|
|
|
|
memcpy(&pseudo.ip6ph_src, &ip6->ip6_src, 16);
|
|
|
|
memcpy(&pseudo.ip6ph_dst, &ip6->ip6_dst, 16);
|
|
|
|
pseudo.ip6ph_len = ip6->ip6_ctlun.ip6_un1.ip6_un1_plen;
|
|
|
|
pseudo.ip6ph_nxt = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
|
|
|
|
|
|
|
|
csum = calc_checksum(0, (uint8_t *) &pseudo, sizeof(struct ip6_hdr_pseudo));
|
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
// Build UDP header
|
2016-01-20 13:11:04 +00:00
|
|
|
udp->source = cur->dest;
|
|
|
|
udp->dest = cur->source;
|
|
|
|
udp->check = 0;
|
|
|
|
udp->len = htons(sizeof(struct udphdr) + datalen);
|
|
|
|
|
2016-01-24 21:46:25 +00:00
|
|
|
if (cur->version == 4) {
|
|
|
|
csum = calc_checksum(csum, (uint8_t *) udp, sizeof(struct udphdr));
|
|
|
|
csum = calc_checksum(csum, data, datalen);
|
|
|
|
udp->check = ~csum;
|
|
|
|
} else {
|
|
|
|
// TODO checksum (IPv6)
|
|
|
|
}
|
2016-01-20 13:11:04 +00:00
|
|
|
|
|
|
|
// Send packet
|
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
2016-01-22 09:37:57 +00:00
|
|
|
"Sending UDP to tun from %s/%u to %s/%u data %u",
|
2016-01-24 21:46:25 +00:00
|
|
|
source, ntohs(cur->source), dest, ntohs(cur->dest), datalen);
|
2016-01-20 13:11:04 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
ssize_t res = write(args->tun, buffer, len);
|
2016-01-20 13:11:04 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "tun UDP write %f", mselapsed);
|
|
|
|
#endif
|
|
|
|
|
2016-01-23 14:50:18 +00:00
|
|
|
if (args->log)
|
2016-01-24 21:46:25 +00:00
|
|
|
log_packet(args, cur->version, IPPROTO_UDP, "",
|
2016-01-23 14:50:18 +00:00
|
|
|
source, ntohs(udp->source), dest, ntohs(udp->dest), cur->uid, 1);
|
2016-01-20 15:52:38 +00:00
|
|
|
|
2016-01-20 13:11:04 +00:00
|
|
|
// Write pcap record
|
2016-01-22 12:06:50 +00:00
|
|
|
if (pcap_file != NULL)
|
2016-01-20 13:11:04 +00:00
|
|
|
write_pcap_rec(buffer, len);
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
ssize_t write_tcp(const struct arguments *args, const struct tcp_session *cur,
|
|
|
|
const uint8_t *data, size_t datalen, size_t confirm,
|
2016-01-24 11:50:40 +00:00
|
|
|
int syn, int ack, int fin, int rst) {
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-14 14:02:32 +00:00
|
|
|
// Build packet
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t len = sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen;
|
2016-01-14 14:02:32 +00:00
|
|
|
u_int8_t *buffer = calloc(len, 1);
|
2016-01-23 19:46:27 +00:00
|
|
|
struct iphdr *ip = (struct iphdr *) buffer;
|
|
|
|
struct tcphdr *tcp = (struct tcphdr *) (buffer + sizeof(struct iphdr));
|
2016-01-14 18:30:38 +00:00
|
|
|
if (datalen)
|
2016-01-16 14:12:42 +00:00
|
|
|
memcpy(buffer + sizeof(struct iphdr) + sizeof(struct tcphdr), data, datalen);
|
2016-01-14 14:02:32 +00:00
|
|
|
|
|
|
|
// Build IP header
|
|
|
|
ip->version = 4;
|
|
|
|
ip->ihl = sizeof(struct iphdr) >> 2;
|
|
|
|
ip->tot_len = htons(len);
|
2016-01-24 21:46:25 +00:00
|
|
|
ip->ttl = IPDEFTTL;
|
2016-01-14 14:02:32 +00:00
|
|
|
ip->protocol = IPPROTO_TCP;
|
2016-01-24 21:46:25 +00:00
|
|
|
ip->saddr = cur->daddr.ip4;
|
|
|
|
ip->daddr = cur->saddr.ip4;
|
2016-01-14 14:02:32 +00:00
|
|
|
|
|
|
|
// Calculate IP checksum
|
2016-01-23 19:46:27 +00:00
|
|
|
ip->check = ~calc_checksum(0, (uint8_t *) ip, sizeof(struct iphdr));
|
2016-01-14 14:02:32 +00:00
|
|
|
|
|
|
|
// Build TCP header
|
|
|
|
tcp->source = cur->dest;
|
|
|
|
tcp->dest = cur->source;
|
2016-01-17 05:41:32 +00:00
|
|
|
tcp->seq = htonl(cur->local_seq);
|
2016-01-17 09:42:21 +00:00
|
|
|
tcp->ack_seq = htonl((uint32_t) (cur->remote_seq + confirm));
|
2016-01-14 14:02:32 +00:00
|
|
|
tcp->doff = sizeof(struct tcphdr) >> 2;
|
2016-01-23 19:46:27 +00:00
|
|
|
tcp->syn = (__u16) syn;
|
|
|
|
tcp->ack = (__u16) ack;
|
|
|
|
tcp->fin = (__u16) fin;
|
|
|
|
tcp->rst = (__u16) rst;
|
2016-01-22 18:03:32 +00:00
|
|
|
tcp->window = htons(TCP_RECV_WINDOW);
|
2016-01-14 14:02:32 +00:00
|
|
|
|
2016-01-17 09:42:21 +00:00
|
|
|
if (!tcp->ack)
|
|
|
|
tcp->ack_seq = 0;
|
|
|
|
|
2016-01-14 14:02:32 +00:00
|
|
|
// Calculate TCP checksum
|
2016-01-22 16:00:50 +00:00
|
|
|
struct ippseudo pseudo;
|
2016-01-23 19:46:27 +00:00
|
|
|
pseudo.ippseudo_src.s_addr = (__be32) ip->saddr;
|
|
|
|
pseudo.ippseudo_dst.s_addr = (__be32) ip->daddr;
|
2016-01-22 16:00:50 +00:00
|
|
|
pseudo.ippseudo_pad = 0;
|
|
|
|
pseudo.ippseudo_p = ip->protocol;
|
|
|
|
pseudo.ippseudo_len = htons(sizeof(struct tcphdr) + datalen);
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
uint16_t csum = calc_checksum(0, (uint8_t *) &pseudo, sizeof(struct ippseudo));
|
|
|
|
csum = calc_checksum(csum, (uint8_t *) tcp, sizeof(struct tcphdr));
|
|
|
|
csum = calc_checksum(csum, (uint8_t *) data, datalen);
|
2016-01-14 14:02:32 +00:00
|
|
|
|
2016-01-22 16:00:50 +00:00
|
|
|
tcp->check = ~csum;
|
2016-01-14 14:02:32 +00:00
|
|
|
|
2016-01-24 14:39:56 +00:00
|
|
|
char to[INET6_ADDRSTRLEN + 1];
|
2016-01-14 14:02:32 +00:00
|
|
|
inet_ntop(AF_INET, &(ip->daddr), to, sizeof(to));
|
|
|
|
|
|
|
|
// Send packet
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG,
|
|
|
|
"Sending%s%s%s%s to tun %s/%u seq %u ack %u data %u confirm %u",
|
|
|
|
(tcp->syn ? " SYN" : ""),
|
|
|
|
(tcp->ack ? " ACK" : ""),
|
|
|
|
(tcp->fin ? " FIN" : ""),
|
|
|
|
(tcp->rst ? " RST" : ""),
|
|
|
|
to, ntohs(tcp->dest),
|
|
|
|
ntohl(tcp->seq) - cur->local_start,
|
|
|
|
ntohl(tcp->ack_seq) - cur->remote_start,
|
|
|
|
datalen, confirm);
|
2016-01-18 20:18:23 +00:00
|
|
|
|
2016-01-24 11:50:40 +00:00
|
|
|
ssize_t res = write(args->tun, buffer, len);
|
2016-01-14 14:02:32 +00:00
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
2016-01-20 13:11:04 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "tun TCP write %f", mselapsed);
|
2016-01-18 18:37:52 +00:00
|
|
|
#endif
|
|
|
|
|
2016-01-17 19:40:40 +00:00
|
|
|
// Write pcap record
|
2016-01-22 12:06:50 +00:00
|
|
|
if (pcap_file != NULL)
|
2016-01-18 20:37:51 +00:00
|
|
|
write_pcap_rec(buffer, len);
|
2016-01-17 09:42:21 +00:00
|
|
|
|
2016-01-14 14:02:32 +00:00
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2016-01-19 08:49:47 +00:00
|
|
|
uint8_t char2nible(const char c) {
|
2016-01-23 19:46:27 +00:00
|
|
|
if (c >= '0' && c <= '9') return (uint8_t) (c - '0');
|
|
|
|
if (c >= 'a' && c <= 'f') return (uint8_t) ((c - 'a') + 10);
|
|
|
|
if (c >= 'A' && c <= 'F') return (uint8_t) ((c - 'A') + 10);
|
2016-01-19 08:49:47 +00:00
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hex2bytes(const char *hex, uint8_t *buffer) {
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t len = strlen(hex);
|
2016-01-19 08:49:47 +00:00
|
|
|
for (int i = 0; i < len; i += 2)
|
|
|
|
buffer[i / 2] = (char2nible(hex[i]) << 4) | char2nible(hex[i + 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
jint get_uid(const int protocol, const int version,
|
|
|
|
const void *saddr, const uint16_t sport, int dump) {
|
2016-01-10 07:14:47 +00:00
|
|
|
char line[250];
|
2016-01-19 08:49:47 +00:00
|
|
|
char hex[16 * 2 + 1];
|
2016-01-10 07:14:47 +00:00
|
|
|
int fields;
|
2016-01-19 08:49:47 +00:00
|
|
|
uint8_t addr4[4];
|
|
|
|
uint8_t addr6[16];
|
2016-01-23 19:46:27 +00:00
|
|
|
int port;
|
2016-01-12 19:47:01 +00:00
|
|
|
jint uid = -1;
|
2016-01-10 07:14:47 +00:00
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
2016-01-10 07:14:47 +00:00
|
|
|
// Get proc file name
|
|
|
|
char *fn = NULL;
|
|
|
|
if (protocol == IPPROTO_TCP)
|
|
|
|
fn = (version == 4 ? "/proc/net/tcp" : "/proc/net/tcp6");
|
|
|
|
else if (protocol == IPPROTO_UDP)
|
|
|
|
fn = (version == 4 ? "/proc/net/udp" : "/proc/net/udp6");
|
|
|
|
else
|
2016-01-15 11:13:12 +00:00
|
|
|
return uid;
|
2016-01-10 07:14:47 +00:00
|
|
|
|
2016-01-19 08:49:47 +00:00
|
|
|
if (dump) {
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
2016-01-19 08:49:47 +00:00
|
|
|
inet_ntop(version == 4 ? AF_INET : AF_INET6, saddr, source, sizeof(source));
|
|
|
|
log_android(ANDROID_LOG_INFO, "Searching %s/%u in %s", source, sport, fn);
|
|
|
|
}
|
|
|
|
|
2016-01-10 07:14:47 +00:00
|
|
|
// Open proc file
|
|
|
|
FILE *fd = fopen(fn, "r");
|
|
|
|
if (fd == NULL) {
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "fopen %s error %d: %s", fn, errno, strerror(errno));
|
2016-01-15 11:13:12 +00:00
|
|
|
return uid;
|
2016-01-10 07:14:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Scan proc file
|
2016-01-15 11:13:12 +00:00
|
|
|
jint u;
|
2016-01-10 07:14:47 +00:00
|
|
|
int i = 0;
|
|
|
|
while (fgets(line, sizeof(line), fd) != NULL) {
|
|
|
|
if (i++) {
|
|
|
|
if (version == 4)
|
2016-01-18 18:37:52 +00:00
|
|
|
fields = sscanf(
|
|
|
|
line,
|
2016-01-19 08:49:47 +00:00
|
|
|
"%*d: %8s:%X %*X:%*X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld",
|
|
|
|
hex, &port, &u);
|
2016-01-10 07:14:47 +00:00
|
|
|
else
|
2016-01-18 18:37:52 +00:00
|
|
|
fields = sscanf(
|
|
|
|
line,
|
2016-01-19 08:49:47 +00:00
|
|
|
"%*d: %32s:%X %*X:%*X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld",
|
|
|
|
hex, &port, &u);
|
|
|
|
if (fields == 3) {
|
|
|
|
hex2bytes(hex, version == 4 ? addr4 : addr6);
|
|
|
|
if (version == 4)
|
|
|
|
((uint32_t *) addr4)[0] = htonl(((uint32_t *) addr4)[0]);
|
|
|
|
for (int w = 0; w < 4; w++)
|
|
|
|
((uint32_t *) addr6)[w] = htonl(((uint32_t *) addr6)[w]);
|
|
|
|
|
|
|
|
if (dump) {
|
2016-01-24 14:39:56 +00:00
|
|
|
char source[INET6_ADDRSTRLEN + 1];
|
2016-01-19 08:49:47 +00:00
|
|
|
inet_ntop(version == 4 ? AF_INET : AF_INET6,
|
|
|
|
version == 4 ? addr4 : addr6,
|
|
|
|
source, sizeof(source));
|
|
|
|
log_android(ANDROID_LOG_INFO, "%s/%u %d", source, sport, u);
|
|
|
|
}
|
2016-01-15 11:13:12 +00:00
|
|
|
|
|
|
|
if (port == sport) {
|
2016-01-20 08:24:34 +00:00
|
|
|
if (memcmp(version == 4 ? addr4 : addr6, saddr, version == 4 ? 4 : 16) ==
|
|
|
|
0) {
|
2016-01-19 08:49:47 +00:00
|
|
|
uid = u;
|
|
|
|
break;
|
2016-01-15 11:13:12 +00:00
|
|
|
}
|
2016-01-10 11:51:02 +00:00
|
|
|
}
|
2016-01-15 11:13:12 +00:00
|
|
|
} else
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "Invalid field #%d: %s", fields, line);
|
2016-01-09 20:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
2016-01-10 07:14:47 +00:00
|
|
|
|
2016-01-15 09:28:31 +00:00
|
|
|
if (fclose(fd))
|
2016-01-18 18:37:52 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "fclose %s error %d: %s", fn, errno, strerror(errno));
|
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "get uid ip %f", mselapsed);
|
|
|
|
#endif
|
2016-01-10 07:14:47 +00:00
|
|
|
|
2016-01-15 11:13:12 +00:00
|
|
|
return uid;
|
2016-01-12 12:15:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
int protect_socket(const struct arguments *args, int socket) {
|
2016-01-22 15:41:27 +00:00
|
|
|
jclass cls = (*args->env)->GetObjectClass(args->env, args->instance);
|
|
|
|
jmethodID mid = jniGetMethodID(args->env, cls, "protect", "(I)Z");
|
2016-01-20 08:24:34 +00:00
|
|
|
|
2016-01-22 15:41:27 +00:00
|
|
|
jboolean isProtected = (*args->env)->CallBooleanMethod(args->env, args->instance, mid, socket);
|
|
|
|
jniCheckException(args->env);
|
2016-01-20 08:24:34 +00:00
|
|
|
|
|
|
|
if (!isProtected) {
|
2016-01-22 15:41:27 +00:00
|
|
|
log_android(ANDROID_LOG_ERROR, "protect socket failed");
|
2016-01-20 08:24:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-01-22 15:41:27 +00:00
|
|
|
(*args->env)->DeleteLocalRef(args->env, cls);
|
2016-01-21 11:55:08 +00:00
|
|
|
|
2016-01-20 08:24:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
uint16_t calc_checksum(uint16_t start, const uint8_t *buffer, size_t length) {
|
2016-01-22 16:00:50 +00:00
|
|
|
register uint32_t sum = start;
|
2016-01-23 19:46:27 +00:00
|
|
|
register uint16_t *buf = (uint16_t *) buffer;
|
|
|
|
register size_t len = length;
|
2016-01-12 12:15:21 +00:00
|
|
|
|
2016-01-15 11:57:32 +00:00
|
|
|
while (len > 1) {
|
|
|
|
sum += *buf++;
|
|
|
|
len -= 2;
|
2016-01-12 12:15:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 11:57:32 +00:00
|
|
|
if (len > 0)
|
|
|
|
sum += *((uint8_t *) buf);
|
|
|
|
|
|
|
|
while (sum >> 16)
|
|
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
|
|
|
2016-01-22 16:00:50 +00:00
|
|
|
return (uint16_t) sum;
|
2016-01-12 12:15:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-22 09:37:57 +00:00
|
|
|
// http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
|
|
|
|
// http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/index.html
|
|
|
|
|
|
|
|
jobject jniGlobalRef(JNIEnv *env, jobject cls) {
|
|
|
|
jobject gcls = (*env)->NewGlobalRef(env, cls);
|
|
|
|
if (gcls == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "Global ref failed (out of memory?)");
|
|
|
|
return gcls;
|
|
|
|
}
|
|
|
|
|
|
|
|
jclass jniFindClass(JNIEnv *env, const char *name) {
|
|
|
|
jclass cls = (*env)->FindClass(env, name);
|
|
|
|
if (cls == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "Class %s not found", name);
|
|
|
|
else
|
|
|
|
jniCheckException(env);
|
|
|
|
return cls;
|
|
|
|
}
|
|
|
|
|
2016-01-22 15:41:27 +00:00
|
|
|
jmethodID method_protect = NULL;
|
|
|
|
jmethodID method_logPacket = NULL;
|
|
|
|
|
2016-01-22 09:37:57 +00:00
|
|
|
jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature) {
|
2016-01-22 15:41:27 +00:00
|
|
|
if (strcmp(name, "protect") == 0 && method_protect != NULL)
|
|
|
|
return method_protect;
|
|
|
|
if (strcmp(name, "logPacket") == 0 && method_logPacket != NULL)
|
|
|
|
return method_logPacket;
|
|
|
|
|
2016-01-22 09:37:57 +00:00
|
|
|
jmethodID method = (*env)->GetMethodID(env, cls, name, signature);
|
|
|
|
if (method == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "Method %s%s", name, signature);
|
2016-01-22 15:41:27 +00:00
|
|
|
else {
|
|
|
|
if (strcmp(name, "protect") == 0) {
|
|
|
|
method_protect = method;
|
|
|
|
log_android(ANDROID_LOG_INFO, "Cached method ID protect");
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "logPacket") == 0) {
|
|
|
|
method_logPacket = method;
|
|
|
|
log_android(ANDROID_LOG_INFO, "Cached method ID logPacket");
|
|
|
|
}
|
|
|
|
}
|
2016-01-22 09:37:57 +00:00
|
|
|
return method;
|
|
|
|
}
|
|
|
|
|
|
|
|
jfieldID jniGetFieldID(JNIEnv *env, jclass cls, const char *name, const char *type) {
|
|
|
|
jfieldID field = (*env)->GetFieldID(env, cls, name, type);
|
|
|
|
if (field == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "Field %s type %s not found", name, type);
|
|
|
|
return field;
|
|
|
|
}
|
|
|
|
|
|
|
|
jobject jniNewObject(JNIEnv *env, jclass cls, jmethodID constructor, const char *name) {
|
|
|
|
jobject object = (*env)->NewObject(env, cls, constructor);
|
|
|
|
if (object == NULL)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "Create object %s failed", name);
|
|
|
|
else
|
|
|
|
jniCheckException(env);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
int jniCheckException(JNIEnv *env) {
|
|
|
|
jthrowable ex = (*env)->ExceptionOccurred(env);
|
|
|
|
if (ex) {
|
|
|
|
(*env)->ExceptionDescribe(env);
|
|
|
|
(*env)->ExceptionClear(env);
|
|
|
|
(*env)->DeleteLocalRef(env, ex);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-18 18:37:52 +00:00
|
|
|
void log_android(int prio, const char *fmt, ...) {
|
2016-01-17 15:08:40 +00:00
|
|
|
if (prio >= loglevel) {
|
|
|
|
char line[1024];
|
2016-01-17 13:20:07 +00:00
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, fmt);
|
2016-01-17 15:08:40 +00:00
|
|
|
vsprintf(line, fmt, argptr);
|
|
|
|
__android_log_print(prio, TAG, line);
|
2016-01-17 13:20:07 +00:00
|
|
|
va_end(argptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-20 15:52:38 +00:00
|
|
|
void log_packet(
|
|
|
|
const struct arguments *args,
|
|
|
|
jint version,
|
|
|
|
jint protocol,
|
|
|
|
const char *flags,
|
2016-01-22 09:37:57 +00:00
|
|
|
const char *source,
|
|
|
|
jint sport,
|
|
|
|
const char *dest,
|
|
|
|
jint dport,
|
2016-01-20 15:52:38 +00:00
|
|
|
jint uid,
|
|
|
|
jboolean allowed) {
|
2016-01-18 18:37:52 +00:00
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
JNIEnv *env = args->env;
|
2016-01-22 15:41:27 +00:00
|
|
|
jclass clsService = (*env)->GetObjectClass(env, args->instance);
|
2016-01-22 09:37:57 +00:00
|
|
|
|
|
|
|
const char *signature = "(Leu/faircode/netguard/Packet;)V";
|
|
|
|
jmethodID logPacket = jniGetMethodID(env, clsService, "logPacket", signature);
|
|
|
|
|
|
|
|
const char *packet = "eu/faircode/netguard/Packet";
|
|
|
|
jmethodID initPacket = jniGetMethodID(env, clsPacket, "<init>", "()V");
|
|
|
|
jobject objPacket = jniNewObject(env, clsPacket, initPacket, packet);
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
jlong t = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
|
|
|
|
jstring jflags = (*env)->NewStringUTF(env, flags);
|
|
|
|
jstring jsource = (*env)->NewStringUTF(env, source);
|
|
|
|
jstring jdest = (*env)->NewStringUTF(env, dest);
|
|
|
|
|
|
|
|
const char *string = "Ljava/lang/String;";
|
|
|
|
(*env)->SetLongField(env, objPacket, jniGetFieldID(env, clsPacket, "time", "J"), t);
|
|
|
|
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "version", "I"), version);
|
|
|
|
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "protocol", "I"), protocol);
|
|
|
|
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "flags", string), jflags);
|
|
|
|
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "saddr", string), jsource);
|
|
|
|
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "sport", "I"), sport);
|
|
|
|
(*env)->SetObjectField(env, objPacket, jniGetFieldID(env, clsPacket, "daddr", string), jdest);
|
|
|
|
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "dport", "I"), dport);
|
|
|
|
(*env)->SetIntField(env, objPacket, jniGetFieldID(env, clsPacket, "uid", "I"), uid);
|
|
|
|
(*env)->SetBooleanField(env, objPacket, jniGetFieldID(env, clsPacket, "allowed", "Z"), allowed);
|
|
|
|
|
2016-01-22 15:41:27 +00:00
|
|
|
(*env)->CallVoidMethod(env, args->instance, logPacket, objPacket);
|
2016-01-22 09:37:57 +00:00
|
|
|
jniCheckException(env);
|
|
|
|
|
|
|
|
(*env)->DeleteLocalRef(env, jdest);
|
|
|
|
(*env)->DeleteLocalRef(env, jsource);
|
|
|
|
(*env)->DeleteLocalRef(env, jflags);
|
|
|
|
(*env)->DeleteLocalRef(env, objPacket);
|
|
|
|
(*env)->DeleteLocalRef(env, clsService);
|
2016-01-18 18:37:52 +00:00
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "log java %f", mselapsed);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-01-18 20:37:51 +00:00
|
|
|
void write_pcap_hdr() {
|
|
|
|
struct pcap_hdr_s pcap_hdr;
|
|
|
|
pcap_hdr.magic_number = 0xa1b2c3d4;
|
|
|
|
pcap_hdr.version_major = 2;
|
|
|
|
pcap_hdr.version_minor = 4;
|
|
|
|
pcap_hdr.thiszone = 0;
|
|
|
|
pcap_hdr.sigfigs = 0;
|
2016-01-22 12:06:50 +00:00
|
|
|
pcap_hdr.snaplen = MAX_PCAP_RECORD;
|
2016-01-18 20:37:51 +00:00
|
|
|
pcap_hdr.network = LINKTYPE_RAW;
|
|
|
|
write_pcap(&pcap_hdr, sizeof(struct pcap_hdr_s));
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
void write_pcap_rec(const uint8_t *buffer, size_t length) {
|
2016-01-18 20:37:51 +00:00
|
|
|
struct timespec ts;
|
|
|
|
if (clock_gettime(CLOCK_REALTIME, &ts))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "clock_gettime error %d: %s", errno, strerror(errno));
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
size_t plen = (length < MAX_PCAP_RECORD ? length : MAX_PCAP_RECORD);
|
2016-01-22 16:00:50 +00:00
|
|
|
struct pcaprec_hdr_s pcap_rec;
|
2016-01-18 20:37:51 +00:00
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
pcap_rec.ts_sec = (guint32_t) ts.tv_sec;
|
|
|
|
pcap_rec.ts_usec = (guint32_t) (ts.tv_nsec / 1000);
|
|
|
|
pcap_rec.incl_len = (guint32_t) plen;
|
|
|
|
pcap_rec.orig_len = (guint32_t) length;
|
2016-01-18 20:37:51 +00:00
|
|
|
|
2016-01-22 16:00:50 +00:00
|
|
|
write_pcap(&pcap_rec, sizeof(struct pcaprec_hdr_s));
|
|
|
|
write_pcap(buffer, plen);
|
2016-01-18 20:37:51 +00:00
|
|
|
}
|
|
|
|
|
2016-01-22 12:06:50 +00:00
|
|
|
void write_pcap(const void *ptr, size_t len) {
|
|
|
|
#ifdef PROFILE
|
|
|
|
float mselapsed;
|
|
|
|
struct timeval start, end;
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (fwrite(ptr, len, 1, pcap_file) < 1)
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP fwrite error %d: %s", errno, strerror(errno));
|
|
|
|
else {
|
|
|
|
long fsize = ftell(pcap_file);
|
|
|
|
log_android(ANDROID_LOG_DEBUG, "PCAP wrote %d @%ld", len, fsize);
|
|
|
|
|
|
|
|
if (fsize > MAX_PCAP_FILE) {
|
2016-01-24 21:46:25 +00:00
|
|
|
log_android(ANDROID_LOG_WARN, "PCAP truncate @%ld", fsize);
|
2016-01-22 12:06:50 +00:00
|
|
|
if (ftruncate(fileno(pcap_file), sizeof(struct pcap_hdr_s)))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP ftruncate error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
else {
|
|
|
|
if (!lseek(fileno(pcap_file), sizeof(struct pcap_hdr_s), SEEK_SET))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "PCAP ftruncate error %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PROFILE
|
|
|
|
gettimeofday(&end, NULL);
|
|
|
|
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
|
|
|
|
(end.tv_usec - start.tv_usec) / 1000.0;
|
|
|
|
if (mselapsed > 1)
|
|
|
|
log_android(ANDROID_LOG_INFO, "pcap write %f", mselapsed);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-01-23 11:48:17 +00:00
|
|
|
char *trim(char *str) {
|
|
|
|
while (isspace(*str))
|
|
|
|
str++;
|
|
|
|
if (*str == 0)
|
|
|
|
return str;
|
|
|
|
|
|
|
|
char *end = str + strlen(str) - 1;
|
|
|
|
while (end > str && isspace(*end))
|
|
|
|
end--;
|
|
|
|
*(end + 1) = 0;
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void read_hosts(const char *name, struct arguments *args) {
|
2016-01-23 20:30:54 +00:00
|
|
|
log_android(ANDROID_LOG_INFO, "Reading %s", name);
|
2016-01-23 11:48:17 +00:00
|
|
|
|
|
|
|
args->hcount = 0;
|
|
|
|
args->hosts = NULL;
|
|
|
|
|
|
|
|
FILE *hosts;
|
|
|
|
if ((hosts = fopen(name, "r")) == NULL) {
|
|
|
|
log_android(ANDROID_LOG_ERROR, "fopen(%s) error %d: %s", name, errno, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char buffer[160];
|
|
|
|
while (fgets(buffer, sizeof(buffer), hosts)) {
|
|
|
|
char *hash = strchr(buffer, '#');
|
|
|
|
if (hash)
|
|
|
|
*hash = 0;
|
|
|
|
|
|
|
|
char *host = trim(buffer);
|
|
|
|
while (*host && !isspace(*host))
|
|
|
|
host++;
|
|
|
|
|
|
|
|
if (isspace(*host)) {
|
|
|
|
host++;
|
|
|
|
if (*host && strcmp(host, "localhost")) {
|
|
|
|
args->hosts = realloc(args->hosts, sizeof(char *) * (args->hcount + 1));
|
|
|
|
args->hosts[args->hcount] = malloc(strlen(host) + 1);
|
|
|
|
strcpy(args->hosts[args->hcount], host);
|
|
|
|
args->hcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fclose(hosts))
|
|
|
|
log_android(ANDROID_LOG_ERROR, "fclose(%s) error %d: %s", name, errno, strerror(errno));
|
|
|
|
|
|
|
|
for (int i = 0; i < args->hcount; i++)
|
2016-01-23 14:50:18 +00:00
|
|
|
log_android(ANDROID_LOG_DEBUG, "host '%s'", args->hosts[i]);
|
2016-01-23 11:48:17 +00:00
|
|
|
}
|
|
|
|
|
2016-01-16 11:32:55 +00:00
|
|
|
const char *strstate(const int state) {
|
|
|
|
switch (state) {
|
|
|
|
case TCP_ESTABLISHED:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "ESTABLISHED";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_SYN_SENT:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "SYN_SENT";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_SYN_RECV:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "SYN_RECV";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_FIN_WAIT1:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "FIN_WAIT1";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_FIN_WAIT2:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "FIN_WAIT2";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_TIME_WAIT:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "TIME_WAIT";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_CLOSE:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "CLOSE";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_CLOSE_WAIT:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "CLOSE_WAIT";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_LAST_ACK:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "LAST_ACK";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_LISTEN:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "LISTEN";
|
2016-01-16 11:32:55 +00:00
|
|
|
case TCP_CLOSING:
|
2016-01-18 19:57:49 +00:00
|
|
|
return "CLOSING";
|
2016-01-16 11:32:55 +00:00
|
|
|
default:
|
2016-01-23 19:46:27 +00:00
|
|
|
return "UNKNOWN";
|
2016-01-16 11:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-23 19:46:27 +00:00
|
|
|
char *hex(const u_int8_t *data, const size_t len) {
|
2016-01-12 20:15:25 +00:00
|
|
|
char hex_str[] = "0123456789ABCDEF";
|
2016-01-12 12:15:21 +00:00
|
|
|
|
2016-01-15 11:13:12 +00:00
|
|
|
char *hexout;
|
|
|
|
hexout = (char *) malloc(len * 3 + 1); // TODO free
|
2016-01-12 12:15:21 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
2016-01-13 19:17:21 +00:00
|
|
|
hexout[i * 3 + 0] = hex_str[(data[i] >> 4) & 0x0F];
|
|
|
|
hexout[i * 3 + 1] = hex_str[(data[i]) & 0x0F];
|
|
|
|
hexout[i * 3 + 2] = ' ';
|
2016-01-12 12:15:21 +00:00
|
|
|
}
|
2016-01-23 14:50:18 +00:00
|
|
|
hexout[len * 3] = 0;
|
|
|
|
|
2016-01-13 19:17:21 +00:00
|
|
|
return hexout;
|
2016-01-12 16:19:27 +00:00
|
|
|
}
|