Handle initiation of not supported IKE versions properly
[strongswan.git] / src / libcharon / plugins / android / android_service.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <unistd.h>
17 #include <cutils/sockets.h>
18 #include <cutils/properties.h>
19 #include <signal.h>
20
21 #include "android_service.h"
22
23 #include <daemon.h>
24 #include <threading/thread.h>
25 #include <processing/jobs/callback_job.h>
26
27 typedef struct private_android_service_t private_android_service_t;
28
29 /**
30 * private data of Android service
31 */
32 struct private_android_service_t {
33
34 /**
35 * public interface
36 */
37 android_service_t public;
38
39 /**
40 * current IKE_SA
41 */
42 ike_sa_t *ike_sa;
43
44 /**
45 * job that handles requests from the Android control socket
46 */
47 callback_job_t *job;
48
49 /**
50 * android credentials
51 */
52 android_creds_t *creds;
53
54 /**
55 * android control socket
56 */
57 int control;
58
59 };
60
61 /**
62 * Some of the error codes defined in VpnManager.java
63 */
64 typedef enum {
65 /** Error code to indicate an error from authentication. */
66 VPN_ERROR_AUTH = 51,
67 /** Error code to indicate the connection attempt failed. */
68 VPN_ERROR_CONNECTION_FAILED = 101,
69 /** Error code to indicate an error of remote server hanging up. */
70 VPN_ERROR_REMOTE_HUNG_UP = 7,
71 /** Error code to indicate an error of losing connectivity. */
72 VPN_ERROR_CONNECTION_LOST = 103,
73 } android_vpn_errors_t;
74
75 /**
76 * send a status code back to the Android app
77 */
78 static void send_status(private_android_service_t *this, u_char code)
79 {
80 DBG1(DBG_CFG, "status of Android plugin changed: %d", code);
81 send(this->control, &code, 1, 0);
82 }
83
84 METHOD(listener_t, ike_updown, bool,
85 private_android_service_t *this, ike_sa_t *ike_sa, bool up)
86 {
87 /* this callback is only registered during initiation, so if the IKE_SA
88 * goes down we assume an authentication error */
89 if (this->ike_sa == ike_sa && !up)
90 {
91 send_status(this, VPN_ERROR_AUTH);
92 return FALSE;
93 }
94 return TRUE;
95 }
96
97 METHOD(listener_t, child_state_change, bool,
98 private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
99 child_sa_state_t state)
100 {
101 /* this callback is only registered during initiation, so we still have
102 * the control socket open */
103 if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
104 {
105 send_status(this, VPN_ERROR_CONNECTION_FAILED);
106 return FALSE;
107 }
108 return TRUE;
109 }
110
111 /**
112 * Callback used to shutdown the daemon
113 */
114 static job_requeue_t shutdown_callback(void *data)
115 {
116 kill(0, SIGTERM);
117 return JOB_REQUEUE_NONE;
118 }
119
120 METHOD(listener_t, child_updown, bool,
121 private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
122 bool up)
123 {
124 if (this->ike_sa == ike_sa)
125 {
126 if (up)
127 {
128 /* disable the hooks registered to catch initiation failures */
129 this->public.listener.ike_updown = NULL;
130 this->public.listener.child_state_change = NULL;
131 property_set("vpn.status", "ok");
132 }
133 else
134 {
135 callback_job_t *job;
136 /* the control socket is closed as soon as vpn.status is set to "ok"
137 * and the daemon proxy then only checks for terminated daemons to
138 * detect lost connections, so... */
139 DBG1(DBG_CFG, "connection lost, raising delayed SIGTERM");
140 /* to avoid any conflicts we send the SIGTERM not directly from this
141 * callback, but from a different thread. we also delay it to avoid
142 * a race condition during a regular shutdown */
143 job = callback_job_create(shutdown_callback, NULL, NULL, NULL);
144 lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, 1);
145 return FALSE;
146 }
147 }
148 return TRUE;
149 }
150
151 METHOD(listener_t, ike_rekey, bool,
152 private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
153 {
154 if (this->ike_sa == old)
155 {
156 this->ike_sa = new;
157 }
158 return TRUE;
159 }
160
161 /**
162 * Read a string argument from the Android control socket
163 */
164 static char *read_argument(int fd, u_char length)
165 {
166 int offset = 0;
167 char *data = malloc(length + 1);
168 while (offset < length)
169 {
170 int n = recv(fd, &data[offset], length - offset, 0);
171 if (n < 0)
172 {
173 DBG1(DBG_CFG, "failed to read argument from Android"
174 " control socket: %s", strerror(errno));
175 free(data);
176 return NULL;
177 }
178 offset += n;
179 }
180 data[length] = '\0';
181 DBG3(DBG_CFG, "received argument from Android control socket: %s", data);
182 return data;
183 }
184
185 /**
186 * handle the request received from the Android control socket
187 */
188 static job_requeue_t initiate(private_android_service_t *this)
189 {
190 bool oldstate;
191 int fd, i = 0;
192 char *hostname = NULL, *cacert = NULL, *username = NULL, *password = NULL;
193 identification_t *gateway = NULL, *user = NULL;
194 ike_cfg_t *ike_cfg;
195 peer_cfg_t *peer_cfg;
196 child_cfg_t *child_cfg;
197 traffic_selector_t *ts;
198 ike_sa_t *ike_sa;
199 auth_cfg_t *auth;
200 lifetime_cfg_t lifetime = {
201 .time = {
202 .life = 10800, /* 3h */
203 .rekey = 10200, /* 2h50min */
204 .jitter = 300 /* 5min */
205 }
206 };
207
208 fd = accept(this->control, NULL, 0);
209 if (fd < 0)
210 {
211 DBG1(DBG_CFG, "accept on Android control socket failed: %s",
212 strerror(errno));
213 return JOB_REQUEUE_NONE;
214 }
215 /* the original control socket is not used anymore */
216 close(this->control);
217 this->control = fd;
218
219 while (TRUE)
220 {
221 u_char length;
222 if (recv(fd, &length, 1, 0) != 1)
223 {
224 DBG1(DBG_CFG, "failed to read from Android control socket: %s",
225 strerror(errno));
226 return JOB_REQUEUE_NONE;
227 }
228
229 if (length == 0xFF)
230 { /* last argument */
231 break;
232 }
233 else
234 {
235 switch (i++)
236 {
237 case 0: /* gateway */
238 hostname = read_argument(fd, length);
239 break;
240 case 1: /* CA certificate name */
241 cacert = read_argument(fd, length);
242 break;
243 case 2: /* username */
244 username = read_argument(fd, length);
245 break;
246 case 3: /* password */
247 password = read_argument(fd, length);
248 break;
249 }
250 }
251 }
252
253 if (cacert)
254 {
255 if (!this->creds->add_certificate(this->creds, cacert))
256 {
257 DBG1(DBG_CFG, "failed to load CA certificate");
258 }
259 /* if this is a server cert we could use the cert subject as id
260 * but we have to test first if that possible to configure */
261 }
262
263 gateway = identification_create_from_string(hostname);
264 DBG1(DBG_CFG, "using CA certificate, gateway identitiy '%Y'", gateway);
265
266 if (username)
267 {
268 user = identification_create_from_string(username);
269 this->creds->set_username_password(this->creds, user, password);
270 }
271
272 ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", IKEV2_UDP_PORT,
273 hostname, IKEV2_UDP_PORT);
274 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
275
276 peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED,
277 UNIQUE_REPLACE, 1, /* keyingtries */
278 36000, 0, /* rekey 10h, reauth none */
279 600, 600, /* jitter, over 10min */
280 TRUE, 0, /* mobike, DPD */
281 host_create_from_string("0.0.0.0", 0) /* virt */,
282 NULL, FALSE, NULL, NULL); /* pool, mediation */
283
284 auth = auth_cfg_create();
285 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
286 auth->add(auth, AUTH_RULE_IDENTITY, user);
287 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
288 auth = auth_cfg_create();
289 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
290 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
291 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
292
293 child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
294 ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
295 0, 0, NULL, NULL, 0);
296 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
297 ts = traffic_selector_create_dynamic(0, 0, 65535);
298 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
299 ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
300 0, "255.255.255.255", 65535);
301 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
302 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
303
304 /* get us an IKE_SA */
305 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
306 peer_cfg);
307 if (!ike_sa)
308 {
309 peer_cfg->destroy(peer_cfg);
310 send_status(this, VPN_ERROR_CONNECTION_FAILED);
311 return JOB_REQUEUE_NONE;
312 }
313
314 if (!ike_sa->get_peer_cfg(ike_sa))
315 {
316 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
317 }
318 peer_cfg->destroy(peer_cfg);
319
320 /* store the IKE_SA so we can track its progress */
321 this->ike_sa = ike_sa;
322
323 /* confirm that we received the request */
324 send_status(this, i);
325
326 /* get an additional reference because initiate consumes one */
327 child_cfg->get_ref(child_cfg);
328 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
329 {
330 DBG1(DBG_CFG, "failed to initiate tunnel");
331 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
332 ike_sa);
333 send_status(this, VPN_ERROR_CONNECTION_FAILED);
334 return JOB_REQUEUE_NONE;
335 }
336 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
337 return JOB_REQUEUE_NONE;
338 }
339
340 METHOD(android_service_t, destroy, void,
341 private_android_service_t *this)
342 {
343 charon->bus->remove_listener(charon->bus, &this->public.listener);
344 close(this->control);
345 free(this);
346 }
347
348 /**
349 * See header
350 */
351 android_service_t *android_service_create(android_creds_t *creds)
352 {
353 private_android_service_t *this;
354
355 INIT(this,
356 .public = {
357 .listener = {
358 .ike_updown = _ike_updown,
359 .child_state_change = _child_state_change,
360 .child_updown = _child_updown,
361 .ike_rekey = _ike_rekey,
362 },
363 .destroy = _destroy,
364 },
365 .creds = creds,
366 );
367
368 this->control = android_get_control_socket("charon");
369 if (this->control == -1)
370 {
371 DBG1(DBG_CFG, "failed to get Android control socket");
372 free(this);
373 return NULL;
374 }
375
376 if (listen(this->control, 1) < 0)
377 {
378 DBG1(DBG_CFG, "failed to listen on Android control socket: %s",
379 strerror(errno));
380 close(this->control);
381 free(this);
382 return NULL;
383 }
384
385 charon->bus->add_listener(charon->bus, &this->public.listener);
386 this->job = callback_job_create((callback_job_cb_t)initiate, this,
387 NULL, NULL);
388 lib->processor->queue_job(lib->processor, (job_t*)this->job);
389
390 return &this->public;
391 }
392