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