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