bee57067122af3a24d91ec5c8329bb41700851b2
[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 (dh->get_shared_secret(dh, &secret) != SUCCESS)
73 {
74 return TRUE;
75 }
76
77 m = ha_sync_message_create(HA_SYNC_IKE_ADD);
78 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
79
80 if (rekey)
81 {
82 chunk_t skd;
83 keymat_t *keymat;
84
85 keymat = rekey->get_keymat(rekey);
86 m->add_attribute(m, HA_SYNC_IKE_REKEY_ID, rekey->get_id(rekey));
87 m->add_attribute(m, HA_SYNC_ALG_OLD_PRF, keymat->get_skd(keymat, &skd));
88 m->add_attribute(m, HA_SYNC_OLD_SKD, skd);
89 }
90
91 proposal = ike_sa->get_proposal(ike_sa);
92 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
93 {
94 m->add_attribute(m, HA_SYNC_ALG_ENCR, alg);
95 if (len)
96 {
97 m->add_attribute(m, HA_SYNC_ALG_ENCR_LEN, len);
98 }
99 }
100 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
101 {
102 m->add_attribute(m, HA_SYNC_ALG_INTEG, alg);
103 }
104 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
105 {
106 m->add_attribute(m, HA_SYNC_ALG_PRF, alg);
107 }
108 m->add_attribute(m, HA_SYNC_NONCE_I, nonce_i);
109 m->add_attribute(m, HA_SYNC_NONCE_R, nonce_r);
110 m->add_attribute(m, HA_SYNC_SECRET, secret);
111 chunk_clear(&secret);
112
113 this->socket->push(this->socket, m);
114 m->destroy(m);
115
116 return TRUE;
117 }
118
119 /**
120 * Implementation of listener_t.ike_state_change
121 */
122 static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
123 ike_sa_state_t state)
124 {
125 ha_sync_message_t *m;
126
127 if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
128 { /* only sync active IKE_SAs */
129 return TRUE;
130 }
131
132 switch (state)
133 {
134 case IKE_ESTABLISHED:
135 {
136 iterator_t *iterator;
137 peer_cfg_t *peer_cfg;
138 u_int32_t extension, condition;
139 host_t *addr;
140 identification_t *eap_id;
141 ike_sa_id_t *id;
142
143 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
144
145 condition = copy_condition(ike_sa, COND_NAT_ANY)
146 | copy_condition(ike_sa, COND_NAT_HERE)
147 | copy_condition(ike_sa, COND_NAT_THERE)
148 | copy_condition(ike_sa, COND_NAT_FAKE)
149 | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
150 | copy_condition(ike_sa, COND_CERTREQ_SEEN)
151 | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
152
153 extension = copy_extension(ike_sa, EXT_NATT)
154 | copy_extension(ike_sa, EXT_MOBIKE)
155 | copy_extension(ike_sa, EXT_HASH_AND_URL);
156
157 eap_id = ike_sa->get_eap_identity(ike_sa);
158 id = ike_sa->get_id(ike_sa);
159
160 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
161 m->add_attribute(m, HA_SYNC_IKE_ID, id);
162 m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
163 m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
164 m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
165 m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
166 m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
167 m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
168 m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
169 if (eap_id)
170 {
171 m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
172 }
173 iterator = ike_sa->create_additional_address_iterator(ike_sa);
174 while (iterator->iterate(iterator, (void**)&addr))
175 {
176 m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
177 }
178 iterator->destroy(iterator);
179 break;
180 }
181 case IKE_DESTROYING:
182 {
183 m = ha_sync_message_create(HA_SYNC_IKE_DELETE);
184 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
185 break;
186 }
187 default:
188 return TRUE;
189 }
190 this->socket->push(this->socket, m);
191 m->destroy(m);
192 return TRUE;
193 }
194
195 /**
196 * Implementation of listener_t.message
197 */
198 static bool message_hook(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
199 message_t *message, bool incoming)
200 {
201 if (message->get_exchange_type(message) != IKE_SA_INIT &&
202 message->get_request(message))
203 { /* we sync on requests, but skip it on IKE_SA_INIT */
204 ha_sync_message_t *m;
205 u_int32_t mid;
206
207 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
208 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
209 mid = message->get_message_id(message) + 1;
210 if (incoming)
211 {
212 m->add_attribute(m, HA_SYNC_RESPOND_MID, mid);
213 }
214 else
215 {
216 m->add_attribute(m, HA_SYNC_INITIATE_MID, mid);
217 }
218 this->socket->push(this->socket, m);
219 m->destroy(m);
220 }
221 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
222 message->get_exchange_type(message) == IKE_AUTH &&
223 !message->get_request(message))
224 { /* After IKE_SA has been established, sync peers virtual IP.
225 * We cannot sync it in the state_change hook, it is installed later.
226 * TODO: where to sync local VIP? */
227 ha_sync_message_t *m;
228 host_t *vip;
229
230 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
231 if (vip)
232 {
233 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
234 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
235 m->add_attribute(m, HA_SYNC_REMOTE_VIP, vip);
236 this->socket->push(this->socket, m);
237 m->destroy(m);
238 }
239 }
240 return TRUE;
241 }
242
243 /**
244 * Implementation of ha_sync_ike_t.destroy.
245 */
246 static void destroy(private_ha_sync_ike_t *this)
247 {
248 free(this);
249 }
250
251 /**
252 * See header
253 */
254 ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket)
255 {
256 private_ha_sync_ike_t *this = malloc_thing(private_ha_sync_ike_t);
257
258 memset(&this->public.listener, 0, sizeof(listener_t));
259 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;
260 this->public.listener.ike_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, ike_sa_state_t state))ike_state_change;
261 this->public.listener.message = (bool(*)(listener_t*, ike_sa_t *, message_t *,bool))message_hook;
262 this->public.destroy = (void(*)(ha_sync_ike_t*))destroy;
263
264 this->socket = socket;
265
266 return &this->public;
267 }
268