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