diff options
Diffstat (limited to 'jni/iodine-client.c')
-rw-r--r-- | jni/iodine-client.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/jni/iodine-client.c b/jni/iodine-client.c new file mode 100644 index 0000000..cb5db97 --- /dev/null +++ b/jni/iodine-client.c @@ -0,0 +1,209 @@ +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include <jni.h> + +#include <sys/system_properties.h> + +#include "iodine/src/common.h" +#include "iodine/src/tun.h" +#include "iodine/src/client.h" +#include "iodine/src/util.h" + +#define IODINE_CLIENT_CLASS "org/xapek/andiodine/IodineClient" +#define IODINE_CLIENT_CLASS_LOG_CALLBACK "log_callback" +#define IODINE_CLIENT_CLASS_LOG_CALLBACK_SIG "(Ljava/lang/String;)V" + +static int dns_fd; + +static JavaVM *javaVM = 0; + +JNIEXPORT jint JNI_OnLoad(JavaVM* jvm, void* reserved) { + javaVM = jvm; + + return JNI_VERSION_1_6; +} + +void android_log_callback(const char *msg_) { + int i; + JNIEnv *env; + char *msg = strdup(msg_); + + if (!msg) { + return; + } + + (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_6); + if (!env) { + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Native Debug: env == null"); + return; + } + + if ((*javaVM)->AttachCurrentThread(javaVM, &env, 0) < 0) { + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Failed to get the environment using AttachCurrentThread()"); + return; + } + + jclass clazz = (*env)->FindClass(env, IODINE_CLIENT_CLASS); + if (!clazz) { + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Native Debug: clazz == null"); + return; + } + + jmethodID log_callback = (*env)->GetStaticMethodID(env, clazz, + IODINE_CLIENT_CLASS_LOG_CALLBACK, IODINE_CLIENT_CLASS_LOG_CALLBACK_SIG); + if (!log_callback) { + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Native Debug: log_callback == null"); + return; + } + + for (i = 0; i< strlen(msg); i++) { + // not printable + if ( ! (msg[i] >= 0x20 && msg[i] <= 0x7e)) { + msg[i] = ' '; + } + } + jstring message = (*env)->NewStringUTF(env, msg); + if (!message) { + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Native Debug: message == null"); + return; + } + (*env)->CallStaticVoidMethod(env, clazz, log_callback, message); + + (*env)->DeleteLocalRef(env,message); + free(msg); +} + +JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_getDnsFd( + JNIEnv *env, jclass klass) { + return dns_fd; +} + +JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_connect( + JNIEnv *env, jclass klass, jstring j_nameserv_addr, jstring j_topdomain, jboolean j_raw_mode, jboolean j_lazy_mode, + jstring j_password) { + + // XXX strdup leaks + const char *__p_nameserv_addr = (*env)->GetStringUTFChars(env, + j_nameserv_addr, NULL); + const char *p_nameserv_addr = strdup(__p_nameserv_addr); + (*env)->ReleaseStringUTFChars(env, j_nameserv_addr, __p_nameserv_addr); + + const char *__p_topdomain = (*env)->GetStringUTFChars(env, j_topdomain, + NULL); + const char *p_topdomain = strdup(__p_topdomain); + (*env)->ReleaseStringUTFChars(env, j_topdomain, __p_topdomain); + + const char *p_password = (*env)->GetStringUTFChars(env, j_password, NULL); + char passwordField[33]; + memset(passwordField, 0, 33); + strncpy(passwordField, p_password, 32); + (*env)->ReleaseStringUTFChars(env, j_password, p_password); + + tun_config_android.request_disconnect = 0; + + int selecttimeout = 2; // original: 4 + int lazy_mode; + int hostname_maxlen = 0xFF; + int raw_mode; + int autodetect_frag_size = 1; + int max_downstream_frag_size = 3072; + + if (j_raw_mode) { + raw_mode = 1; + } else { + raw_mode = 0; + } + + if (j_lazy_mode) { + lazy_mode = 1; + } else { + lazy_mode = 0; + } + + srand((unsigned) time(NULL)); + client_init(); + client_set_nameserver(p_nameserv_addr, DNS_PORT); + client_set_selecttimeout(selecttimeout); + client_set_lazymode(lazy_mode); + client_set_topdomain(p_topdomain); + client_set_hostname_maxlen(hostname_maxlen); + client_set_password(passwordField); + + if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) { + printf("Could not open dns socket: %s", strerror(errno)); + return 1; + } + + if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, + max_downstream_frag_size)) { + printf("Handshake unsuccessful: %s", strerror(errno)); + close(dns_fd); + return 2; + } + + if (client_get_conn() == CONN_RAW_UDP) { + printf("Sending raw traffic directly to %s\n", client_get_raw_addr()); + } + + printf("Handshake successful, leave native code"); + return 0; +} + + +static int tunnel_continue_cb() { + return ! tun_config_android.request_disconnect; +} + +JNIEXPORT void JNICALL Java_org_xapek_andiodine_IodineClient_tunnelInterrupt(JNIEnv *env, + jclass klass) { + tun_config_android.request_disconnect = 1; + client_stop(); +} + +JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_tunnel(JNIEnv *env, + jclass klass, jint tun_fd) { + + printf("Run client_tunnel_cb"); + int retval = client_tunnel_cb(tun_fd, dns_fd, &tunnel_continue_cb); + + close(dns_fd); + close(tun_fd); + return retval; +} + +// String IodineClient.getIp() +JNIEXPORT jstring JNICALL Java_org_xapek_andiodine_IodineClient_getIp( + JNIEnv *env, jclass klass) { + return (*env)->NewStringUTF(env, tun_config_android.ip); +} + +// String IodineClient.getRemoteIp() +JNIEXPORT jstring JNICALL Java_org_xapek_andiodine_IodineClient_getRemoteIp( + JNIEnv *env, jclass klass) { + return (*env)->NewStringUTF(env, tun_config_android.remoteip); +} + +// int IodineClient.getNetbits() +JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_getNetbits( + JNIEnv *env, jclass klass) { + return tun_config_android.netbits; +} + +// int IodineClient.getMtu() +JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_getMtu(JNIEnv *env, + jclass klass) { + return tun_config_android.mtu; +} + +// String IodineClient.getPropertyNetDns1 +JNIEXPORT jstring JNICALL Java_org_xapek_andiodine_IodineClient_getPropertyNetDns1( + JNIEnv *env, jclass klass) { + char value[PROP_VALUE_MAX]; + __system_property_get("net.dns1", value); + return (*env)->NewStringUTF(env, value); +} + |