added HA resync option to (re-)integrate nodes to a cluster
[strongswan.git] / src / charon / plugins / ha_sync / ha_sync_ike.c
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.
14 *
15 * $Id$
16 */
17
18 #include "ha_sync_ike.h"
19
20 typedef struct private_ha_sync_ike_t private_ha_sync_ike_t;
21
22 /**
23 * Private data of an ha_sync_ike_t object.
24 */
25 struct private_ha_sync_ike_t {
26
27 /**
28 * Public ha_sync_ike_t interface.
29 */
30 ha_sync_ike_t public;
31
32 /**
33 * socket we use for syncing
34 */
35 ha_sync_socket_t *socket;
36 };
37
38 /**
39 * Return condition if it is set on ike_sa
40 */
41 static ike_condition_t copy_condition(ike_sa_t *ike_sa, ike_condition_t cond)
42 {
43 if (ike_sa->has_condition(ike_sa, cond))
44 {
45 return cond;
46 }
47 return 0;
48 }
49
50 /**
51 * Return extension if it is supported by peers IKE_SA
52 */
53 static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
54 {
55 if (ike_sa->supports_extension(ike_sa, ext))
56 {
57 return ext;
58 }
59 return 0;
60 }
61
62 /**
63 * Implementation of listener_t.ike_keys
64 */
65 static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
66 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
67 ike_sa_t *rekey)
68 {
69 ha_sync_message_t *m;
70 chunk_t secret;
71 proposal_t *proposal;
72 u_int16_t alg, len;
73
74 if (dh->get_shared_secret(dh, &secret) != SUCCESS)
75 {
76 return TRUE;
77 }
78
79 m = ha_sync_message_create(HA_SYNC_IKE_ADD);
80 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
81
82 if (rekey)
83 {
84 chunk_t skd;
85 keymat_t *keymat;
86
87 keymat = rekey->get_keymat(rekey);
88 m->add_attribute(m, HA_SYNC_IKE_REKEY_ID, rekey->get_id(rekey));
89 m->add_attribute(m, HA_SYNC_ALG_OLD_PRF, keymat->get_skd(keymat, &skd));
90 m->add_attribute(m, HA_SYNC_OLD_SKD, skd);
91 }
92
93 proposal = ike_sa->get_proposal(ike_sa);
94 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
95 {
96 m->add_attribute(m, HA_SYNC_ALG_ENCR, alg);
97 if (len)
98 {
99 m->add_attribute(m, HA_SYNC_ALG_ENCR_LEN, len);
100 }
101 }
102 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
103 {
104 m->add_attribute(m, HA_SYNC_ALG_INTEG, alg);
105 }
106 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
107 {
108 m->add_attribute(m, HA_SYNC_ALG_PRF, alg);
109 }
110 m->add_attribute(m, HA_SYNC_NONCE_I, nonce_i);
111 m->add_attribute(m, HA_SYNC_NONCE_R, nonce_r);
112 m->add_attribute(m, HA_SYNC_SECRET, secret);
113 chunk_clear(&secret);
114
115 this->socket->push(this->socket, m);
116 m->destroy(m);
117
118 return TRUE;
119 }
120
121 /**
122 * Implementation of listener_t.ike_state_change
123 */
124 static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
125 ike_sa_state_t state)
126 {
127 ha_sync_message_t *m;
128
129 if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
130 { /* only sync active IKE_SAs */
131 return TRUE;
132 }
133
134 switch (state)
135 {
136 case IKE_ESTABLISHED:
137 {
138 iterator_t *iterator;
139 peer_cfg_t *peer_cfg;
140 u_int32_t extension, condition;
141 host_t *addr;
142 identification_t *eap_id;
143 ike_sa_id_t *id;
144
145 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
146
147 condition = copy_condition(ike_sa, COND_NAT_ANY)
148 | copy_condition(ike_sa, COND_NAT_HERE)
149 | copy_condition(ike_sa, COND_NAT_THERE)
150 | copy_condition(ike_sa, COND_NAT_FAKE)
151 | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
152 | copy_condition(ike_sa, COND_CERTREQ_SEEN)
153 | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
154
155 extension = copy_extension(ike_sa, EXT_NATT)
156 | copy_extension(ike_sa, EXT_MOBIKE)
157 | copy_extension(ike_sa, EXT_HASH_AND_URL);
158
159 eap_id = ike_sa->get_eap_identity(ike_sa);
160 id = ike_sa->get_id(ike_sa);
161
162 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
163 m->add_attribute(m, HA_SYNC_IKE_ID, id);
164 m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
165 m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
166 m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
167 m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
168 m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
169 m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
170 m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
171 if (eap_id)
172 {
173 m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
174 }
175 iterator = ike_sa->create_additional_address_iterator(ike_sa);
176 while (iterator->iterate(iterator, (void**)&addr))
177 {
178 m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
179 }
180 iterator->destroy(iterator);
181 break;
182 }
183 case IKE_DESTROYING:
184 {
185 m = ha_sync_message_create(HA_SYNC_IKE_DELETE);
186 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
187 break;
188 }
189 default:
190 return TRUE;
191 }
192 this->socket->push(this->socket, m);
193 m->destroy(m);
194 return TRUE;
195 }
196
197 /**
198 * Implementation of listener_t.message
199 */
200 static bool message_hook(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
201 message_t *message, bool incoming)
202 {
203 if (message->get_exchange_type(message) != IKE_SA_INIT &&
204 message->get_request(message))
205 { /* we sync on requests, but skip it on IKE_SA_INIT */
206 ha_sync_message_t *m;
207 u_int32_t mid;
208
209 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
210 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
211 mid = message->get_message_id(message) + 1;
212 if (incoming)
213 {
214 m->add_attribute(m, HA_SYNC_RESPOND_MID, mid);
215 }
216 else
217 {
218 m->add_attribute(m, HA_SYNC_INITIATE_MID, mid);
219 }
220 this->socket->push(this->socket, m);
221 m->destroy(m);
222 }
223 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
224 message->get_exchange_type(message) == IKE_AUTH &&
225 !message->get_request(message))
226 { /* After IKE_SA has been established, sync peers virtual IP.
227 * We cannot sync it in the state_change hook, it is installed later.
228 * TODO: where to sync local VIP? */
229 ha_sync_message_t *m;
230 host_t *vip;
231
232 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
233 if (vip)
234 {
235 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
236 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
237 m->add_attribute(m, HA_SYNC_REMOTE_VIP, vip);
238 this->socket->push(this->socket, m);
239 m->destroy(m);
240 }
241 }
242 return TRUE;
243 }
244
245 /**
246 * Implementation of ha_sync_ike_t.destroy.
247 */
248 static void destroy(private_ha_sync_ike_t *this)
249 {
250 free(this);
251 }
252
253 /**
254 * See header
255 */
256 ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket)
257 {
258 private_ha_sync_ike_t *this = malloc_thing(private_ha_sync_ike_t);
259
260 memset(&this->public.listener, 0, sizeof(listener_t));
261 this->public.listener.ike_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh,chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys;
262 this->public.listener.ike_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, ike_sa_state_t state))ike_state_change;
263 this->public.listener.message = (bool(*)(listener_t*, ike_sa_t *, message_t *,bool))message_hook;
264 this->public.destroy = (void(*)(ha_sync_ike_t*))destroy;
265
266 this->socket = socket;
267
268 return &this->public;
269 }
270