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