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