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