b528a33dcee1c9a359217a3cfacaf540d20da662
[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 * Synced and cached SAs
39 */
40 ha_sync_cache_t *cache;
41 };
42
43 /**
44 * Return condition if it is set on ike_sa
45 */
46 static ike_condition_t copy_condition(ike_sa_t *ike_sa, ike_condition_t cond)
47 {
48 if (ike_sa->has_condition(ike_sa, cond))
49 {
50 return cond;
51 }
52 return 0;
53 }
54
55 /**
56 * Return extension if it is supported by peers IKE_SA
57 */
58 static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
59 {
60 if (ike_sa->supports_extension(ike_sa, ext))
61 {
62 return ext;
63 }
64 return 0;
65 }
66
67 /**
68 * Implementation of listener_t.ike_keys
69 */
70 static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
71 diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
72 ike_sa_t *rekey)
73 {
74 ha_sync_message_t *m;
75 chunk_t secret;
76 proposal_t *proposal;
77 u_int16_t alg, len;
78
79 if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
80 { /* IKE_SA is cached, do not sync */
81 return TRUE;
82 }
83
84 if (dh->get_shared_secret(dh, &secret) != SUCCESS)
85 {
86 return TRUE;
87 }
88
89 m = ha_sync_message_create(HA_SYNC_IKE_ADD);
90 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
91
92 if (rekey)
93 {
94 chunk_t skd;
95 keymat_t *keymat;
96
97 keymat = rekey->get_keymat(rekey);
98 m->add_attribute(m, HA_SYNC_IKE_REKEY_ID, rekey->get_id(rekey));
99 m->add_attribute(m, HA_SYNC_ALG_OLD_PRF, keymat->get_skd(keymat, &skd));
100 m->add_attribute(m, HA_SYNC_OLD_SKD, skd);
101 }
102
103 proposal = ike_sa->get_proposal(ike_sa);
104 if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
105 {
106 m->add_attribute(m, HA_SYNC_ALG_ENCR, alg);
107 if (len)
108 {
109 m->add_attribute(m, HA_SYNC_ALG_ENCR_LEN, len);
110 }
111 }
112 if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
113 {
114 m->add_attribute(m, HA_SYNC_ALG_INTEG, alg);
115 }
116 if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
117 {
118 m->add_attribute(m, HA_SYNC_ALG_PRF, alg);
119 }
120 m->add_attribute(m, HA_SYNC_NONCE_I, nonce_i);
121 m->add_attribute(m, HA_SYNC_NONCE_R, nonce_r);
122 m->add_attribute(m, HA_SYNC_SECRET, secret);
123 chunk_clear(&secret);
124
125 this->socket->push(this->socket, m);
126 m->destroy(m);
127
128 return TRUE;
129 }
130
131 /**
132 * Implementation of listener_t.ike_state_change
133 */
134 static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
135 ike_sa_state_t state)
136 {
137 ha_sync_message_t *m;
138
139 if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
140 { /* IKE_SA is cached, do not sync */
141 return TRUE;
142 }
143
144 switch (state)
145 {
146 case IKE_ESTABLISHED:
147 {
148 iterator_t *iterator;
149 peer_cfg_t *peer_cfg;
150 u_int32_t extension, condition;
151 host_t *local_vip, *remote_vip, *addr;
152 identification_t *eap_id;
153
154 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
155
156 condition = copy_condition(ike_sa, COND_NAT_ANY)
157 | copy_condition(ike_sa, COND_NAT_HERE)
158 | copy_condition(ike_sa, COND_NAT_THERE)
159 | copy_condition(ike_sa, COND_NAT_FAKE)
160 | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
161 | copy_condition(ike_sa, COND_CERTREQ_SEEN)
162 | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
163
164 extension = copy_extension(ike_sa, EXT_NATT)
165 | copy_extension(ike_sa, EXT_MOBIKE)
166 | copy_extension(ike_sa, EXT_HASH_AND_URL);
167
168 local_vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
169 remote_vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
170 eap_id = ike_sa->get_eap_identity(ike_sa);
171
172 m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
173 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
174 m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
175 m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
176 m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
177 m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
178 m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
179 m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
180 m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
181 if (local_vip)
182 {
183 m->add_attribute(m, HA_SYNC_LOCAL_VIP, local_vip);
184 }
185 if (remote_vip)
186 {
187 m->add_attribute(m, HA_SYNC_REMOTE_VIP, remote_vip);
188 }
189 if (eap_id)
190 {
191 m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
192 }
193 iterator = ike_sa->create_additional_address_iterator(ike_sa);
194 while (iterator->iterate(iterator, (void**)&addr))
195 {
196 m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
197 }
198 iterator->destroy(iterator);
199 break;
200 }
201 case IKE_DESTROYING:
202 {
203 m = ha_sync_message_create(HA_SYNC_IKE_DELETE);
204 m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
205 break;
206 }
207 default:
208 return TRUE;
209 }
210 this->socket->push(this->socket, m);
211 m->destroy(m);
212 return TRUE;
213 }
214
215 /**
216 * Implementation of ha_sync_ike_t.destroy.
217 */
218 static void destroy(private_ha_sync_ike_t *this)
219 {
220 free(this);
221 }
222
223 /**
224 * See header
225 */
226 ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket,
227 ha_sync_cache_t *cache)
228 {
229 private_ha_sync_ike_t *this = malloc_thing(private_ha_sync_ike_t);
230
231 memset(&this->public.listener, 0, sizeof(listener_t));
232 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;
233 this->public.listener.ike_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, ike_sa_state_t state))ike_state_change;
234 this->public.destroy = (void(*)(ha_sync_ike_t*))destroy;
235
236 this->socket = socket;
237 this->cache = cache;
238
239 return &this->public;
240 }
241