]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libcharon/plugins/ha/ha_dispatcher.c
ha: Streamline handling of conditions and extensions
[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/**
d6879ef9 300 * Apply all set conditions to the IKE_SA
765935c8 301 */
d6879ef9 302static void set_conditions(ike_sa_t *ike_sa, ike_condition_t conditions)
765935c8 303{
d6879ef9
TE
304 ike_condition_t i;
305
306 for (i = 0; i < sizeof(i) * 8; ++i)
307 {
308 ike_condition_t cond = (1 << i);
309
310 ike_sa->set_condition(ike_sa, cond, (conditions & cond) != 0);
311 }
765935c8
MW
312}
313
314/**
d6879ef9 315 * Apply all enabled extensions to the IKE_SA
765935c8 316 */
d6879ef9 317static void set_extensions(ike_sa_t *ike_sa, ike_extension_t extensions)
765935c8 318{
d6879ef9
TE
319 ike_extension_t i;
320
321 for (i = 0; i < sizeof(i) * 8; ++i)
765935c8 322 {
d6879ef9
TE
323 ike_extension_t ext = (1 << i);
324
325 if (extensions & ext)
326 {
327 ike_sa->enable_extension(ike_sa, ext);
328 }
765935c8
MW
329 }
330}
331
332/**
333 * Process messages of type IKE_UPDATE
334 */
d8748966
MW
335static void process_ike_update(private_ha_dispatcher_t *this,
336 ha_message_t *message)
765935c8 337{
d8748966
MW
338 ha_message_attribute_t attribute;
339 ha_message_value_t value;
765935c8
MW
340 enumerator_t *enumerator;
341 ike_sa_t *ike_sa = NULL;
342 peer_cfg_t *peer_cfg = NULL;
fa4f71c8 343 auth_cfg_t *auth;
d2e8f20d 344 bool received_vip = FALSE, first_local_vip = TRUE, first_peer_addr = TRUE;
765935c8
MW
345
346 enumerator = message->create_attribute_enumerator(message);
347 while (enumerator->enumerate(enumerator, &attribute, &value))
348 {
d8748966 349 if (attribute != HA_IKE_ID && ike_sa == NULL)
765935c8 350 {
34d240a6 351 /* must be first attribute */
765935c8
MW
352 break;
353 }
354 switch (attribute)
355 {
d8748966 356 case HA_IKE_ID:
34d240a6
MW
357 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
358 value.ike_sa_id);
190edaf5 359 break;
d8748966 360 case HA_LOCAL_ID:
765935c8
MW
361 ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
362 break;
d8748966 363 case HA_REMOTE_ID:
765935c8
MW
364 ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
365 break;
fa4f71c8
MW
366 case HA_REMOTE_EAP_ID:
367 auth = auth_cfg_create();
368 auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
369 ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
370 break;
d8748966 371 case HA_LOCAL_ADDR:
765935c8
MW
372 ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
373 break;
d8748966 374 case HA_REMOTE_ADDR:
765935c8
MW
375 ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
376 break;
d8748966 377 case HA_LOCAL_VIP:
d2e8f20d
TB
378 if (first_local_vip)
379 {
380 ike_sa->clear_virtual_ips(ike_sa, TRUE);
381 first_local_vip = FALSE;
382 }
101d26ba 383 ike_sa->add_virtual_ip(ike_sa, TRUE, value.host);
80624c79 384 break;
d8748966 385 case HA_REMOTE_VIP:
d2e8f20d
TB
386 if (!received_vip)
387 {
388 ike_sa->clear_virtual_ips(ike_sa, FALSE);
389 }
101d26ba 390 ike_sa->add_virtual_ip(ike_sa, FALSE, value.host);
98d03438 391 received_vip = TRUE;
765935c8 392 break;
94bbc602 393 case HA_PEER_ADDR:
cd6b5bf8
TB
394 if (first_peer_addr)
395 {
396 ike_sa->clear_peer_addresses(ike_sa);
397 first_peer_addr = FALSE;
398 }
94bbc602 399 ike_sa->add_peer_address(ike_sa, value.host->clone(value.host));
190edaf5 400 break;
d8748966 401 case HA_CONFIG_NAME:
765935c8
MW
402 peer_cfg = charon->backends->get_peer_cfg_by_name(
403 charon->backends, value.str);
34d240a6
MW
404 if (peer_cfg)
405 {
406 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
407 peer_cfg->destroy(peer_cfg);
408 }
409 else
410 {
d8748966 411 DBG1(DBG_IKE, "HA is missing nodes peer configuration");
438318c6
MW
412 charon->ike_sa_manager->checkin_and_destroy(
413 charon->ike_sa_manager, ike_sa);
414 ike_sa = NULL;
34d240a6 415 }
190edaf5 416 break;
d8748966 417 case HA_EXTENSIONS:
d6879ef9 418 set_extensions(ike_sa, value.u32);
26d08a24 419 break;
d8748966 420 case HA_CONDITIONS:
d6879ef9 421 set_conditions(ike_sa, value.u32);
190edaf5 422 break;
765935c8
MW
423 default:
424 break;
425 }
426 }
427 enumerator->destroy(enumerator);
428
34d240a6 429 if (ike_sa)
765935c8 430 {
34d240a6
MW
431 if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
432 ike_sa->get_peer_cfg(ike_sa))
433 {
aa334daa
MW
434 DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
435 ike_sa->get_name(ike_sa),
436 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
437 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
34d240a6
MW
438 ike_sa->set_state(ike_sa, IKE_PASSIVE);
439 }
98d03438
MW
440 if (received_vip)
441 {
497ce2cf 442 enumerator_t *pools, *vips;
98d03438
MW
443 host_t *vip;
444 char *pool;
445
446 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
101d26ba 447 if (peer_cfg)
98d03438 448 {
497ce2cf
MW
449 pools = peer_cfg->create_pool_enumerator(peer_cfg);
450 while (pools->enumerate(pools, &pool))
98d03438 451 {
497ce2cf
MW
452 vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
453 while (vips->enumerate(vips, &vip))
101d26ba
MW
454 {
455 this->attr->reserve(this->attr, pool, vip);
456 }
497ce2cf 457 vips->destroy(vips);
98d03438 458 }
497ce2cf 459 pools->destroy(pools);
98d03438
MW
460 }
461 }
e1c7e1bc 462#ifdef USE_IKEV1
aa3b53e7
MW
463 if (ike_sa->get_version(ike_sa) == IKEV1)
464 {
465 lib->processor->queue_job(lib->processor, (job_t*)
466 adopt_children_job_create(ike_sa->get_id(ike_sa)));
467 }
e1c7e1bc 468#endif /* USE_IKEV1 */
aa334daa 469 this->cache->cache(this->cache, ike_sa, message);
34d240a6 470 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
765935c8 471 }
aa334daa
MW
472 else
473 {
474 DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
475 message->destroy(message);
476 }
765935c8
MW
477}
478
ad2488fc
MW
479/**
480 * Process messages of type IKE_MID_INITIATOR/RESPONDER
481 */
482static void process_ike_mid(private_ha_dispatcher_t *this,
483 ha_message_t *message, bool initiator)
484{
485 ha_message_attribute_t attribute;
486 ha_message_value_t value;
487 enumerator_t *enumerator;
488 ike_sa_t *ike_sa = NULL;
b12c53ce 489 uint32_t mid = 0;
ad2488fc
MW
490
491 enumerator = message->create_attribute_enumerator(message);
492 while (enumerator->enumerate(enumerator, &attribute, &value))
493 {
494 switch (attribute)
495 {
496 case HA_IKE_ID:
497 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
498 value.ike_sa_id);
499 break;
500 case HA_MID:
501 mid = value.u32;
502 break;
503 default:
504 break;
505 }
506 }
507 enumerator->destroy(enumerator);
508
509 if (ike_sa)
510 {
511 if (mid)
512 {
513 ike_sa->set_message_id(ike_sa, initiator, mid);
514 }
aa334daa 515 this->cache->cache(this->cache, ike_sa, message);
ad2488fc
MW
516 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
517 }
aa334daa
MW
518 else
519 {
520 message->destroy(message);
521 }
ad2488fc
MW
522}
523
c8531b7e
MW
524/**
525 * Process messages of type IKE_IV
526 */
527static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message)
528{
529 ha_message_attribute_t attribute;
530 ha_message_value_t value;
531 enumerator_t *enumerator;
532 ike_sa_t *ike_sa = NULL;
533 chunk_t iv = chunk_empty;
534
535 enumerator = message->create_attribute_enumerator(message);
536 while (enumerator->enumerate(enumerator, &attribute, &value))
537 {
538 switch (attribute)
539 {
540 case HA_IKE_ID:
541 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
542 value.ike_sa_id);
543 break;
544 case HA_IV:
545 iv = value.chunk;
546 break;
547 default:
548 break;
549 }
550 }
551 enumerator->destroy(enumerator);
552
553 if (ike_sa)
554 {
555 if (ike_sa->get_version(ike_sa) == IKEV1)
556 {
557 if (iv.len)
558 {
559 keymat_v1_t *keymat;
560
561 keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
e185612d
MW
562 if (keymat->update_iv(keymat, 0, iv))
563 {
564 keymat->confirm_iv(keymat, 0);
565 }
c8531b7e
MW
566 }
567 }
568 this->cache->cache(this->cache, ike_sa, message);
569 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
570 }
571 else
572 {
573 message->destroy(message);
574 }
575}
576
765935c8
MW
577/**
578 * Process messages of type IKE_DELETE
579 */
d8748966
MW
580static void process_ike_delete(private_ha_dispatcher_t *this,
581 ha_message_t *message)
765935c8 582{
d8748966
MW
583 ha_message_attribute_t attribute;
584 ha_message_value_t value;
765935c8 585 enumerator_t *enumerator;
aa334daa 586 ike_sa_t *ike_sa = NULL;
765935c8
MW
587
588 enumerator = message->create_attribute_enumerator(message);
589 while (enumerator->enumerate(enumerator, &attribute, &value))
590 {
591 switch (attribute)
592 {
d8748966 593 case HA_IKE_ID:
34d240a6
MW
594 ike_sa = charon->ike_sa_manager->checkout(
595 charon->ike_sa_manager, value.ike_sa_id);
765935c8
MW
596 break;
597 default:
190edaf5
MW
598 break;
599 }
600 }
601 enumerator->destroy(enumerator);
aa334daa
MW
602 if (ike_sa)
603 {
604 this->cache->cache(this->cache, ike_sa, message);
605 charon->ike_sa_manager->checkin_and_destroy(
606 charon->ike_sa_manager, ike_sa);
607 }
608 else
609 {
610 message->destroy(message);
611 }
190edaf5
MW
612}
613
c94fe198 614/**
34d240a6 615 * Lookup a child cfg from the peer cfg by name
c94fe198 616 */
34d240a6 617static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
c94fe198
MW
618{
619 peer_cfg_t *peer_cfg;
620 child_cfg_t *current, *found = NULL;
621 enumerator_t *enumerator;
622
34d240a6 623 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
c94fe198
MW
624 if (peer_cfg)
625 {
626 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
627 while (enumerator->enumerate(enumerator, &current))
628 {
629 if (streq(current->get_name(current), name))
630 {
631 found = current;
c94fe198
MW
632 break;
633 }
634 }
635 enumerator->destroy(enumerator);
c94fe198
MW
636 }
637 return found;
638}
639
7999be5b
MW
640/**
641 * Process messages of type CHILD_ADD
642 */
d8748966
MW
643static void process_child_add(private_ha_dispatcher_t *this,
644 ha_message_t *message)
7999be5b 645{
d8748966
MW
646 ha_message_attribute_t attribute;
647 ha_message_value_t value;
c94fe198
MW
648 enumerator_t *enumerator;
649 ike_sa_t *ike_sa = NULL;
14041845 650 char *config_name = "";
c94fe198
MW
651 child_cfg_t *config = NULL;
652 child_sa_t *child_sa;
653 proposal_t *proposal;
6bc6f67b 654 bool initiator = FALSE, failed = FALSE, ok = FALSE;
b12c53ce
AS
655 uint32_t inbound_spi = 0, outbound_spi = 0;
656 uint16_t inbound_cpi = 0, outbound_cpi = 0;
657 uint8_t mode = MODE_TUNNEL, ipcomp = 0;
658 uint16_t encr = 0, integ = 0, len = 0, dh_grp = 0;
659 uint16_t esn = NO_EXT_SEQ_NUMBERS;
08e266a1 660 u_int seg_i, seg_o;
c94fe198
MW
661 chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
662 chunk_t encr_i, integ_i, encr_r, integ_r;
663 linked_list_t *local_ts, *remote_ts;
8bcd9bd1 664 diffie_hellman_t *dh = NULL;
c94fe198
MW
665
666 enumerator = message->create_attribute_enumerator(message);
667 while (enumerator->enumerate(enumerator, &attribute, &value))
668 {
669 switch (attribute)
670 {
d8748966 671 case HA_IKE_ID:
34d240a6
MW
672 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
673 value.ike_sa_id);
c94fe198 674 break;
d8748966 675 case HA_CONFIG_NAME:
34d240a6 676 config_name = value.str;
c94fe198 677 break;
3e6736f6
MW
678 case HA_INITIATOR:
679 initiator = value.u8;
680 break;
d8748966 681 case HA_INBOUND_SPI:
c94fe198
MW
682 inbound_spi = value.u32;
683 break;
d8748966 684 case HA_OUTBOUND_SPI:
c94fe198
MW
685 outbound_spi = value.u32;
686 break;
d8748966 687 case HA_INBOUND_CPI:
c94fe198
MW
688 inbound_cpi = value.u32;
689 break;
d8748966 690 case HA_OUTBOUND_CPI:
c94fe198
MW
691 outbound_cpi = value.u32;
692 break;
d8748966 693 case HA_IPSEC_MODE:
c94fe198
MW
694 mode = value.u8;
695 break;
d8748966 696 case HA_IPCOMP:
c94fe198
MW
697 ipcomp = value.u8;
698 break;
d8748966 699 case HA_ALG_ENCR:
c94fe198
MW
700 encr = value.u16;
701 break;
d8748966 702 case HA_ALG_ENCR_LEN:
c94fe198
MW
703 len = value.u16;
704 break;
d8748966 705 case HA_ALG_INTEG:
c94fe198
MW
706 integ = value.u16;
707 break;
b5c2ed50
TB
708 case HA_ALG_DH:
709 dh_grp = value.u16;
710 break;
98788537
MW
711 case HA_ESN:
712 esn = value.u16;
713 break;
d8748966 714 case HA_NONCE_I:
c94fe198
MW
715 nonce_i = value.chunk;
716 break;
d8748966 717 case HA_NONCE_R:
c94fe198
MW
718 nonce_r = value.chunk;
719 break;
d8748966 720 case HA_SECRET:
c94fe198
MW
721 secret = value.chunk;
722 break;
723 default:
724 break;
725 }
726 }
727 enumerator->destroy(enumerator);
728
34d240a6 729 if (!ike_sa)
c94fe198 730 {
d8748966 731 DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
aa334daa 732 message->destroy(message);
c94fe198
MW
733 return;
734 }
34d240a6
MW
735 config = find_child_cfg(ike_sa, config_name);
736 if (!config)
c94fe198 737 {
d8748966 738 DBG1(DBG_CHD, "HA is missing nodes child configuration");
34d240a6 739 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
aa334daa 740 message->destroy(message);
c94fe198
MW
741 return;
742 }
34d240a6 743
fafa7698
TB
744 child_sa_create_t data = {
745 .encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY),
746 };
c94fe198 747 child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
fafa7698 748 ike_sa->get_other_host(ike_sa), config, &data);
c94fe198
MW
749 child_sa->set_mode(child_sa, mode);
750 child_sa->set_protocol(child_sa, PROTO_ESP);
751 child_sa->set_ipcomp(child_sa, ipcomp);
752
bb162175 753 proposal = proposal_create(PROTO_ESP, 0);
c94fe198
MW
754 if (integ)
755 {
756 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
757 }
758 if (encr)
759 {
760 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
761 }
b5c2ed50
TB
762 if (dh_grp)
763 {
764 proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
765 }
98788537 766 proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
8bcd9bd1
MW
767 if (secret.len)
768 {
769 dh = ha_diffie_hellman_create(secret, chunk_empty);
770 }
6bc6f67b
MW
771 if (ike_sa->get_version(ike_sa) == IKEV2)
772 {
773 keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
c94fe198 774
8bcd9bd1
MW
775 ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
776 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
777 }
778 if (ike_sa->get_version(ike_sa) == IKEV1)
779 {
780 keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
b12c53ce 781 uint32_t spi_i, spi_r;
8bcd9bd1
MW
782
783 spi_i = initiator ? inbound_spi : outbound_spi;
784 spi_r = initiator ? outbound_spi : inbound_spi;
c94fe198 785
8bcd9bd1
MW
786 ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
787 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
6bc6f67b 788 }
8bcd9bd1 789 DESTROY_IF(dh);
6bc6f67b 790 if (!ok)
c94fe198 791 {
d8748966 792 DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
c94fe198
MW
793 child_sa->destroy(child_sa);
794 proposal->destroy(proposal);
34d240a6 795 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
c94fe198
MW
796 return;
797 }
798 child_sa->set_proposal(child_sa, proposal);
799 child_sa->set_state(child_sa, CHILD_INSTALLING);
800 proposal->destroy(proposal);
7999be5b 801
14041845
MW
802 /* TODO: Change CHILD_SA API to avoid cloning twice */
803 local_ts = linked_list_create();
804 remote_ts = linked_list_create();
805 enumerator = message->create_attribute_enumerator(message);
806 while (enumerator->enumerate(enumerator, &attribute, &value))
807 {
808 switch (attribute)
809 {
810 case HA_LOCAL_TS:
811 local_ts->insert_last(local_ts, value.ts->clone(value.ts));
812 break;
813 case HA_REMOTE_TS:
814 remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
815 break;
816 default:
817 break;
818 }
819 }
820 enumerator->destroy(enumerator);
821
4989aba8
TB
822 child_sa->set_policies(child_sa, local_ts, remote_ts);
823
c94fe198
MW
824 if (initiator)
825 {
14041845 826 if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
4989aba8 827 inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
14041845 828 child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
4989aba8 829 outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
c94fe198
MW
830 {
831 failed = TRUE;
832 }
833 }
834 else
835 {
14041845 836 if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
4989aba8 837 inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
14041845 838 child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
4989aba8 839 outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
c94fe198
MW
840 {
841 failed = TRUE;
842 }
843 }
844 chunk_clear(&encr_i);
845 chunk_clear(&integ_i);
846 chunk_clear(&encr_r);
847 chunk_clear(&integ_r);
848
849 if (failed)
850 {
d8748966 851 DBG1(DBG_CHD, "HA CHILD_SA installation failed");
c94fe198 852 child_sa->destroy(child_sa);
14041845
MW
853 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
854 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
34d240a6 855 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
aa334daa 856 message->destroy(message);
c94fe198
MW
857 return;
858 }
859
08e266a1
MW
860 seg_i = this->kernel->get_segment_spi(this->kernel,
861 ike_sa->get_my_host(ike_sa), inbound_spi);
862 seg_o = this->kernel->get_segment_spi(this->kernel,
863 ike_sa->get_other_host(ike_sa), outbound_spi);
864
ebeb8c87 865 DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
08e266a1 866 "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
246c969d 867 child_sa->get_unique_id(child_sa), local_ts, remote_ts,
08e266a1
MW
868 seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
869 seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
4989aba8 870 child_sa->install_policies(child_sa);
c94fe198
MW
871 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
872 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
873
874 child_sa->set_state(child_sa, CHILD_INSTALLED);
875 ike_sa->add_child_sa(ike_sa, child_sa);
aa334daa 876 message->destroy(message);
34d240a6 877 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
7999be5b
MW
878}
879
880/**
881 * Process messages of type CHILD_DELETE
882 */
d8748966
MW
883static void process_child_delete(private_ha_dispatcher_t *this,
884 ha_message_t *message)
7999be5b 885{
d8748966
MW
886 ha_message_attribute_t attribute;
887 ha_message_value_t value;
c94fe198
MW
888 enumerator_t *enumerator;
889 ike_sa_t *ike_sa = NULL;
aa334daa 890 child_sa_t *child_sa;
b12c53ce 891 uint32_t spi = 0;
7999be5b 892
c94fe198
MW
893 enumerator = message->create_attribute_enumerator(message);
894 while (enumerator->enumerate(enumerator, &attribute, &value))
895 {
896 switch (attribute)
897 {
d8748966 898 case HA_IKE_ID:
34d240a6
MW
899 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
900 value.ike_sa_id);
c94fe198 901 break;
d8748966 902 case HA_INBOUND_SPI:
aa334daa 903 spi = value.u32;
c94fe198
MW
904 break;
905 default:
906 break;
907 }
c94fe198 908 }
aa334daa
MW
909 enumerator->destroy(enumerator);
910
34d240a6
MW
911 if (ike_sa)
912 {
aa334daa
MW
913 child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
914 if (child_sa)
915 {
916 ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
917 }
34d240a6
MW
918 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
919 }
aa334daa 920 message->destroy(message);
7999be5b
MW
921}
922
37459ea9
MW
923/**
924 * Process messages of type SEGMENT_TAKE/DROP
925 */
d8748966
MW
926static void process_segment(private_ha_dispatcher_t *this,
927 ha_message_t *message, bool take)
37459ea9 928{
d8748966
MW
929 ha_message_attribute_t attribute;
930 ha_message_value_t value;
37459ea9
MW
931 enumerator_t *enumerator;
932
933 enumerator = message->create_attribute_enumerator(message);
934 while (enumerator->enumerate(enumerator, &attribute, &value))
935 {
936 switch (attribute)
937 {
d8748966 938 case HA_SEGMENT:
37459ea9
MW
939 if (take)
940 {
1466af85 941 DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
37459ea9
MW
942 this->segments->deactivate(this->segments, value.u16, FALSE);
943 }
944 else
945 {
1466af85 946 DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
37459ea9
MW
947 this->segments->activate(this->segments, value.u16, FALSE);
948 }
949 break;
950 default:
951 break;
952 }
953 }
954 enumerator->destroy(enumerator);
aa334daa 955 message->destroy(message);
37459ea9
MW
956}
957
3912fdb1
MW
958/**
959 * Process messages of type STATUS
960 */
d8748966
MW
961static void process_status(private_ha_dispatcher_t *this,
962 ha_message_t *message)
3912fdb1 963{
d8748966
MW
964 ha_message_attribute_t attribute;
965 ha_message_value_t value;
3912fdb1
MW
966 enumerator_t *enumerator;
967 segment_mask_t mask = 0;
968
969 enumerator = message->create_attribute_enumerator(message);
970 while (enumerator->enumerate(enumerator, &attribute, &value))
971 {
972 switch (attribute)
973 {
d8748966 974 case HA_SEGMENT:
3912fdb1
MW
975 mask |= SEGMENTS_BIT(value.u16);
976 break;
977 default:
978 break;
979 }
980 }
981 enumerator->destroy(enumerator);
982
983 this->segments->handle_status(this->segments, mask);
aa334daa 984 message->destroy(message);
3912fdb1
MW
985}
986
c866a427
MW
987/**
988 * Process messages of type RESYNC
989 */
990static void process_resync(private_ha_dispatcher_t *this,
991 ha_message_t *message)
992{
993 ha_message_attribute_t attribute;
994 ha_message_value_t value;
995 enumerator_t *enumerator;
996
997 enumerator = message->create_attribute_enumerator(message);
998 while (enumerator->enumerate(enumerator, &attribute, &value))
999 {
1000 switch (attribute)
1001 {
1002 case HA_SEGMENT:
aa334daa 1003 this->cache->resync(this->cache, value.u16);
c866a427
MW
1004 break;
1005 default:
1006 break;
1007 }
1008 }
1009 enumerator->destroy(enumerator);
aa334daa 1010 message->destroy(message);
c866a427
MW
1011}
1012
190edaf5
MW
1013/**
1014 * Dispatcher job function
1015 */
d8748966 1016static job_requeue_t dispatch(private_ha_dispatcher_t *this)
190edaf5 1017{
d8748966 1018 ha_message_t *message;
2031002d 1019 ha_message_type_t type;
190edaf5
MW
1020
1021 message = this->socket->pull(this->socket);
2031002d
MW
1022 type = message->get_type(message);
1023 if (type != HA_STATUS)
1024 {
1025 DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
1026 message->get_type(message));
1027 }
1028 switch (type)
190edaf5 1029 {
d8748966 1030 case HA_IKE_ADD:
190edaf5
MW
1031 process_ike_add(this, message);
1032 break;
d8748966 1033 case HA_IKE_UPDATE:
765935c8 1034 process_ike_update(this, message);
190edaf5 1035 break;
ad2488fc
MW
1036 case HA_IKE_MID_INITIATOR:
1037 process_ike_mid(this, message, TRUE);
1038 break;
1039 case HA_IKE_MID_RESPONDER:
1040 process_ike_mid(this, message, FALSE);
1041 break;
c8531b7e
MW
1042 case HA_IKE_IV:
1043 process_ike_iv(this, message);
1044 break;
d8748966 1045 case HA_IKE_DELETE:
765935c8 1046 process_ike_delete(this, message);
190edaf5 1047 break;
d8748966 1048 case HA_CHILD_ADD:
7999be5b 1049 process_child_add(this, message);
190edaf5 1050 break;
d8748966 1051 case HA_CHILD_DELETE:
7999be5b 1052 process_child_delete(this, message);
190edaf5 1053 break;
d8748966 1054 case HA_SEGMENT_DROP:
37459ea9
MW
1055 process_segment(this, message, FALSE);
1056 break;
d8748966 1057 case HA_SEGMENT_TAKE:
37459ea9
MW
1058 process_segment(this, message, TRUE);
1059 break;
d8748966 1060 case HA_STATUS:
3912fdb1
MW
1061 process_status(this, message);
1062 break;
c866a427
MW
1063 case HA_RESYNC:
1064 process_resync(this, message);
1065 break;
190edaf5 1066 default:
2031002d 1067 DBG1(DBG_CFG, "received unknown HA message type %d", type);
aa334daa 1068 message->destroy(message);
190edaf5
MW
1069 break;
1070 }
190edaf5
MW
1071 return JOB_REQUEUE_DIRECT;
1072}
1073
00c1bd06
MW
1074METHOD(ha_dispatcher_t, destroy, void,
1075 private_ha_dispatcher_t *this)
190edaf5 1076{
190edaf5
MW
1077 free(this);
1078}
1079
1080/**
1081 * See header
1082 */
d8748966 1083ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
98d03438
MW
1084 ha_segments_t *segments, ha_cache_t *cache,
1085 ha_kernel_t *kernel, ha_attribute_t *attr)
190edaf5 1086{
00c1bd06 1087 private_ha_dispatcher_t *this;
190edaf5 1088
190edaf5 1089
00c1bd06
MW
1090 INIT(this,
1091 .public = {
1092 .destroy = _destroy,
1093 },
1094 .socket = socket,
1095 .segments = segments,
aa334daa 1096 .cache = cache,
08e266a1 1097 .kernel = kernel,
98d03438 1098 .attr = attr,
00c1bd06 1099 );
26d77eb3
TB
1100 lib->processor->queue_job(lib->processor,
1101 (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
1102 NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
190edaf5
MW
1103
1104 return &this->public;
1105}