5c18924be5f1975f2cbc01a4ad88eaa91afd2558
[strongswan.git] / src / frontends / android / jni / libandroidbridge / backend / android_service.c
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"
20
21 #include <daemon.h>
22 #include <library.h>
23 #include <processing/jobs/callback_job.h>
24
25 typedef struct private_android_service_t private_android_service_t;
26
27 /**
28 * private data of Android service
29 */
30 struct private_android_service_t {
31
32 /**
33 * public interface
34 */
35 android_service_t public;
36
37 /**
38 * current IKE_SA
39 */
40 ike_sa_t *ike_sa;
41
42 /**
43 * local ipv4 address
44 */
45 char *local_address;
46
47 /**
48 * gateway
49 */
50 char *gateway;
51
52 /**
53 * username
54 */
55 char *username;
56
57 };
58
59 METHOD(listener_t, child_updown, bool,
60 private_android_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
61 bool up)
62 {
63 if (this->ike_sa == ike_sa)
64 {
65 if (up)
66 {
67 /* disable the hooks registered to catch initiation failures */
68 this->public.listener.ike_updown = NULL;
69 this->public.listener.ike_state_change = NULL;
70 charonservice->update_status(charonservice,
71 CHARONSERVICE_CHILD_STATE_UP);
72 }
73 else
74 {
75 charonservice->update_status(charonservice,
76 CHARONSERVICE_CHILD_STATE_DOWN);
77 return FALSE;
78 }
79 }
80 return TRUE;
81 }
82
83 METHOD(listener_t, ike_updown, bool,
84 private_android_service_t *this, ike_sa_t *ike_sa, bool up)
85 {
86 /* this callback is only registered during initiation, so if the IKE_SA
87 * goes down we assume an authentication error */
88 if (this->ike_sa == ike_sa && !up)
89 {
90 charonservice->update_status(charonservice,
91 CHARONSERVICE_AUTH_ERROR);
92 return FALSE;
93 }
94 return TRUE;
95 }
96
97 METHOD(listener_t, ike_state_change, bool,
98 private_android_service_t *this, ike_sa_t *ike_sa, ike_sa_state_t state)
99 {
100 /* this call back is only registered during initiation */
101 if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
102 {
103 charonservice->update_status(charonservice,
104 CHARONSERVICE_UNREACHABLE_ERROR);
105 return FALSE;
106 }
107 return TRUE;
108 }
109
110 METHOD(listener_t, alert, bool,
111 private_android_service_t *this, ike_sa_t *ike_sa, alert_t alert,
112 va_list args)
113 {
114 if (this->ike_sa == ike_sa)
115 {
116 switch (alert)
117 {
118 case ALERT_PEER_ADDR_FAILED:
119 charonservice->update_status(charonservice,
120 CHARONSERVICE_LOOKUP_ERROR);
121 break;
122 case ALERT_PEER_AUTH_FAILED:
123 charonservice->update_status(charonservice,
124 CHARONSERVICE_PEER_AUTH_ERROR);
125 break;
126 default:
127 break;
128 }
129 }
130 return TRUE;
131 }
132
133 METHOD(listener_t, ike_rekey, bool,
134 private_android_service_t *this, ike_sa_t *old, ike_sa_t *new)
135 {
136 if (this->ike_sa == old)
137 {
138 this->ike_sa = new;
139 }
140 return TRUE;
141 }
142
143 static job_requeue_t initiate(private_android_service_t *this)
144 {
145 identification_t *gateway, *user;
146 ike_cfg_t *ike_cfg;
147 peer_cfg_t *peer_cfg;
148 child_cfg_t *child_cfg;
149 traffic_selector_t *ts;
150 ike_sa_t *ike_sa;
151 auth_cfg_t *auth;
152 lifetime_cfg_t lifetime = {
153 .time = {
154 .life = 10800, /* 3h */
155 .rekey = 10200, /* 2h50min */
156 .jitter = 300 /* 5min */
157 }
158 };
159
160 ike_cfg = ike_cfg_create(TRUE, TRUE, this->local_address, FALSE,
161 charon->socket->get_port(charon->socket, FALSE),
162 this->gateway, FALSE, IKEV2_UDP_PORT);
163 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
164
165 peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED,
166 UNIQUE_REPLACE, 1, /* keyingtries */
167 36000, 0, /* rekey 10h, reauth none */
168 600, 600, /* jitter, over 10min */
169 TRUE, FALSE, /* mobike, aggressive */
170 0, 0, /* DPD delay, timeout */
171 host_create_from_string("0.0.0.0", 0) /* virt */,
172 NULL, FALSE, NULL, NULL); /* pool, mediation */
173
174
175 auth = auth_cfg_create();
176 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
177 user = identification_create_from_string(this->username);
178 auth->add(auth, AUTH_RULE_IDENTITY, user);
179 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
180 auth = auth_cfg_create();
181 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
182 gateway = identification_create_from_string(this->gateway);
183 auth->add(auth, AUTH_RULE_IDENTITY, gateway);
184 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
185
186 child_cfg = child_cfg_create("android", &lifetime, NULL, TRUE, MODE_TUNNEL,
187 ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
188 0, 0, NULL, NULL, 0);
189 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
190 ts = traffic_selector_create_dynamic(0, 0, 65535);
191 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
192 ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0",
193 0, "255.255.255.255", 65535);
194 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
195 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
196
197 /* get us an IKE_SA */
198 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
199 peer_cfg);
200 if (!ike_sa)
201 {
202 peer_cfg->destroy(peer_cfg);
203 charonservice->update_status(charonservice,
204 CHARONSERVICE_GENERIC_ERROR);
205 return JOB_REQUEUE_NONE;
206 }
207 if (!ike_sa->get_peer_cfg(ike_sa))
208 {
209 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
210 }
211 peer_cfg->destroy(peer_cfg);
212
213 /* store the IKE_SA so we can track its progress */
214 this->ike_sa = ike_sa;
215
216 /* get an additional reference because initiate consumes one */
217 child_cfg->get_ref(child_cfg);
218 if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS)
219 {
220 DBG1(DBG_CFG, "failed to initiate tunnel");
221 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
222 ike_sa);
223 return JOB_REQUEUE_NONE;
224 }
225 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
226 return JOB_REQUEUE_NONE;
227 }
228
229 METHOD(android_service_t, destroy, void,
230 private_android_service_t *this)
231 {
232 charon->bus->remove_listener(charon->bus, &this->public.listener);
233 free(this->local_address);
234 free(this->username);
235 free(this->gateway);
236 free(this);
237 }
238
239 /**
240 * See header
241 */
242 android_service_t *android_service_create(char *local_address, char *gateway,
243 char *username)
244 {
245 private_android_service_t *this;
246
247 INIT(this,
248 .public = {
249 .listener = {
250 .ike_rekey = _ike_rekey,
251 .ike_updown = _ike_updown,
252 .ike_state_change = _ike_state_change,
253 .child_updown = _child_updown,
254 .alert = _alert,
255 },
256 .destroy = _destroy,
257 },
258 .local_address = local_address,
259 .username = username,
260 .gateway = gateway,
261 );
262
263 charon->bus->add_listener(charon->bus, &this->public.listener);
264
265 lib->processor->queue_job(lib->processor,
266 (job_t*)callback_job_create((callback_job_cb_t)initiate, this,
267 NULL, NULL));
268 return &this->public;
269 }