android: Add a custom kernel-net implementation to replace kernel-netlink
[strongswan.git] / src / frontends / android / jni / libandroidbridge / vpnservice_builder.c
1 /*
2 * Copyright (C) 2012-2014 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "vpnservice_builder.h"
19 #include "android_jni.h"
20
21 #include <utils/debug.h>
22 #include <library.h>
23
24 typedef struct private_vpnservice_builder_t private_vpnservice_builder_t;
25
26 /**
27 * private data of vpnservice_builder
28 */
29 struct private_vpnservice_builder_t {
30
31 /**
32 * public interface
33 */
34 vpnservice_builder_t public;
35
36 /**
37 * Java object
38 */
39 jobject builder;
40 };
41
42 METHOD(vpnservice_builder_t, add_address, bool,
43 private_vpnservice_builder_t *this, host_t *addr)
44 {
45 JNIEnv *env;
46 jmethodID method_id;
47 jstring str;
48 char buf[INET6_ADDRSTRLEN];
49 int prefix;
50
51 androidjni_attach_thread(&env);
52
53 DBG2(DBG_LIB, "builder: adding interface address %H", addr);
54
55 prefix = addr->get_family(addr) == AF_INET ? 32 : 128;
56 if (snprintf(buf, sizeof(buf), "%H", addr) >= sizeof(buf))
57 {
58 goto failed;
59 }
60
61 method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
62 "addAddress", "(Ljava/lang/String;I)Z");
63 if (!method_id)
64 {
65 goto failed;
66 }
67 str = (*env)->NewStringUTF(env, buf);
68 if (!str)
69 {
70 goto failed;
71 }
72 if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, prefix))
73 {
74 goto failed;
75 }
76 androidjni_detach_thread();
77 return TRUE;
78
79 failed:
80 DBG1(DBG_LIB, "builder: failed to add address");
81 androidjni_exception_occurred(env);
82 androidjni_detach_thread();
83 return FALSE;
84 }
85
86 METHOD(vpnservice_builder_t, set_mtu, bool,
87 private_vpnservice_builder_t *this, int mtu)
88 {
89 JNIEnv *env;
90 jmethodID method_id;
91
92 androidjni_attach_thread(&env);
93
94 DBG2(DBG_LIB, "builder: setting MTU to %d", mtu);
95
96 method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
97 "setMtu", "(I)Z");
98 if (!method_id)
99 {
100 goto failed;
101 }
102 if (!(*env)->CallBooleanMethod(env, this->builder, method_id, mtu))
103 {
104 goto failed;
105 }
106 androidjni_detach_thread();
107 return TRUE;
108
109 failed:
110 DBG1(DBG_LIB, "builder: failed to set MTU");
111 androidjni_exception_occurred(env);
112 androidjni_detach_thread();
113 return FALSE;
114 }
115
116 METHOD(vpnservice_builder_t, add_route, bool,
117 private_vpnservice_builder_t *this, host_t *net, int prefix)
118 {
119 JNIEnv *env;
120 jmethodID method_id;
121 jstring str;
122 char buf[INET6_ADDRSTRLEN];
123
124 androidjni_attach_thread(&env);
125
126 DBG2(DBG_LIB, "builder: adding route %+H/%d", net, prefix);
127
128 if (snprintf(buf, sizeof(buf), "%+H", net) >= sizeof(buf))
129 {
130 goto failed;
131 }
132
133 method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
134 "addRoute", "(Ljava/lang/String;I)Z");
135 if (!method_id)
136 {
137 goto failed;
138 }
139 str = (*env)->NewStringUTF(env, buf);
140 if (!str)
141 {
142 goto failed;
143 }
144 if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str, prefix))
145 {
146 goto failed;
147 }
148 androidjni_detach_thread();
149 return TRUE;
150
151 failed:
152 DBG1(DBG_LIB, "builder: failed to add route");
153 androidjni_exception_occurred(env);
154 androidjni_detach_thread();
155 return FALSE;
156 }
157
158 METHOD(vpnservice_builder_t, add_dns, bool,
159 private_vpnservice_builder_t *this, host_t *dns)
160 {
161 JNIEnv *env;
162 jmethodID method_id;
163 jstring str;
164 char buf[INET6_ADDRSTRLEN];
165
166 androidjni_attach_thread(&env);
167
168 DBG2(DBG_LIB, "builder: adding DNS server %H", dns);
169
170 if (snprintf(buf, sizeof(buf), "%H", dns) >= sizeof(buf))
171 {
172 goto failed;
173 }
174
175 method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
176 "addDnsServer", "(Ljava/lang/String;)Z");
177 if (!method_id)
178 {
179 goto failed;
180 }
181 str = (*env)->NewStringUTF(env, buf);
182 if (!str)
183 {
184 goto failed;
185 }
186 if (!(*env)->CallBooleanMethod(env, this->builder, method_id, str))
187 {
188 goto failed;
189 }
190 androidjni_detach_thread();
191 return TRUE;
192
193 failed:
194 DBG1(DBG_LIB, "builder: failed to add DNS server");
195 androidjni_exception_occurred(env);
196 androidjni_detach_thread();
197 return FALSE;
198 }
199
200 /**
201 * Establish or reestablish the TUN device
202 */
203 static int establish_internal(private_vpnservice_builder_t *this, char *method)
204 {
205 JNIEnv *env;
206 jmethodID method_id;
207 int fd;
208
209 androidjni_attach_thread(&env);
210
211 DBG2(DBG_LIB, "builder: building TUN device");
212
213 method_id = (*env)->GetMethodID(env, android_charonvpnservice_builder_class,
214 method, "()I");
215 if (!method_id)
216 {
217 goto failed;
218 }
219 fd = (*env)->CallIntMethod(env, this->builder, method_id);
220 if (fd == -1)
221 {
222 goto failed;
223 }
224 androidjni_detach_thread();
225 return fd;
226
227 failed:
228 DBG1(DBG_LIB, "builder: failed to build TUN device");
229 androidjni_exception_occurred(env);
230 androidjni_detach_thread();
231 return -1;
232 }
233
234 METHOD(vpnservice_builder_t, establish, int,
235 private_vpnservice_builder_t *this)
236 {
237 return establish_internal(this, "establish");
238 }
239
240 METHOD(vpnservice_builder_t, establish_no_dns, int,
241 private_vpnservice_builder_t *this)
242 {
243 return establish_internal(this, "establishNoDns");
244 }
245
246 METHOD(vpnservice_builder_t, destroy, void,
247 private_vpnservice_builder_t *this)
248 {
249 JNIEnv *env;
250
251 androidjni_attach_thread(&env);
252 (*env)->DeleteGlobalRef(env, this->builder);
253 androidjni_detach_thread();
254 free(this);
255 }
256
257 vpnservice_builder_t *vpnservice_builder_create(jobject builder)
258 {
259 JNIEnv *env;
260 private_vpnservice_builder_t *this;
261
262 INIT(this,
263 .public = {
264 .add_address = _add_address,
265 .add_route = _add_route,
266 .add_dns = _add_dns,
267 .set_mtu = _set_mtu,
268 .establish = _establish,
269 .establish_no_dns = _establish_no_dns,
270 .destroy = _destroy,
271 },
272 );
273
274 androidjni_attach_thread(&env);
275 this->builder = (*env)->NewGlobalRef(env, builder);
276 androidjni_detach_thread();
277
278 return &this->public;
279 }