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