summaryrefslogtreecommitdiff
path: root/jni/iodine-client.c
blob: 905b15465ab96a7c63e16df3058de14052f0aa10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <netdb.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);
	char *p_nameserv_addr = strdup(__p_nameserv_addr);
	struct sockaddr_storage p_nameserv;
	int p_nameserv_len = get_addr(p_nameserv_addr, 53, AF_INET, 0, &p_nameserv);
	(*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);
	__android_log_print(ANDROID_LOG_ERROR, "iodine", "Topdomain from vm: %s", p_topdomain);

	(*env)->ReleaseStringUTFChars(env, j_topdomain, __p_topdomain);
	__android_log_print(ANDROID_LOG_ERROR, "iodine", "Topdomain from vm: %s", 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, p_nameserv_len);
	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_from_host(NULL, 0, AF_INET, AI_PASSIVE)) == -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);
}