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