]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/frontends/android/jni/libandroidbridge/backend/android_service.c
Add routes based on the installed IPsec policies to the TUN device builder
[thirdparty/strongswan.git] / src / frontends / android / jni / libandroidbridge / backend / android_service.c
CommitLineData
66211196
TB
1/*
2 * Copyright (C) 2010-2012 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 "android_service.h"
19#include "../charonservice.h"
a2993d72 20#include "../vpnservice_builder.h"
66211196
TB
21
22#include <daemon.h>
23#include <library.h>
24#include <processing/jobs/callback_job.h>
a2993d72 25#include <threading/rwlock.h>
66211196
TB
26
27typedef struct private_android_service_t private_android_service_t;
28
a2993d72
TB
29#define TUN_DEFAULT_MTU 1400
30
66211196
TB
31/**
32 * private data of Android service
33 */
34struct private_android_service_t {
35
36 /**
37 * public interface
38 */
39 android_service_t public;
40
41 /**
42 * current IKE_SA
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * local ipv4 address
48 */
49 char *local_address;
50
51 /**
52 * gateway
53 */
54 char *gateway;
55
56 /**
57 * username
58 */
59 char *username;
60
a2993d72
TB
61 /**
62 * lock to safely access the TUN device fd
63 */
64 rwlock_t *lock;
65
66 /**
67 * TUN device file descriptor
68 */
69 int tunfd;
70
66211196
TB
71};
72
30ba2ff7
TB
73/**
74 * Add a route to the TUN device builder
75 */
76static bool add_route(vpnservice_builder_t *builder, host_t *net,
77 u_int8_t prefix)
78{
79 /* if route is 0.0.0.0/0, split it into two routes 0.0.0.0/1 and
80 * 128.0.0.0/1 because otherwise it would conflict with the current default
81 * route */
82 if (net->is_anyaddr(net) && prefix == 0)
83 {
84 bool success;
85
86 success = add_route(builder, net, 1);
87 net = host_create_from_string("128.0.0.0", 0);
88 success = success && add_route(builder, net, 1);
89 net->destroy(net);
90 return success;
91 }
92 return builder->add_route(builder, net, prefix);
93}
94
95/**
96 * Generate and set routes from installed IPsec policies
97 */
98static bool add_routes(vpnservice_builder_t *builder, child_sa_t *child_sa)
99{
100 traffic_selector_t *src_ts, *dst_ts;
101 enumerator_t *enumerator;
102 bool success = TRUE;
103
104 enumerator = child_sa->create_policy_enumerator(child_sa);
105 while (success && enumerator->enumerate(enumerator, &src_ts, &dst_ts))
106 {
107 host_t *net;
108 u_int8_t prefix;
109
110 dst_ts->to_subnet(dst_ts, &net, &prefix);
111 success = add_route(builder, net, prefix);
112 net->destroy(net);
113 }
114 enumerator->destroy(enumerator);
115 return success;
116}
117
a2993d72
TB
118/**
119 * Setup a new TUN device for the supplied SAs.
120 * Additional information such as DNS servers are gathered in appropriate
121 * listeners asynchronously. To be sure every required bit of information is
122 * available this should be called after the CHILD_SA has been established.
123 */
124static bool setup_tun_device(private_android_service_t *this,
125 ike_sa_t *ike_sa, child_sa_t *child_sa)
126{
127 vpnservice_builder_t *builder;
62e6630b 128 host_t *vip;
a2993d72
TB
129 int tunfd;
130
131 DBG1(DBG_DMN, "setting up TUN device for CHILD_SA %s{%u}",
132 child_sa->get_name(child_sa), child_sa->get_reqid(child_sa));
62e6630b
TB
133 vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
134 if (!vip || vip->is_anyaddr(vip))
135 {
136 DBG1(DBG_DMN, "setting up TUN device failed, no virtual IP found");
137 return FALSE;
138 }
a2993d72
TB
139
140 builder = charonservice->get_vpnservice_builder(charonservice);
62e6630b 141 if (!builder->add_address(builder, vip) ||
30ba2ff7 142 !add_routes(builder, child_sa) ||
62e6630b 143 !builder->set_mtu(builder, TUN_DEFAULT_MTU))
a2993d72
TB
144 {
145 return FALSE;
146 }
147
148 tunfd = builder->establish(builder);
149 if (tunfd == -1)
150 {
151 return FALSE;
152 }
153
154 this->lock->write_lock(this->lock);
155 this->tunfd = tunfd;
156 this->lock->unlock(this->lock);
157
158 DBG1(DBG_DMN, "successfully created TUN device");
159 return TRUE;
160}
161
162/**
163 * Close the current tun device
164 */
165static void close_tun_device(private_android_service_t *this)
166{
167 int tunfd;
168
169 this->lock->write_lock(this->lock);
170 if (this->tunfd < 0)
171 { /* already closed (or never created) */
172 this->lock->unlock(this->lock);
173 return;
174 }
175 tunfd = this->tunfd;
176 this->tunfd = -1;
177 this->lock->unlock(this->lock);
178 close(tunfd);
179}
180
66211196
TB
181METHOD(listener_t, child_updown, bool,
182 private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
183 bool up)
184{
185 if (this->ike_sa == ike_sa)
186 {
187 if (up)
188 {
189 /* disable the hooks registered to catch initiation failures */
190 this->public.listener.ike_updown = NULL;
191 this->public.listener.ike_state_change = NULL;
a2993d72
TB
192 if (!setup_tun_device(this, ike_sa, child_sa))
193 {
194 DBG1(DBG_DMN, "failed to setup TUN device");
195 charonservice->update_status(charonservice,
196 CHARONSERVICE_GENERIC_ERROR);
197 return FALSE;
198
199 }
66211196
TB
200 charonservice->update_status(charonservice,
201 CHARONSERVICE_CHILD_STATE_UP);
202 }
203 else
204 {
a2993d72 205 close_tun_device(this);
66211196
TB
206 charonservice->update_status(charonservice,
207 CHARONSERVICE_CHILD_STATE_DOWN);
208 return FALSE;
209 }
210 }
211 return TRUE;
212}
213
214METHOD(listener_t, ike_updown, bool,
215 private_android_service_t *this, ike_sa_t *ike_sa, bool up)
216{
217 /* this callback is only registered during initiation, so if the IKE_SA
218 * goes down we assume an authentication error */
219 if (this->ike_sa == ike_sa && !up)
220 {
221 charonservice->update_status(charonservice,
222 CHARONSERVICE_AUTH_ERROR);
223 return FALSE;
224 }
225 return TRUE;
226}
227
228METHOD(listener_t, ike_state_change, bool,
229 private_android_service_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
230{
231 /* this call back is only registered during initiation */
232 if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
233 {
234 charonservice->update_status(charonservice,
235 CHARONSERVICE_UNREACHABLE_ERROR);
236 return FALSE;
237 }
238 return TRUE;
239}
240
241METHOD(listener_t, alert, bool,
242 private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert,
243 va_list args)
244{
245 if (this->ike_sa == ike_sa)
246 {
247 switch (alert)
248 {
249 case ALERT_PEER_ADDR_FAILED:
250 charonservice->update_status(charonservice,
251 CHARONSERVICE_LOOKUP_ERROR);
252 break;
253 case ALERT_PEER_AUTH_FAILED:
254 charonservice->update_status(charonservice,
255 CHARONSERVICE_PEER_AUTH_ERROR);
256 break;
257 default:
258 break;
259 }
260 }
261 return TRUE;
262}
263
264METHOD(listener_t, ike_rekey, bool,
265 private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
266{
267 if (this->ike_sa == old)
268 {
269 this->ike_sa = new;
270 }
271 return TRUE;
272}
273
274static job_requeue_t initiate(private_android_service_t *this)
275{
276 identification_t *gateway, *user;
277 ike_cfg_t *ike_cfg;
278 peer_cfg_t *peer_cfg;
279 child_cfg_t *child_cfg;
280 traffic_selector_t *ts;
281 ike_sa_t *ike_sa;
282 auth_cfg_t *auth;
283 lifetime_cfg_t lifetime = {
284 .time = {
285 .life = 10800, /* 3h */
286 .rekey = 10200, /* 2h50min */
287 .jitter = 300 /* 5min */
288 }
289 };
290
291 ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE,
292 charon->socket->get_port(charon->socket, FALSE),
293 this->gateway, FALSE, IKEV2_UDP_PORT);
294 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
295
296 peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED,
297 UNIQUE_REPLACE, 1, /* keyingtries */
298 36000, 0, /* rekey 10h, reauth none */
299 600, 600, /* jitter, over 10min */
300 TRUE, FALSE, /* mobike, aggressive */
301 0, 0, /* DPD delay, timeout */
302 host_create_from_string("0.0.0.0", 0) /* virt */,
303 NULL, FALSE, NULL, NULL); /* pool, mediation */
304
305
306 auth = auth_cfg_create();
307 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
308 user = identification_create_from_string(this->username);
309 auth->add(auth, AUTH_RULE_IDENTITY, user);
310 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
311 auth = auth_cfg_create();
312 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
313 gateway = identification_create_from_string(this->gateway);
314 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
315 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
316
317 child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
318 ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
319 0, 0, NULL, NULL, 0);
320 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
321 ts = traffic_selector_create_dynamic(0, 0, 65535);
322 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
323 ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
324 0, "255.255.255.255", 65535);
325 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
326 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
327
328 /* get us an IKE_SA */
329 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
330 peer_cfg);
331 if (!ike_sa)
332 {
333 peer_cfg->destroy(peer_cfg);
334 charonservice->update_status(charonservice,
335 CHARONSERVICE_GENERIC_ERROR);
336 return JOB_REQUEUE_NONE;
337 }
338 if (!ike_sa->get_peer_cfg(ike_sa))
339 {
340 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
341 }
342 peer_cfg->destroy(peer_cfg);
343
344 /* store the IKE_SA so we can track its progress */
345 this->ike_sa = ike_sa;
346
347 /* get an additional reference because initiate consumes one */
348 child_cfg->get_ref(child_cfg);
349 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
350 {
351 DBG1(DBG_CFG, "failed to initiate tunnel");
352 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
353 ike_sa);
354 return JOB_REQUEUE_NONE;
355 }
356 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
357 return JOB_REQUEUE_NONE;
358}
359
360METHOD(android_service_t, destroy, void,
361 private_android_service_t *this)
362{
363 charon->bus->remove_listener(charon->bus, &this->public.listener);
a2993d72
TB
364 /* make sure the tun device is actually closed */
365 close_tun_device(this);
366 this->lock->destroy(this->lock);
66211196
TB
367 free(this->local_address);
368 free(this->username);
369 free(this->gateway);
370 free(this);
371}
372
373/**
374 * See header
375 */
376android_service_t *android_service_create(char *local_address, char *gateway,
377 char *username)
378{
379 private_android_service_t *this;
380
381 INIT(this,
382 .public = {
383 .listener = {
384 .ike_rekey = _ike_rekey,
385 .ike_updown = _ike_updown,
386 .ike_state_change = _ike_state_change,
387 .child_updown = _child_updown,
388 .alert = _alert,
389 },
390 .destroy = _destroy,
391 },
a2993d72 392 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
66211196
TB
393 .local_address = local_address,
394 .username = username,
395 .gateway = gateway,
a2993d72 396 .tunfd = -1,
66211196
TB
397 );
398
399 charon->bus->add_listener(charon->bus, &this->public.listener);
400
401 lib->processor->queue_job(lib->processor,
402 (job_t*)callback_job_create((callback_job_cb_t)initiate, this,
403 NULL, NULL));
404 return &this->public;
405}