ad458caad84c6eede4a6891f3efd7062e6afbb0d
[strongswan.git] / src / libcharon / plugins / ha / ha_tunnel.c
1 /*
2 * Copyright (C) 2009 Martin Willi
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 "ha_tunnel.h"
17 #include "ha_plugin.h"
18
19 #include <daemon.h>
20 #include <utils/identification.h>
21 #include <processing/jobs/callback_job.h>
22
23 typedef struct private_ha_tunnel_t private_ha_tunnel_t;
24 typedef struct ha_backend_t ha_backend_t;
25 typedef struct ha_creds_t ha_creds_t;
26
27 /**
28 * Serves credentials for the HA SA
29 */
30 struct ha_creds_t {
31
32 /**
33 * Implements credential_set_t
34 */
35 credential_set_t public;
36
37 /**
38 * own identity
39 */
40 identification_t *local;
41
42 /**
43 * peer identity
44 */
45 identification_t *remote;
46
47 /**
48 * Shared key to serve
49 */
50 shared_key_t *key;
51 };
52
53 /**
54 * Serves configurations for the HA SA
55 */
56 struct ha_backend_t {
57
58 /**
59 * Implements backend_t
60 */
61 backend_t public;
62
63 /**
64 * peer config we serve
65 */
66 peer_cfg_t *cfg;
67 };
68
69 /**
70 * Private data of an ha_tunnel_t object.
71 */
72 struct private_ha_tunnel_t {
73
74 /**
75 * Public ha_tunnel_t interface.
76 */
77 ha_tunnel_t public;
78
79 /**
80 * Reqid of installed trap
81 */
82 u_int32_t trap;
83
84 /**
85 * backend for HA SA
86 */
87 ha_backend_t backend;
88
89 /**
90 * credential set for HA SA
91 */
92 ha_creds_t creds;
93 };
94
95 METHOD(ha_tunnel_t, is_sa, bool,
96 private_ha_tunnel_t *this, ike_sa_t *ike_sa)
97 {
98 peer_cfg_t *cfg = this->backend.cfg;
99
100 return cfg && ike_sa->get_ike_cfg(ike_sa) == cfg->get_ike_cfg(cfg);
101 }
102
103 /**
104 * Enumerator over HA shared_key
105 */
106 typedef struct {
107 /** Implements enumerator_t */
108 enumerator_t public;
109 /** a single secret we serve */
110 shared_key_t *key;
111 } shared_enum_t;
112
113 METHOD(enumerator_t, shared_enumerate, bool,
114 shared_enum_t *this, shared_key_t **key, id_match_t *me, id_match_t *other)
115 {
116 if (this->key)
117 {
118 if (me)
119 {
120 *me = ID_MATCH_PERFECT;
121 }
122 if (other)
123 {
124 *other = ID_MATCH_PERFECT;
125 }
126 *key = this->key;
127 this->key = NULL;
128 return TRUE;
129 }
130 return FALSE;
131 }
132
133 METHOD(ha_creds_t, create_shared_enumerator, enumerator_t*,
134 ha_creds_t *this, shared_key_type_t type,
135 identification_t *me, identification_t *other)
136 {
137 shared_enum_t *enumerator;
138
139 if (type != SHARED_IKE && type != SHARED_ANY)
140 {
141 return NULL;
142 }
143 if (me && !me->equals(me, this->local))
144 {
145 return NULL;
146 }
147 if (other && !other->equals(other, this->remote))
148 {
149 return NULL;
150 }
151
152 INIT(enumerator,
153 .public = {
154 .enumerate = (void*)_shared_enumerate,
155 .destroy = (void*)free,
156 },
157 .key = this->key,
158 );
159
160 return &enumerator->public;
161 }
162
163 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
164 ha_backend_t *this, identification_t *me, identification_t *other)
165 {
166 return enumerator_create_single(this->cfg, NULL);
167 }
168
169 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
170 ha_backend_t *this, host_t *me, host_t *other)
171 {
172 return enumerator_create_single(this->cfg->get_ike_cfg(this->cfg), NULL);
173 }
174
175 /**
176 * Install configs and a a trap for secured HA message exchange
177 */
178 static void setup_tunnel(private_ha_tunnel_t *this,
179 char *local, char *remote, char *secret)
180 {
181 peer_cfg_t *peer_cfg;
182 ike_cfg_t *ike_cfg;
183 auth_cfg_t *auth_cfg;
184 child_cfg_t *child_cfg;
185 traffic_selector_t *ts;
186 lifetime_cfg_t lifetime = {
187 .time = {
188 .life = 21600, .rekey = 20400, .jitter = 400,
189 },
190 };
191
192 /* setup credentials */
193 this->creds.local = identification_create_from_string(local);
194 this->creds.remote = identification_create_from_string(remote);
195 this->creds.key = shared_key_create(SHARED_IKE,
196 chunk_clone(chunk_create(secret, strlen(secret))));
197 this->creds.public.create_private_enumerator = (void*)return_null;
198 this->creds.public.create_cert_enumerator = (void*)return_null;
199 this->creds.public.create_shared_enumerator = (void*)_create_shared_enumerator;
200 this->creds.public.create_cdp_enumerator = (void*)return_null;
201 this->creds.public.cache_cert = (void*)nop;
202
203 lib->credmgr->add_set(lib->credmgr, &this->creds.public);
204
205 /* create config and backend */
206 ike_cfg = ike_cfg_create(FALSE, FALSE, local, FALSE,
207 charon->socket->get_port(charon->socket, FALSE),
208 remote, FALSE, IKEV2_UDP_PORT);
209 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
210 peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND,
211 UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30,
212 0, NULL, NULL, FALSE, NULL, NULL);
213
214 auth_cfg = auth_cfg_create();
215 auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
216 auth_cfg->add(auth_cfg, AUTH_RULE_IDENTITY,
217 identification_create_from_string(local));
218 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
219
220 auth_cfg = auth_cfg_create();
221 auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
222 auth_cfg->add(auth_cfg, AUTH_RULE_IDENTITY,
223 identification_create_from_string(remote));
224 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
225
226 child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE, MODE_TRANSPORT,
227 ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE,
228 0, 0, NULL, NULL, 0);
229 ts = traffic_selector_create_dynamic(IPPROTO_UDP, HA_PORT, HA_PORT);
230 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
231 ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535);
232 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
233 ts = traffic_selector_create_dynamic(IPPROTO_UDP, HA_PORT, HA_PORT);
234 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
235 ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535);
236 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
237 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
238 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
239
240 this->backend.cfg = peer_cfg;
241 this->backend.public.create_peer_cfg_enumerator = (void*)_create_peer_cfg_enumerator;
242 this->backend.public.create_ike_cfg_enumerator = (void*)_create_ike_cfg_enumerator;
243 this->backend.public.get_peer_cfg_by_name = (void*)return_null;
244
245 charon->backends->add_backend(charon->backends, &this->backend.public);
246
247 /* install an acquiring trap */
248 this->trap = charon->traps->install(charon->traps, peer_cfg, child_cfg);
249 }
250
251 METHOD(ha_tunnel_t, destroy, void,
252 private_ha_tunnel_t *this)
253 {
254 if (this->backend.cfg)
255 {
256 charon->backends->remove_backend(charon->backends, &this->backend.public);
257 this->backend.cfg->destroy(this->backend.cfg);
258 }
259 if (this->creds.key)
260 {
261 lib->credmgr->remove_set(lib->credmgr, &this->creds.public);
262 this->creds.key->destroy(this->creds.key);
263 }
264 this->creds.local->destroy(this->creds.local);
265 this->creds.remote->destroy(this->creds.remote);
266 if (this->trap)
267 {
268 charon->traps->uninstall(charon->traps, this->trap);
269 }
270 free(this);
271 }
272
273 /**
274 * See header
275 */
276 ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret)
277 {
278 private_ha_tunnel_t *this;
279
280 INIT(this,
281 .public = {
282 .is_sa = _is_sa,
283 .destroy = _destroy,
284 },
285 );
286
287 setup_tunnel(this, local, remote, secret);
288
289 return &this->public;
290 }
291