]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libcharon/plugins/ha/ha_dispatcher.c
ha: Register the correct IKE_SA with the manager after a rekeying
[people/ms/strongswan.git] / src / libcharon / plugins / ha / ha_dispatcher.c
CommitLineData
190edaf5
MW
1/*
2 * Copyright (C) 2008 Martin Willi
1b671669 3 * HSR Hochschule fuer Technik Rapperswil
190edaf5
MW
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.
190edaf5
MW
14 */
15
d8748966 16#include "ha_dispatcher.h"
190edaf5
MW
17
18#include <daemon.h>
6bc6f67b 19#include <sa/ikev2/keymat_v2.h>
8bcd9bd1 20#include <sa/ikev1/keymat_v1.h>
190edaf5 21#include <processing/jobs/callback_job.h>
aa3b53e7 22#include <processing/jobs/adopt_children_job.h>
190edaf5 23
d8748966 24typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
26451482 25typedef struct ha_diffie_hellman_t ha_diffie_hellman_t;
190edaf5
MW
26
27/**
d8748966 28 * Private data of an ha_dispatcher_t object.
190edaf5 29 */
d8748966 30struct private_ha_dispatcher_t {
190edaf5
MW
31
32 /**
d8748966 33 * Public ha_dispatcher_t interface.
190edaf5 34 */
d8748966 35 ha_dispatcher_t public;
190edaf5
MW
36
37 /**
38 * socket to pull messages from
39 */
d8748966 40 ha_socket_t *socket;
190edaf5 41
37459ea9
MW
42 /**
43 * segments to control
44 */
d8748966 45 ha_segments_t *segments;
37459ea9 46
aa334daa
MW
47 /**
48 * Cache for resync
49 */
50 ha_cache_t *cache;
51
08e266a1
MW
52 /**
53 * Kernel helper
54 */
55 ha_kernel_t *kernel;
56
98d03438
MW
57 /**
58 * HA enabled pool
59 */
60 ha_attribute_t *attr;
190edaf5
MW
61};
62
765935c8 63/**
26451482 64 * DH implementation for HA synced DH values
765935c8 65 */
26451482
MW
66struct ha_diffie_hellman_t {
67
68 /**
69 * Implements diffie_hellman_t
70 */
71 diffie_hellman_t dh;
72
73 /**
74 * Shared secret
75 */
76 chunk_t secret;
8bcd9bd1
MW
77
78 /**
79 * Own public value
80 */
81 chunk_t pub;
26451482
MW
82};
83
bace1d64 84METHOD(diffie_hellman_t, dh_get_shared_secret, bool,
26451482 85 ha_diffie_hellman_t *this, chunk_t *secret)
765935c8 86{
26451482 87 *secret = chunk_clone(this->secret);
bace1d64 88 return TRUE;
765935c8
MW
89}
90
42431690 91METHOD(diffie_hellman_t, dh_get_my_public_value, bool,
8bcd9bd1
MW
92 ha_diffie_hellman_t *this, chunk_t *value)
93{
94 *value = chunk_clone(this->pub);
42431690 95 return TRUE;
8bcd9bd1
MW
96}
97
26451482
MW
98METHOD(diffie_hellman_t, dh_destroy, void,
99 ha_diffie_hellman_t *this)
100{
101 free(this);
102}
103
104/**
105 * Create a HA synced DH implementation
106 */
8bcd9bd1 107static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub)
26451482
MW
108{
109 ha_diffie_hellman_t *this;
110
111 INIT(this,
112 .dh = {
113 .get_shared_secret = _dh_get_shared_secret,
8bcd9bd1 114 .get_my_public_value = _dh_get_my_public_value,
26451482
MW
115 .destroy = _dh_destroy,
116 },
117 .secret = secret,
8bcd9bd1 118 .pub = pub,
26451482
MW
119 );
120
121 return &this->dh;
122}
123
190edaf5
MW
124/**
125 * Process messages of type IKE_ADD
126 */
d8748966 127static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message)
190edaf5 128{
d8748966
MW
129 ha_message_attribute_t attribute;
130 ha_message_value_t value;
190edaf5 131 enumerator_t *enumerator;
d4113a42 132 ike_sa_t *ike_sa = NULL, *old_sa = NULL;
8bcd9bd1 133 ike_version_t version = IKEV2;
b12c53ce
AS
134 uint16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
135 uint16_t dh_grp = 0;
d4113a42
MW
136 chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
137 chunk_t secret = chunk_empty, old_skd = chunk_empty;
8bcd9bd1 138 chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
34347094 139 host_t *other = NULL;
6bc6f67b 140 bool ok = FALSE;
eed20c21 141 auth_method_t method = AUTH_RSA;
190edaf5
MW
142
143 enumerator = message->create_attribute_enumerator(message);
144 while (enumerator->enumerate(enumerator, &attribute, &value))
145 {
146 switch (attribute)
147 {
d8748966 148 case HA_IKE_ID:
17ec1c74 149 ike_sa = ike_sa_create(value.ike_sa_id,
8bcd9bd1 150 value.ike_sa_id->is_initiator(value.ike_sa_id), version);
765935c8 151 break;
d8748966 152 case HA_IKE_REKEY_ID:
34d240a6
MW
153 old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
154 value.ike_sa_id);
765935c8 155 break;
34347094
TE
156 case HA_REMOTE_ADDR:
157 other = value.host->clone(value.host);
158 break;
8bcd9bd1
MW
159 case HA_IKE_VERSION:
160 version = value.u8;
161 break;
d8748966 162 case HA_NONCE_I:
765935c8
MW
163 nonce_i = value.chunk;
164 break;
d8748966 165 case HA_NONCE_R:
765935c8
MW
166 nonce_r = value.chunk;
167 break;
d8748966 168 case HA_SECRET:
765935c8
MW
169 secret = value.chunk;
170 break;
8bcd9bd1
MW
171 case HA_LOCAL_DH:
172 dh_local = value.chunk;
173 break;
174 case HA_REMOTE_DH:
175 dh_remote = value.chunk;
176 break;
177 case HA_PSK:
178 psk = value.chunk;
179 break;
d8748966 180 case HA_OLD_SKD:
d4113a42
MW
181 old_skd = value.chunk;
182 break;
d8748966 183 case HA_ALG_ENCR:
765935c8
MW
184 encr = value.u16;
185 break;
d8748966 186 case HA_ALG_ENCR_LEN:
765935c8
MW
187 len = value.u16;
188 break;
d8748966 189 case HA_ALG_INTEG:
765935c8
MW
190 integ = value.u16;
191 break;
d8748966 192 case HA_ALG_PRF:
765935c8
MW
193 prf = value.u16;
194 break;
d8748966 195 case HA_ALG_OLD_PRF:
d4113a42
MW
196 old_prf = value.u16;
197 break;
f1e90883
TB
198 case HA_ALG_DH:
199 dh_grp = value.u16;
200 break;
eed20c21
TE
201 case HA_AUTH_METHOD:
202 method = value.u16;
765935c8
MW
203 default:
204 break;
205 }
206 }
207 enumerator->destroy(enumerator);
208
765935c8
MW
209 if (ike_sa)
210 {
211 proposal_t *proposal;
26451482 212 diffie_hellman_t *dh;
765935c8 213
bb162175 214 proposal = proposal_create(PROTO_IKE, 0);
765935c8
MW
215 if (integ)
216 {
217 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
218 }
219 if (encr)
220 {
221 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
222 }
223 if (prf)
224 {
225 proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
226 }
f1e90883
TB
227 if (dh_grp)
228 {
229 proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
230 }
c94fe198 231 charon->bus->set_sa(charon->bus, ike_sa);
8bcd9bd1 232 dh = ha_diffie_hellman_create(secret, dh_local);
6bc6f67b
MW
233 if (ike_sa->get_version(ike_sa) == IKEV2)
234 {
235 keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
236
26451482 237 ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
6bc6f67b
MW
238 nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
239 }
8bcd9bd1
MW
240 if (ike_sa->get_version(ike_sa) == IKEV1)
241 {
242 keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
243 shared_key_t *shared = NULL;
8bcd9bd1
MW
244
245 if (psk.len)
246 {
247 method = AUTH_PSK;
248 shared = shared_key_create(SHARED_IKE, chunk_clone(psk));
249 }
ae926418
MW
250 if (keymat_v1->create_hasher(keymat_v1, proposal))
251 {
252 ok = keymat_v1->derive_ike_keys(keymat_v1, proposal,
253 dh, dh_remote, nonce_i, nonce_r,
254 ike_sa->get_id(ike_sa), method, shared);
255 }
8bcd9bd1
MW
256 DESTROY_IF(shared);
257 }
26451482 258 dh->destroy(dh);
6bc6f67b 259 if (ok)
34d240a6
MW
260 {
261 if (old_sa)
20dfbcad
TB
262 { /* register IKE_SA before calling inherit_post() so no scheduled
263 * jobs are lost */
264 charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
79b526de 265 ike_sa);
713a1122
MW
266 ike_sa->inherit_pre(ike_sa, old_sa);
267 ike_sa->inherit_post(ike_sa, old_sa);
34d240a6
MW
268 charon->ike_sa_manager->checkin_and_destroy(
269 charon->ike_sa_manager, old_sa);
270 old_sa = NULL;
271 }
34347094
TE
272 if (other)
273 {
274 ike_sa->set_other_host(ike_sa, other);
275 other = NULL;
276 }
34d240a6 277 ike_sa->set_state(ike_sa, IKE_CONNECTING);
c3f1839a 278 ike_sa->set_proposal(ike_sa, proposal);
aa334daa
MW
279 this->cache->cache(this->cache, ike_sa, message);
280 message = NULL;
34d240a6
MW
281 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
282 }
283 else
765935c8 284 {
d8748966 285 DBG1(DBG_IKE, "HA keymat derivation failed");
34d240a6 286 ike_sa->destroy(ike_sa);
765935c8 287 }
c94fe198 288 charon->bus->set_sa(charon->bus, NULL);
765935c8 289 proposal->destroy(proposal);
34d240a6
MW
290 }
291 if (old_sa)
292 {
293 charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
765935c8 294 }
34347094 295 DESTROY_IF(other);
aa334daa 296 DESTROY_IF(message);
765935c8
MW
297}
298
299/**
300 * Apply a condition flag to the IKE_SA if it is in set
301 */
302static void set_condition(ike_sa_t *ike_sa, ike_condition_t set,
303 ike_condition_t flag)
304{
305 ike_sa->set_condition(ike_sa, flag, flag & set);
306}
307
308/**
309 * Apply a extension flag to the IKE_SA if it is in set
310 */
311static void set_extension(ike_sa_t *ike_sa, ike_extension_t set,
312 ike_extension_t flag)
313{
314 if (flag & set)
315 {
316 ike_sa->enable_extension(ike_sa, flag);
317 }
318}
319
320/**
321 * Process messages of type IKE_UPDATE
322 */
d8748966
MW
323static void process_ike_update(private_ha_dispatcher_t *this,
324 ha_message_t *message)
765935c8 325{
d8748966
MW
326 ha_message_attribute_t attribute;
327 ha_message_value_t value;
765935c8
MW
328 enumerator_t *enumerator;
329 ike_sa_t *ike_sa = NULL;
330 peer_cfg_t *peer_cfg = NULL;
fa4f71c8 331 auth_cfg_t *auth;
d2e8f20d 332 bool received_vip = FALSE, first_local_vip = TRUE, first_peer_addr = TRUE;
765935c8
MW
333
334 enumerator = message->create_attribute_enumerator(message);
335 while (enumerator->enumerate(enumerator, &attribute, &value))
336 {
d8748966 337 if (attribute != HA_IKE_ID && ike_sa == NULL)
765935c8 338 {
34d240a6 339 /* must be first attribute */
765935c8
MW
340 break;
341 }
342 switch (attribute)
343 {
d8748966 344 case HA_IKE_ID:
34d240a6
MW
345 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
346 value.ike_sa_id);
190edaf5 347 break;
d8748966 348 case HA_LOCAL_ID:
765935c8
MW
349 ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
350 break;
d8748966 351 case HA_REMOTE_ID:
765935c8
MW
352 ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
353 break;
fa4f71c8
MW
354 case HA_REMOTE_EAP_ID:
355 auth = auth_cfg_create();
356 auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
357 ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
358 break;
d8748966 359 case HA_LOCAL_ADDR:
765935c8
MW
360 ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
361 break;
d8748966 362 case HA_REMOTE_ADDR:
765935c8
MW
363 ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
364 break;
d8748966 365 case HA_LOCAL_VIP:
d2e8f20d
TB
366 if (first_local_vip)
367 {
368 ike_sa->clear_virtual_ips(ike_sa, TRUE);
369 first_local_vip = FALSE;
370 }
101d26ba 371 ike_sa->add_virtual_ip(ike_sa, TRUE, value.host);
80624c79 372 break;
d8748966 373 case HA_REMOTE_VIP:
d2e8f20d
TB
374 if (!received_vip)
375 {
376 ike_sa->clear_virtual_ips(ike_sa, FALSE);
377 }
101d26ba 378 ike_sa->add_virtual_ip(ike_sa, FALSE, value.host);
98d03438 379 received_vip = TRUE;
765935c8 380 break;
94bbc602 381 case HA_PEER_ADDR:
cd6b5bf8
TB
382 if (first_peer_addr)
383 {
384 ike_sa->clear_peer_addresses(ike_sa);
385 first_peer_addr = FALSE;
386 }
94bbc602 387 ike_sa->add_peer_address(ike_sa, value.host->clone(value.host));
190edaf5 388 break;
d8748966 389 case HA_CONFIG_NAME:
765935c8
MW
390 peer_cfg = charon->backends->get_peer_cfg_by_name(
391 charon->backends, value.str);
34d240a6
MW
392 if (peer_cfg)
393 {
394 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
395 peer_cfg->destroy(peer_cfg);
396 }
397 else
398 {
d8748966 399 DBG1(DBG_IKE, "HA is missing nodes peer configuration");
438318c6
MW
400 charon->ike_sa_manager->checkin_and_destroy(
401 charon->ike_sa_manager, ike_sa);
402 ike_sa = NULL;
34d240a6 403 }
190edaf5 404 break;
d8748966 405 case HA_EXTENSIONS:
26d08a24
MW
406 set_extension(ike_sa, value.u32, EXT_NATT);
407 set_extension(ike_sa, value.u32, EXT_MOBIKE);
408 set_extension(ike_sa, value.u32, EXT_HASH_AND_URL);
f54bcf35
MW
409 set_extension(ike_sa, value.u32, EXT_MULTIPLE_AUTH);
410 set_extension(ike_sa, value.u32, EXT_STRONGSWAN);
411 set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION);
412 set_extension(ike_sa, value.u32, EXT_MS_WINDOWS);
868d92a4
MW
413 set_extension(ike_sa, value.u32, EXT_XAUTH);
414 set_extension(ike_sa, value.u32, EXT_DPD);
26d08a24 415 break;
d8748966 416 case HA_CONDITIONS:
26d08a24
MW
417 set_condition(ike_sa, value.u32, COND_NAT_ANY);
418 set_condition(ike_sa, value.u32, COND_NAT_HERE);
419 set_condition(ike_sa, value.u32, COND_NAT_THERE);
420 set_condition(ike_sa, value.u32, COND_NAT_FAKE);
421 set_condition(ike_sa, value.u32, COND_EAP_AUTHENTICATED);
422 set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
423 set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
f54bcf35 424 set_condition(ike_sa, value.u32, COND_STALE);
868d92a4
MW
425 set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN);
426 set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED);
190edaf5 427 break;
765935c8
MW
428 default:
429 break;
430 }
431 }
432 enumerator->destroy(enumerator);
433
34d240a6 434 if (ike_sa)
765935c8 435 {
34d240a6
MW
436 if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
437 ike_sa->get_peer_cfg(ike_sa))
438 {
aa334daa
MW
439 DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
440 ike_sa->get_name(ike_sa),
441 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
442 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
34d240a6
MW
443 ike_sa->set_state(ike_sa, IKE_PASSIVE);
444 }
98d03438
MW
445 if (received_vip)
446 {
497ce2cf 447 enumerator_t *pools, *vips;
98d03438
MW
448 host_t *vip;
449 char *pool;
450
451 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
101d26ba 452 if (peer_cfg)
98d03438 453 {
497ce2cf
MW
454 pools = peer_cfg->create_pool_enumerator(peer_cfg);
455 while (pools->enumerate(pools, &pool))
98d03438 456 {
497ce2cf
MW
457 vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
458 while (vips->enumerate(vips, &vip))
101d26ba
MW
459 {
460 this->attr->reserve(this->attr, pool, vip);
461 }
497ce2cf 462 vips->destroy(vips);
98d03438 463 }
497ce2cf 464 pools->destroy(pools);
98d03438
MW
465 }
466 }
e1c7e1bc 467#ifdef USE_IKEV1
aa3b53e7
MW
468 if (ike_sa->get_version(ike_sa) == IKEV1)
469 {
470 lib->processor->queue_job(lib->processor, (job_t*)
471 adopt_children_job_create(ike_sa->get_id(ike_sa)));
472 }
e1c7e1bc 473#endif /* USE_IKEV1 */
aa334daa 474 this->cache->cache(this->cache, ike_sa, message);
34d240a6 475 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
765935c8 476 }
aa334daa
MW
477 else
478 {
479 DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
480 message->destroy(message);
481 }
765935c8
MW
482}
483
ad2488fc
MW
484/**
485 * Process messages of type IKE_MID_INITIATOR/RESPONDER
486 */
487static void process_ike_mid(private_ha_dispatcher_t *this,
488 ha_message_t *message, bool initiator)
489{
490 ha_message_attribute_t attribute;
491 ha_message_value_t value;
492 enumerator_t *enumerator;
493 ike_sa_t *ike_sa = NULL;
b12c53ce 494 uint32_t mid = 0;
ad2488fc
MW
495
496 enumerator = message->create_attribute_enumerator(message);
497 while (enumerator->enumerate(enumerator, &attribute, &value))
498 {
499 switch (attribute)
500 {
501 case HA_IKE_ID:
502 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
503 value.ike_sa_id);
504 break;
505 case HA_MID:
506 mid = value.u32;
507 break;
508 default:
509 break;
510 }
511 }
512 enumerator->destroy(enumerator);
513
514 if (ike_sa)
515 {
516 if (mid)
517 {
518 ike_sa->set_message_id(ike_sa, initiator, mid);
519 }
aa334daa 520 this->cache->cache(this->cache, ike_sa, message);
ad2488fc
MW
521 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
522 }
aa334daa
MW
523 else
524 {
525 message->destroy(message);
526 }
ad2488fc
MW
527}
528
c8531b7e
MW
529/**
530 * Process messages of type IKE_IV
531 */
532static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message)
533{
534 ha_message_attribute_t attribute;
535 ha_message_value_t value;
536 enumerator_t *enumerator;
537 ike_sa_t *ike_sa = NULL;
538 chunk_t iv = chunk_empty;
539
540 enumerator = message->create_attribute_enumerator(message);
541 while (enumerator->enumerate(enumerator, &attribute, &value))
542 {
543 switch (attribute)
544 {
545 case HA_IKE_ID:
546 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
547 value.ike_sa_id);
548 break;
549 case HA_IV:
550 iv = value.chunk;
551 break;
552 default:
553 break;
554 }
555 }
556 enumerator->destroy(enumerator);
557
558 if (ike_sa)
559 {
560 if (ike_sa->get_version(ike_sa) == IKEV1)
561 {
562 if (iv.len)
563 {
564 keymat_v1_t *keymat;
565
566 keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
e185612d
MW
567 if (keymat->update_iv(keymat, 0, iv))
568 {
569 keymat->confirm_iv(keymat, 0);
570 }
c8531b7e
MW
571 }
572 }
573 this->cache->cache(this->cache, ike_sa, message);
574 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
575 }
576 else
577 {
578 message->destroy(message);
579 }
580}
581
765935c8
MW
582/**
583 * Process messages of type IKE_DELETE
584 */
d8748966
MW
585static void process_ike_delete(private_ha_dispatcher_t *this,
586 ha_message_t *message)
765935c8 587{
d8748966
MW
588 ha_message_attribute_t attribute;
589 ha_message_value_t value;
765935c8 590 enumerator_t *enumerator;
aa334daa 591 ike_sa_t *ike_sa = NULL;
765935c8
MW
592
593 enumerator = message->create_attribute_enumerator(message);
594 while (enumerator->enumerate(enumerator, &attribute, &value))
595 {
596 switch (attribute)
597 {
d8748966 598 case HA_IKE_ID:
34d240a6
MW
599 ike_sa = charon->ike_sa_manager->checkout(
600 charon->ike_sa_manager, value.ike_sa_id);
765935c8
MW
601 break;
602 default:
190edaf5
MW
603 break;
604 }
605 }
606 enumerator->destroy(enumerator);
aa334daa
MW
607 if (ike_sa)
608 {
609 this->cache->cache(this->cache, ike_sa, message);
610 charon->ike_sa_manager->checkin_and_destroy(
611 charon->ike_sa_manager, ike_sa);
612 }
613 else
614 {
615 message->destroy(message);
616 }
190edaf5
MW
617}
618
c94fe198 619/**
34d240a6 620 * Lookup a child cfg from the peer cfg by name
c94fe198 621 */
34d240a6 622static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
c94fe198
MW
623{
624 peer_cfg_t *peer_cfg;
625 child_cfg_t *current, *found = NULL;
626 enumerator_t *enumerator;
627
34d240a6 628 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
c94fe198
MW
629 if (peer_cfg)
630 {
631 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
632 while (enumerator->enumerate(enumerator, &current))
633 {
634 if (streq(current->get_name(current), name))
635 {
636 found = current;
c94fe198
MW
637 break;
638 }
639 }
640 enumerator->destroy(enumerator);
c94fe198
MW
641 }
642 return found;
643}
644
7999be5b
MW
645/**
646 * Process messages of type CHILD_ADD
647 */
d8748966
MW
648static void process_child_add(private_ha_dispatcher_t *this,
649 ha_message_t *message)
7999be5b 650{
d8748966
MW
651 ha_message_attribute_t attribute;
652 ha_message_value_t value;
c94fe198
MW
653 enumerator_t *enumerator;
654 ike_sa_t *ike_sa = NULL;
14041845 655 char *config_name = "";
c94fe198
MW
656 child_cfg_t *config = NULL;
657 child_sa_t *child_sa;
658 proposal_t *proposal;
6bc6f67b 659 bool initiator = FALSE, failed = FALSE, ok = FALSE;
b12c53ce
AS
660 uint32_t inbound_spi = 0, outbound_spi = 0;
661 uint16_t inbound_cpi = 0, outbound_cpi = 0;
662 uint8_t mode = MODE_TUNNEL, ipcomp = 0;
663 uint16_t encr = 0, integ = 0, len = 0, dh_grp = 0;
664 uint16_t esn = NO_EXT_SEQ_NUMBERS;
08e266a1 665 u_int seg_i, seg_o;
c94fe198
MW
666 chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
667 chunk_t encr_i, integ_i, encr_r, integ_r;
668 linked_list_t *local_ts, *remote_ts;
8bcd9bd1 669 diffie_hellman_t *dh = NULL;
c94fe198
MW
670
671 enumerator = message->create_attribute_enumerator(message);
672 while (enumerator->enumerate(enumerator, &attribute, &value))
673 {
674 switch (attribute)
675 {
d8748966 676 case HA_IKE_ID:
34d240a6
MW
677 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
678 value.ike_sa_id);
c94fe198 679 break;
d8748966 680 case HA_CONFIG_NAME:
34d240a6 681 config_name = value.str;
c94fe198 682 break;
3e6736f6
MW
683 case HA_INITIATOR:
684 initiator = value.u8;
685 break;
d8748966 686 case HA_INBOUND_SPI:
c94fe198
MW
687 inbound_spi = value.u32;
688 break;
d8748966 689 case HA_OUTBOUND_SPI:
c94fe198
MW
690 outbound_spi = value.u32;
691 break;
d8748966 692 case HA_INBOUND_CPI:
c94fe198
MW
693 inbound_cpi = value.u32;
694 break;
d8748966 695 case HA_OUTBOUND_CPI:
c94fe198
MW
696 outbound_cpi = value.u32;
697 break;
d8748966 698 case HA_IPSEC_MODE:
c94fe198
MW
699 mode = value.u8;
700 break;
d8748966 701 case HA_IPCOMP:
c94fe198
MW
702 ipcomp = value.u8;
703 break;
d8748966 704 case HA_ALG_ENCR:
c94fe198
MW
705 encr = value.u16;
706 break;
d8748966 707 case HA_ALG_ENCR_LEN:
c94fe198
MW
708 len = value.u16;
709 break;
d8748966 710 case HA_ALG_INTEG:
c94fe198
MW
711 integ = value.u16;
712 break;
b5c2ed50
TB
713 case HA_ALG_DH:
714 dh_grp = value.u16;
715 break;
98788537
MW
716 case HA_ESN:
717 esn = value.u16;
718 break;
d8748966 719 case HA_NONCE_I:
c94fe198
MW
720 nonce_i = value.chunk;
721 break;
d8748966 722 case HA_NONCE_R:
c94fe198
MW
723 nonce_r = value.chunk;
724 break;
d8748966 725 case HA_SECRET:
c94fe198
MW
726 secret = value.chunk;
727 break;
728 default:
729 break;
730 }
731 }
732 enumerator->destroy(enumerator);
733
34d240a6 734 if (!ike_sa)
c94fe198 735 {
d8748966 736 DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
aa334daa 737 message->destroy(message);
c94fe198
MW
738 return;
739 }
34d240a6
MW
740 config = find_child_cfg(ike_sa, config_name);
741 if (!config)
c94fe198 742 {
d8748966 743 DBG1(DBG_CHD, "HA is missing nodes child configuration");
34d240a6 744 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
aa334daa 745 message->destroy(message);
c94fe198
MW
746 return;
747 }
34d240a6 748
fafa7698
TB
749 child_sa_create_t data = {
750 .encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY),
751 };
c94fe198 752 child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
fafa7698 753 ike_sa->get_other_host(ike_sa), config, &data);
c94fe198
MW
754 child_sa->set_mode(child_sa, mode);
755 child_sa->set_protocol(child_sa, PROTO_ESP);
756 child_sa->set_ipcomp(child_sa, ipcomp);
757
bb162175 758 proposal = proposal_create(PROTO_ESP, 0);
c94fe198
MW
759 if (integ)
760 {
761 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
762 }
763 if (encr)
764 {
765 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
766 }
b5c2ed50
TB
767 if (dh_grp)
768 {
769 proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
770 }
98788537 771 proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
8bcd9bd1
MW
772 if (secret.len)
773 {
774 dh = ha_diffie_hellman_create(secret, chunk_empty);
775 }
6bc6f67b
MW
776 if (ike_sa->get_version(ike_sa) == IKEV2)
777 {
778 keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
c94fe198 779
8bcd9bd1
MW
780 ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
781 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
782 }
783 if (ike_sa->get_version(ike_sa) == IKEV1)
784 {
785 keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
b12c53ce 786 uint32_t spi_i, spi_r;
8bcd9bd1
MW
787
788 spi_i = initiator ? inbound_spi : outbound_spi;
789 spi_r = initiator ? outbound_spi : inbound_spi;
c94fe198 790
8bcd9bd1
MW
791 ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
792 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
6bc6f67b 793 }
8bcd9bd1 794 DESTROY_IF(dh);
6bc6f67b 795 if (!ok)
c94fe198 796 {
d8748966 797 DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
c94fe198
MW
798 child_sa->destroy(child_sa);
799 proposal->destroy(proposal);
34d240a6 800 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
c94fe198
MW
801 return;
802 }
803 child_sa->set_proposal(child_sa, proposal);
804 child_sa->set_state(child_sa, CHILD_INSTALLING);
805 proposal->destroy(proposal);
7999be5b 806
14041845
MW
807 /* TODO: Change CHILD_SA API to avoid cloning twice */
808 local_ts = linked_list_create();
809 remote_ts = linked_list_create();
810 enumerator = message->create_attribute_enumerator(message);
811 while (enumerator->enumerate(enumerator, &attribute, &value))
812 {
813 switch (attribute)
814 {
815 case HA_LOCAL_TS:
816 local_ts->insert_last(local_ts, value.ts->clone(value.ts));
817 break;
818 case HA_REMOTE_TS:
819 remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
820 break;
821 default:
822 break;
823 }
824 }
825 enumerator->destroy(enumerator);
826
4989aba8
TB
827 child_sa->set_policies(child_sa, local_ts, remote_ts);
828
c94fe198
MW
829 if (initiator)
830 {
14041845 831 if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
4989aba8 832 inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
14041845 833 child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
4989aba8 834 outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
c94fe198
MW
835 {
836 failed = TRUE;
837 }
838 }
839 else
840 {
14041845 841 if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
4989aba8 842 inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
14041845 843 child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
4989aba8 844 outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
c94fe198
MW
845 {
846 failed = TRUE;
847 }
848 }
849 chunk_clear(&encr_i);
850 chunk_clear(&integ_i);
851 chunk_clear(&encr_r);
852 chunk_clear(&integ_r);
853
854 if (failed)
855 {
d8748966 856 DBG1(DBG_CHD, "HA CHILD_SA installation failed");
c94fe198 857 child_sa->destroy(child_sa);
14041845
MW
858 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
859 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
34d240a6 860 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
aa334daa 861 message->destroy(message);
c94fe198
MW
862 return;
863 }
864
08e266a1
MW
865 seg_i = this->kernel->get_segment_spi(this->kernel,
866 ike_sa->get_my_host(ike_sa), inbound_spi);
867 seg_o = this->kernel->get_segment_spi(this->kernel,
868 ike_sa->get_other_host(ike_sa), outbound_spi);
869
ebeb8c87 870 DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
08e266a1 871 "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
246c969d 872 child_sa->get_unique_id(child_sa), local_ts, remote_ts,
08e266a1
MW
873 seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
874 seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
4989aba8 875 child_sa->install_policies(child_sa);
c94fe198
MW
876 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
877 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
878
879 child_sa->set_state(child_sa, CHILD_INSTALLED);
880 ike_sa->add_child_sa(ike_sa, child_sa);
aa334daa 881 message->destroy(message);
34d240a6 882 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
7999be5b
MW
883}
884
885/**
886 * Process messages of type CHILD_DELETE
887 */
d8748966
MW
888static void process_child_delete(private_ha_dispatcher_t *this,
889 ha_message_t *message)
7999be5b 890{
d8748966
MW
891 ha_message_attribute_t attribute;
892 ha_message_value_t value;
c94fe198
MW
893 enumerator_t *enumerator;
894 ike_sa_t *ike_sa = NULL;
aa334daa 895 child_sa_t *child_sa;
b12c53ce 896 uint32_t spi = 0;
7999be5b 897
c94fe198
MW
898 enumerator = message->create_attribute_enumerator(message);
899 while (enumerator->enumerate(enumerator, &attribute, &value))
900 {
901 switch (attribute)
902 {
d8748966 903 case HA_IKE_ID:
34d240a6
MW
904 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
905 value.ike_sa_id);
c94fe198 906 break;
d8748966 907 case HA_INBOUND_SPI:
aa334daa 908 spi = value.u32;
c94fe198
MW
909 break;
910 default:
911 break;
912 }
c94fe198 913 }
aa334daa
MW
914 enumerator->destroy(enumerator);
915
34d240a6
MW
916 if (ike_sa)
917 {
aa334daa
MW
918 child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
919 if (child_sa)
920 {
921 ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
922 }
34d240a6
MW
923 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
924 }
aa334daa 925 message->destroy(message);
7999be5b
MW
926}
927
37459ea9
MW
928/**
929 * Process messages of type SEGMENT_TAKE/DROP
930 */
d8748966
MW
931static void process_segment(private_ha_dispatcher_t *this,
932 ha_message_t *message, bool take)
37459ea9 933{
d8748966
MW
934 ha_message_attribute_t attribute;
935 ha_message_value_t value;
37459ea9
MW
936 enumerator_t *enumerator;
937
938 enumerator = message->create_attribute_enumerator(message);
939 while (enumerator->enumerate(enumerator, &attribute, &value))
940 {
941 switch (attribute)
942 {
d8748966 943 case HA_SEGMENT:
37459ea9
MW
944 if (take)
945 {
1466af85 946 DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
37459ea9
MW
947 this->segments->deactivate(this->segments, value.u16, FALSE);
948 }
949 else
950 {
1466af85 951 DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
37459ea9
MW
952 this->segments->activate(this->segments, value.u16, FALSE);
953 }
954 break;
955 default:
956 break;
957 }
958 }
959 enumerator->destroy(enumerator);
aa334daa 960 message->destroy(message);
37459ea9
MW
961}
962
3912fdb1
MW
963/**
964 * Process messages of type STATUS
965 */
d8748966
MW
966static void process_status(private_ha_dispatcher_t *this,
967 ha_message_t *message)
3912fdb1 968{
d8748966
MW
969 ha_message_attribute_t attribute;
970 ha_message_value_t value;
3912fdb1
MW
971 enumerator_t *enumerator;
972 segment_mask_t mask = 0;
973
974 enumerator = message->create_attribute_enumerator(message);
975 while (enumerator->enumerate(enumerator, &attribute, &value))
976 {
977 switch (attribute)
978 {
d8748966 979 case HA_SEGMENT:
3912fdb1
MW
980 mask |= SEGMENTS_BIT(value.u16);
981 break;
982 default:
983 break;
984 }
985 }
986 enumerator->destroy(enumerator);
987
988 this->segments->handle_status(this->segments, mask);
aa334daa 989 message->destroy(message);
3912fdb1
MW
990}
991
c866a427
MW
992/**
993 * Process messages of type RESYNC
994 */
995static void process_resync(private_ha_dispatcher_t *this,
996 ha_message_t *message)
997{
998 ha_message_attribute_t attribute;
999 ha_message_value_t value;
1000 enumerator_t *enumerator;
1001
1002 enumerator = message->create_attribute_enumerator(message);
1003 while (enumerator->enumerate(enumerator, &attribute, &value))
1004 {
1005 switch (attribute)
1006 {
1007 case HA_SEGMENT:
aa334daa 1008 this->cache->resync(this->cache, value.u16);
c866a427
MW
1009 break;
1010 default:
1011 break;
1012 }
1013 }
1014 enumerator->destroy(enumerator);
aa334daa 1015 message->destroy(message);
c866a427
MW
1016}
1017
190edaf5
MW
1018/**
1019 * Dispatcher job function
1020 */
d8748966 1021static job_requeue_t dispatch(private_ha_dispatcher_t *this)
190edaf5 1022{
d8748966 1023 ha_message_t *message;
2031002d 1024 ha_message_type_t type;
190edaf5
MW
1025
1026 message = this->socket->pull(this->socket);
2031002d
MW
1027 type = message->get_type(message);
1028 if (type != HA_STATUS)
1029 {
1030 DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
1031 message->get_type(message));
1032 }
1033 switch (type)
190edaf5 1034 {
d8748966 1035 case HA_IKE_ADD:
190edaf5
MW
1036 process_ike_add(this, message);
1037 break;
d8748966 1038 case HA_IKE_UPDATE:
765935c8 1039 process_ike_update(this, message);
190edaf5 1040 break;
ad2488fc
MW
1041 case HA_IKE_MID_INITIATOR:
1042 process_ike_mid(this, message, TRUE);
1043 break;
1044 case HA_IKE_MID_RESPONDER:
1045 process_ike_mid(this, message, FALSE);
1046 break;
c8531b7e
MW
1047 case HA_IKE_IV:
1048 process_ike_iv(this, message);
1049 break;
d8748966 1050 case HA_IKE_DELETE:
765935c8 1051 process_ike_delete(this, message);
190edaf5 1052 break;
d8748966 1053 case HA_CHILD_ADD:
7999be5b 1054 process_child_add(this, message);
190edaf5 1055 break;
d8748966 1056 case HA_CHILD_DELETE:
7999be5b 1057 process_child_delete(this, message);
190edaf5 1058 break;
d8748966 1059 case HA_SEGMENT_DROP:
37459ea9
MW
1060 process_segment(this, message, FALSE);
1061 break;
d8748966 1062 case HA_SEGMENT_TAKE:
37459ea9
MW
1063 process_segment(this, message, TRUE);
1064 break;
d8748966 1065 case HA_STATUS:
3912fdb1
MW
1066 process_status(this, message);
1067 break;
c866a427
MW
1068 case HA_RESYNC:
1069 process_resync(this, message);
1070 break;
190edaf5 1071 default:
2031002d 1072 DBG1(DBG_CFG, "received unknown HA message type %d", type);
aa334daa 1073 message->destroy(message);
190edaf5
MW
1074 break;
1075 }
190edaf5
MW
1076 return JOB_REQUEUE_DIRECT;
1077}
1078
00c1bd06
MW
1079METHOD(ha_dispatcher_t, destroy, void,
1080 private_ha_dispatcher_t *this)
190edaf5 1081{
190edaf5
MW
1082 free(this);
1083}
1084
1085/**
1086 * See header
1087 */
d8748966 1088ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
98d03438
MW
1089 ha_segments_t *segments, ha_cache_t *cache,
1090 ha_kernel_t *kernel, ha_attribute_t *attr)
190edaf5 1091{
00c1bd06 1092 private_ha_dispatcher_t *this;
190edaf5 1093
190edaf5 1094
00c1bd06
MW
1095 INIT(this,
1096 .public = {
1097 .destroy = _destroy,
1098 },
1099 .socket = socket,
1100 .segments = segments,
aa334daa 1101 .cache = cache,
08e266a1 1102 .kernel = kernel,
98d03438 1103 .attr = attr,
00c1bd06 1104 );
26d77eb3
TB
1105 lib->processor->queue_job(lib->processor,
1106 (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
1107 NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
190edaf5
MW
1108
1109 return &this->public;
1110}