]>
Commit | Line | Data |
---|---|---|
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 | 21 | typedef 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 | 26 | struct 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 | */ | |
67 | static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret) | |
68 | { | |
69 | *secret = chunk_clone((*(chunk_t*)this->destroy)); | |
70 | return SUCCESS; | |
71 | } | |
72 | ||
190edaf5 MW |
73 | /** |
74 | * Process messages of type IKE_ADD | |
75 | */ | |
d8748966 | 76 | static 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 | */ | |
193 | static void set_condition(ike_sa_t *ike_sa, ike_condition_t set, | |
194 | ike_condition_t flag) | |
195 | { | |
196 | ike_sa->set_condition(ike_sa, flag, flag & set); | |
197 | } | |
198 | ||
199 | /** | |
200 | * Apply a extension flag to the IKE_SA if it is in set | |
201 | */ | |
202 | static void set_extension(ike_sa_t *ike_sa, ike_extension_t set, | |
203 | ike_extension_t flag) | |
204 | { | |
205 | if (flag & set) | |
206 | { | |
207 | ike_sa->enable_extension(ike_sa, flag); | |
208 | } | |
209 | } | |
210 | ||
211 | /** | |
212 | * Process messages of type IKE_UPDATE | |
213 | */ | |
d8748966 MW |
214 | static 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 | */ | |
349 | static 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 |
394 | static 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 | 431 | static 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, ¤t)) | |
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 |
457 | static 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 |
669 | static 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 |
712 | static 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 |
747 | static 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 | */ | |
776 | static 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 | 802 | static 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 |
857 | METHOD(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 | 867 | ha_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 |