Do not enable/disable our own sync tunnel
[strongswan.git] / src / charon / plugins / ha_sync / ha_sync_segments.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_segments.h"
17
18 #include <utils/mutex.h>
19 #include <utils/linked_list.h>
20
21 typedef struct private_ha_sync_segments_t private_ha_sync_segments_t;
22
23 /**
24 * Private data of an ha_sync_segments_t object.
25 */
26 struct private_ha_sync_segments_t {
27
28 /**
29 * Public ha_sync_segments_t interface.
30 */
31 ha_sync_segments_t public;
32
33 /**
34 * communication socket
35 */
36 ha_sync_socket_t *socket;
37
38 /**
39 * Sync tunnel, if any
40 */
41 ha_sync_tunnel_t *tunnel;
42
43 /**
44 * Interface to control segments at kernel level
45 */
46 ha_sync_kernel_t *kernel;
47
48 /**
49 * read/write lock for segment manipulation
50 */
51 rwlock_t *lock;
52
53 /**
54 * Total number of ClusterIP segments
55 */
56 u_int segment_count;
57
58 /**
59 * mask of active segments
60 */
61 segment_mask_t active;
62 };
63
64 /**
65 * Log currently active segments
66 */
67 static void log_segments(private_ha_sync_segments_t *this, bool activated,
68 u_int segment)
69 {
70 char buf[64] = "none", *pos = buf;
71 int i;
72 bool first = TRUE;
73
74 for (i = 0; i < this->segment_count; i++)
75 {
76 if (this->active & 0x01 << i)
77 {
78 if (first)
79 {
80 first = FALSE;
81 }
82 else
83 {
84 pos += snprintf(pos, buf + sizeof(buf) - pos, ",");
85 }
86 pos += snprintf(pos, buf + sizeof(buf) - pos, "%d", i+1);
87 }
88 }
89 DBG1(DBG_CFG, "HA sync segment %d %sactivated, now active: %s",
90 segment, activated ? "" : "de", buf);
91 }
92
93 /**
94 * Enable/Disable an an IKE_SA.
95 */
96 static void enable_disable(private_ha_sync_segments_t *this, u_int segment,
97 ike_sa_state_t old, ike_sa_state_t new, bool enable)
98 {
99 ike_sa_t *ike_sa;
100 enumerator_t *enumerator;
101 u_int i, limit;
102
103 this->lock->write_lock(this->lock);
104
105 if (segment == 0 || segment <= this->segment_count)
106 {
107 if (segment)
108 { /* loop once for single segment ... */
109 limit = segment + 1;
110 }
111 else
112 { /* or segment_count times for all segments */
113 limit = this->segment_count;
114 }
115 enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
116 while (enumerator->enumerate(enumerator, &ike_sa))
117 {
118 if (ike_sa->get_state(ike_sa) != old)
119 {
120 continue;
121 }
122 if (this->tunnel && this->tunnel->is_sync_sa(this->tunnel, ike_sa))
123 {
124 continue;
125 }
126 for (i = segment; i < limit; i++)
127 {
128 if (this->kernel->in_segment(this->kernel,
129 ike_sa->get_other_host(ike_sa), i))
130 {
131 ike_sa->set_state(ike_sa, new);
132 }
133 }
134 }
135 enumerator->destroy(enumerator);
136 for (i = segment; i < limit; i++)
137 {
138 if (enable)
139 {
140 if (!(this->active & SEGMENTS_BIT(i)))
141 {
142 this->active |= SEGMENTS_BIT(i);
143 this->kernel->activate(this->kernel, i);
144 }
145 }
146 else
147 {
148 if (this->active & SEGMENTS_BIT(i))
149 {
150 this->active &= ~SEGMENTS_BIT(i);
151 this->kernel->deactivate(this->kernel, i);
152 }
153 }
154 }
155
156 log_segments(this, enable, segment);
157 }
158
159 this->lock->unlock(this->lock);
160 }
161
162 /**
163 * Implementation of ha_sync_segments_t.activate
164 */
165 static void activate(private_ha_sync_segments_t *this, u_int segment,
166 bool notify)
167 {
168 ha_sync_message_t *message;
169
170 enable_disable(this, segment, IKE_PASSIVE, IKE_ESTABLISHED, TRUE);
171
172 if (notify)
173 {
174 message = ha_sync_message_create(HA_SYNC_SEGMENT_TAKE);
175 message->add_attribute(message, HA_SYNC_SEGMENT, segment);
176 this->socket->push(this->socket, message);
177 }
178 }
179
180 /**
181 * Implementation of ha_sync_segments_t.deactivate
182 */
183 static void deactivate(private_ha_sync_segments_t *this, u_int segment,
184 bool notify)
185 {
186 ha_sync_message_t *message;
187
188 enable_disable(this, segment, IKE_ESTABLISHED, IKE_PASSIVE, FALSE);
189
190 if (notify)
191 {
192 message = ha_sync_message_create(HA_SYNC_SEGMENT_DROP);
193 message->add_attribute(message, HA_SYNC_SEGMENT, segment);
194 this->socket->push(this->socket, message);
195 }
196 }
197
198 /**
199 * Rekey all children of an IKE_SA
200 */
201 static status_t rekey_children(ike_sa_t *ike_sa)
202 {
203 iterator_t *iterator;
204 child_sa_t *child_sa;
205 status_t status = SUCCESS;
206
207 iterator = ike_sa->create_child_sa_iterator(ike_sa);
208 while (iterator->iterate(iterator, (void**)&child_sa))
209 {
210 DBG1(DBG_CFG, "resyncing CHILD_SA");
211 status = ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
212 child_sa->get_spi(child_sa, TRUE));
213 if (status == DESTROY_ME)
214 {
215 break;
216 }
217 }
218 iterator->destroy(iterator);
219 return status;
220 }
221
222 /**
223 * Implementation of ha_sync_segments_t.resync
224 */
225 static void resync(private_ha_sync_segments_t *this, u_int segment)
226 {
227 ike_sa_t *ike_sa;
228 enumerator_t *enumerator;
229 linked_list_t *list;
230 ike_sa_id_t *id;
231 u_int16_t mask = SEGMENTS_BIT(segment);
232
233 list = linked_list_create();
234 this->lock->read_lock(this->lock);
235
236 if (segment > 0 && segment <= this->segment_count && (this->active & mask))
237 {
238 this->active &= ~mask;
239
240 DBG1(DBG_CFG, "resyncing HA sync segment %d", segment);
241
242 /* we do the actual rekeying in a seperate loop to avoid rekeying
243 * an SA twice. */
244 enumerator = charon->ike_sa_manager->create_enumerator(
245 charon->ike_sa_manager);
246 while (enumerator->enumerate(enumerator, &ike_sa))
247 {
248 if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
249 this->kernel->in_segment(this->kernel,
250 ike_sa->get_other_host(ike_sa), segment))
251 {
252 id = ike_sa->get_id(ike_sa);
253 list->insert_last(list, id->clone(id));
254 }
255 }
256 enumerator->destroy(enumerator);
257 }
258 this->lock->unlock(this->lock);
259
260 while (list->remove_last(list, (void**)&id) == SUCCESS)
261 {
262 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
263 id->destroy(id);
264 if (ike_sa)
265 {
266 DBG1(DBG_CFG, "resyncing IKE_SA");
267 if (ike_sa->rekey(ike_sa) != DESTROY_ME)
268 {
269 if (rekey_children(ike_sa) != DESTROY_ME)
270 {
271 charon->ike_sa_manager->checkin(
272 charon->ike_sa_manager, ike_sa);
273 continue;
274 }
275 }
276 charon->ike_sa_manager->checkin_and_destroy(
277 charon->ike_sa_manager, ike_sa);
278 }
279 }
280 list->destroy(list);
281 }
282
283 /**
284 * Implementation of listener_t.alert
285 */
286 static bool alert_hook(private_ha_sync_segments_t *this, ike_sa_t *ike_sa,
287 alert_t alert, va_list args)
288 {
289 if (alert == ALERT_SHUTDOWN_SIGNAL)
290 {
291 int i;
292
293 for (i = 0; i < SEGMENTS_MAX; i++)
294 {
295 if (this->active & SEGMENTS_BIT(i))
296 {
297 deactivate(this, i, TRUE);
298 }
299 }
300 }
301 return TRUE;
302 }
303
304 /**
305 * Implementation of ha_sync_segments_t.destroy.
306 */
307 static void destroy(private_ha_sync_segments_t *this)
308 {
309 this->lock->destroy(this->lock);
310 free(this);
311 }
312
313 /**
314 * See header
315 */
316 ha_sync_segments_t *ha_sync_segments_create(ha_sync_socket_t *socket,
317 ha_sync_kernel_t *kernel,
318 ha_sync_tunnel_t *tunnel,
319 u_int count, segment_mask_t active)
320 {
321 private_ha_sync_segments_t *this = malloc_thing(private_ha_sync_segments_t);
322
323 memset(&this->public.listener, 0, sizeof(listener_t));
324 this->public.listener.alert = (bool(*)(listener_t*, ike_sa_t *, alert_t, va_list))alert_hook;
325 this->public.activate = (void(*)(ha_sync_segments_t*, u_int segment,bool))activate;
326 this->public.deactivate = (void(*)(ha_sync_segments_t*, u_int segment,bool))deactivate;
327 this->public.resync = (void(*)(ha_sync_segments_t*, u_int segment))resync;
328 this->public.destroy = (void(*)(ha_sync_segments_t*))destroy;
329
330 this->socket = socket;
331 this->tunnel = tunnel;
332 this->kernel = kernel;
333 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
334 this->active = active;
335 this->segment_count = count;
336
337 return &this->public;
338 }
339