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