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