ha: Add DH group to IKE_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;
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_ESN:
709 esn = value.u16;
710 break;
711 case HA_NONCE_I:
712 nonce_i = value.chunk;
713 break;
714 case HA_NONCE_R:
715 nonce_r = value.chunk;
716 break;
717 case HA_SECRET:
718 secret = value.chunk;
719 break;
720 default:
721 break;
722 }
723 }
724 enumerator->destroy(enumerator);
725
726 if (!ike_sa)
727 {
728 DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
729 message->destroy(message);
730 return;
731 }
732 config = find_child_cfg(ike_sa, config_name);
733 if (!config)
734 {
735 DBG1(DBG_CHD, "HA is missing nodes child configuration");
736 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
737 message->destroy(message);
738 return;
739 }
740
741 child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
742 ike_sa->get_other_host(ike_sa), config, 0,
743 ike_sa->has_condition(ike_sa, COND_NAT_ANY),
744 0, 0);
745 child_sa->set_mode(child_sa, mode);
746 child_sa->set_protocol(child_sa, PROTO_ESP);
747 child_sa->set_ipcomp(child_sa, ipcomp);
748
749 proposal = proposal_create(PROTO_ESP, 0);
750 if (integ)
751 {
752 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
753 }
754 if (encr)
755 {
756 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
757 }
758 proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
759 if (secret.len)
760 {
761 dh = ha_diffie_hellman_create(secret, chunk_empty);
762 }
763 if (ike_sa->get_version(ike_sa) == IKEV2)
764 {
765 keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
766
767 ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
768 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
769 }
770 if (ike_sa->get_version(ike_sa) == IKEV1)
771 {
772 keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
773 u_int32_t spi_i, spi_r;
774
775 spi_i = initiator ? inbound_spi : outbound_spi;
776 spi_r = initiator ? outbound_spi : inbound_spi;
777
778 ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
779 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
780 }
781 DESTROY_IF(dh);
782 if (!ok)
783 {
784 DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
785 child_sa->destroy(child_sa);
786 proposal->destroy(proposal);
787 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
788 return;
789 }
790 child_sa->set_proposal(child_sa, proposal);
791 child_sa->set_state(child_sa, CHILD_INSTALLING);
792 proposal->destroy(proposal);
793
794 /* TODO: Change CHILD_SA API to avoid cloning twice */
795 local_ts = linked_list_create();
796 remote_ts = linked_list_create();
797 enumerator = message->create_attribute_enumerator(message);
798 while (enumerator->enumerate(enumerator, &attribute, &value))
799 {
800 switch (attribute)
801 {
802 case HA_LOCAL_TS:
803 local_ts->insert_last(local_ts, value.ts->clone(value.ts));
804 break;
805 case HA_REMOTE_TS:
806 remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
807 break;
808 default:
809 break;
810 }
811 }
812 enumerator->destroy(enumerator);
813
814 if (initiator)
815 {
816 if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
817 inbound_cpi, initiator, TRUE, TRUE,
818 local_ts, remote_ts) != SUCCESS ||
819 child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
820 outbound_cpi, initiator, FALSE, TRUE,
821 local_ts, remote_ts) != SUCCESS)
822 {
823 failed = TRUE;
824 }
825 }
826 else
827 {
828 if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
829 inbound_cpi, initiator, TRUE, TRUE,
830 local_ts, remote_ts) != SUCCESS ||
831 child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
832 outbound_cpi, initiator, FALSE, TRUE,
833 local_ts, remote_ts) != SUCCESS)
834 {
835 failed = TRUE;
836 }
837 }
838 chunk_clear(&encr_i);
839 chunk_clear(&integ_i);
840 chunk_clear(&encr_r);
841 chunk_clear(&integ_r);
842
843 if (failed)
844 {
845 DBG1(DBG_CHD, "HA CHILD_SA installation failed");
846 child_sa->destroy(child_sa);
847 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
848 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
849 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
850 message->destroy(message);
851 return;
852 }
853
854 seg_i = this->kernel->get_segment_spi(this->kernel,
855 ike_sa->get_my_host(ike_sa), inbound_spi);
856 seg_o = this->kernel->get_segment_spi(this->kernel,
857 ike_sa->get_other_host(ike_sa), outbound_spi);
858
859 DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
860 "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
861 child_sa->get_unique_id(child_sa), local_ts, remote_ts,
862 seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
863 seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
864 child_sa->add_policies(child_sa, local_ts, remote_ts);
865 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
866 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
867
868 child_sa->set_state(child_sa, CHILD_INSTALLED);
869 ike_sa->add_child_sa(ike_sa, child_sa);
870 message->destroy(message);
871 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
872 }
873
874 /**
875 * Process messages of type CHILD_DELETE
876 */
877 static void process_child_delete(private_ha_dispatcher_t *this,
878 ha_message_t *message)
879 {
880 ha_message_attribute_t attribute;
881 ha_message_value_t value;
882 enumerator_t *enumerator;
883 ike_sa_t *ike_sa = NULL;
884 child_sa_t *child_sa;
885 u_int32_t spi = 0;
886
887 enumerator = message->create_attribute_enumerator(message);
888 while (enumerator->enumerate(enumerator, &attribute, &value))
889 {
890 switch (attribute)
891 {
892 case HA_IKE_ID:
893 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
894 value.ike_sa_id);
895 break;
896 case HA_INBOUND_SPI:
897 spi = value.u32;
898 break;
899 default:
900 break;
901 }
902 }
903 enumerator->destroy(enumerator);
904
905 if (ike_sa)
906 {
907 child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
908 if (child_sa)
909 {
910 ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
911 }
912 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
913 }
914 message->destroy(message);
915 }
916
917 /**
918 * Process messages of type SEGMENT_TAKE/DROP
919 */
920 static void process_segment(private_ha_dispatcher_t *this,
921 ha_message_t *message, bool take)
922 {
923 ha_message_attribute_t attribute;
924 ha_message_value_t value;
925 enumerator_t *enumerator;
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 if (take)
934 {
935 DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
936 this->segments->deactivate(this->segments, value.u16, FALSE);
937 }
938 else
939 {
940 DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
941 this->segments->activate(this->segments, value.u16, FALSE);
942 }
943 break;
944 default:
945 break;
946 }
947 }
948 enumerator->destroy(enumerator);
949 message->destroy(message);
950 }
951
952 /**
953 * Process messages of type STATUS
954 */
955 static void process_status(private_ha_dispatcher_t *this,
956 ha_message_t *message)
957 {
958 ha_message_attribute_t attribute;
959 ha_message_value_t value;
960 enumerator_t *enumerator;
961 segment_mask_t mask = 0;
962
963 enumerator = message->create_attribute_enumerator(message);
964 while (enumerator->enumerate(enumerator, &attribute, &value))
965 {
966 switch (attribute)
967 {
968 case HA_SEGMENT:
969 mask |= SEGMENTS_BIT(value.u16);
970 break;
971 default:
972 break;
973 }
974 }
975 enumerator->destroy(enumerator);
976
977 this->segments->handle_status(this->segments, mask);
978 message->destroy(message);
979 }
980
981 /**
982 * Process messages of type RESYNC
983 */
984 static void process_resync(private_ha_dispatcher_t *this,
985 ha_message_t *message)
986 {
987 ha_message_attribute_t attribute;
988 ha_message_value_t value;
989 enumerator_t *enumerator;
990
991 enumerator = message->create_attribute_enumerator(message);
992 while (enumerator->enumerate(enumerator, &attribute, &value))
993 {
994 switch (attribute)
995 {
996 case HA_SEGMENT:
997 this->cache->resync(this->cache, value.u16);
998 break;
999 default:
1000 break;
1001 }
1002 }
1003 enumerator->destroy(enumerator);
1004 message->destroy(message);
1005 }
1006
1007 /**
1008 * Dispatcher job function
1009 */
1010 static job_requeue_t dispatch(private_ha_dispatcher_t *this)
1011 {
1012 ha_message_t *message;
1013 ha_message_type_t type;
1014
1015 message = this->socket->pull(this->socket);
1016 type = message->get_type(message);
1017 if (type != HA_STATUS)
1018 {
1019 DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
1020 message->get_type(message));
1021 }
1022 switch (type)
1023 {
1024 case HA_IKE_ADD:
1025 process_ike_add(this, message);
1026 break;
1027 case HA_IKE_UPDATE:
1028 process_ike_update(this, message);
1029 break;
1030 case HA_IKE_MID_INITIATOR:
1031 process_ike_mid(this, message, TRUE);
1032 break;
1033 case HA_IKE_MID_RESPONDER:
1034 process_ike_mid(this, message, FALSE);
1035 break;
1036 case HA_IKE_IV:
1037 process_ike_iv(this, message);
1038 break;
1039 case HA_IKE_DELETE:
1040 process_ike_delete(this, message);
1041 break;
1042 case HA_CHILD_ADD:
1043 process_child_add(this, message);
1044 break;
1045 case HA_CHILD_DELETE:
1046 process_child_delete(this, message);
1047 break;
1048 case HA_SEGMENT_DROP:
1049 process_segment(this, message, FALSE);
1050 break;
1051 case HA_SEGMENT_TAKE:
1052 process_segment(this, message, TRUE);
1053 break;
1054 case HA_STATUS:
1055 process_status(this, message);
1056 break;
1057 case HA_RESYNC:
1058 process_resync(this, message);
1059 break;
1060 default:
1061 DBG1(DBG_CFG, "received unknown HA message type %d", type);
1062 message->destroy(message);
1063 break;
1064 }
1065 return JOB_REQUEUE_DIRECT;
1066 }
1067
1068 METHOD(ha_dispatcher_t, destroy, void,
1069 private_ha_dispatcher_t *this)
1070 {
1071 free(this);
1072 }
1073
1074 /**
1075 * See header
1076 */
1077 ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
1078 ha_segments_t *segments, ha_cache_t *cache,
1079 ha_kernel_t *kernel, ha_attribute_t *attr)
1080 {
1081 private_ha_dispatcher_t *this;
1082
1083
1084 INIT(this,
1085 .public = {
1086 .destroy = _destroy,
1087 },
1088 .socket = socket,
1089 .segments = segments,
1090 .cache = cache,
1091 .kernel = kernel,
1092 .attr = attr,
1093 );
1094 lib->processor->queue_job(lib->processor,
1095 (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
1096 NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
1097
1098 return &this->public;
1099 }