removing svn keyword $Id$ from all files
[strongswan.git] / src / charon / plugins / stroke / stroke_control.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 "stroke_control.h"
17
18 #include <daemon.h>
19 #include <processing/jobs/delete_ike_sa_job.h>
20
21 typedef struct private_stroke_control_t private_stroke_control_t;
22
23 /**
24 * private data of stroke_control
25 */
26 struct private_stroke_control_t {
27
28 /**
29 * public functions
30 */
31 stroke_control_t public;
32 };
33
34
35 typedef struct stroke_log_info_t stroke_log_info_t;
36
37 /**
38 * helper struct to say what and where to log when using controller callback
39 */
40 struct stroke_log_info_t {
41
42 /**
43 * level to log up to
44 */
45 level_t level;
46
47 /**
48 * where to write log
49 */
50 FILE* out;
51 };
52
53 /**
54 * logging to the stroke interface
55 */
56 static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
57 ike_sa_t *ike_sa, char *format, va_list args)
58 {
59 if (level <= info->level)
60 {
61 if (vfprintf(info->out, format, args) < 0 ||
62 fprintf(info->out, "\n") < 0 ||
63 fflush(info->out) != 0)
64 {
65 return FALSE;
66 }
67 }
68 return TRUE;
69 }
70
71 /**
72 * get the child_cfg with the same name as the peer cfg
73 */
74 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
75 {
76 child_cfg_t *current, *found = NULL;
77 enumerator_t *enumerator;
78
79 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
80 while (enumerator->enumerate(enumerator, &current))
81 {
82 if (streq(current->get_name(current), name))
83 {
84 found = current;
85 found->get_ref(found);
86 break;
87 }
88 }
89 enumerator->destroy(enumerator);
90 return found;
91 }
92
93 /**
94 * Implementation of stroke_control_t.initiate.
95 */
96 static void initiate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
97 {
98 peer_cfg_t *peer_cfg;
99 child_cfg_t *child_cfg;
100 stroke_log_info_t info;
101
102 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
103 msg->initiate.name);
104 if (peer_cfg == NULL)
105 {
106 DBG1(DBG_CFG, "no config named '%s'\n", msg->initiate.name);
107 return;
108 }
109 if (peer_cfg->get_ike_version(peer_cfg) != 2)
110 {
111 DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config",
112 peer_cfg->get_ike_version(peer_cfg));
113 peer_cfg->destroy(peer_cfg);
114 return;
115 }
116
117 child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
118 if (child_cfg == NULL)
119 {
120 DBG1(DBG_CFG, "no child config named '%s'\n", msg->initiate.name);
121 peer_cfg->destroy(peer_cfg);
122 return;
123 }
124
125 if (msg->output_verbosity < 0)
126 {
127 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
128 NULL, NULL);
129 }
130 else
131 {
132 info.out = out;
133 info.level = msg->output_verbosity;
134 charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
135 (controller_cb_t)stroke_log, &info);
136 }
137 }
138
139 /**
140 * Implementation of stroke_control_t.terminate.
141 */
142 static void terminate(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
143 {
144 char *string, *pos = NULL, *name = NULL;
145 u_int32_t id = 0;
146 bool child;
147 int len;
148 ike_sa_t *ike_sa;
149 enumerator_t *enumerator;
150 stroke_log_info_t info;
151
152 string = msg->terminate.name;
153
154 len = strlen(string);
155 if (len < 1)
156 {
157 DBG1(DBG_CFG, "error parsing string");
158 return;
159 }
160 switch (string[len-1])
161 {
162 case '}':
163 child = TRUE;
164 pos = strchr(string, '{');
165 break;
166 case ']':
167 child = FALSE;
168 pos = strchr(string, '[');
169 break;
170 default:
171 name = string;
172 child = FALSE;
173 break;
174 }
175
176 if (name)
177 {
178 /* is a single name */
179 }
180 else if (pos == string + len - 2)
181 { /* is name[] or name{} */
182 string[len-2] = '\0';
183 name = string;
184 }
185 else
186 { /* is name[123] or name{23} */
187 string[len-1] = '\0';
188 id = atoi(pos + 1);
189 if (id == 0)
190 {
191 DBG1(DBG_CFG, "error parsing string");
192 return;
193 }
194 }
195
196 info.out = out;
197 info.level = msg->output_verbosity;
198
199 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
200 while (enumerator->enumerate(enumerator, &ike_sa))
201 {
202 child_sa_t *child_sa;
203 iterator_t *children;
204
205 if (child)
206 {
207 children = ike_sa->create_child_sa_iterator(ike_sa);
208 while (children->iterate(children, (void**)&child_sa))
209 {
210 if ((name && streq(name, child_sa->get_name(child_sa))) ||
211 (id && id == child_sa->get_reqid(child_sa)))
212 {
213 id = child_sa->get_reqid(child_sa);
214 children->destroy(children);
215 enumerator->destroy(enumerator);
216
217 charon->controller->terminate_child(charon->controller, id,
218 (controller_cb_t)stroke_log, &info);
219 return;
220 }
221 }
222 children->destroy(children);
223 }
224 else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
225 (id && id == ike_sa->get_unique_id(ike_sa)))
226 {
227 id = ike_sa->get_unique_id(ike_sa);
228 /* unlock manager first */
229 enumerator->destroy(enumerator);
230
231 charon->controller->terminate_ike(charon->controller, id,
232 (controller_cb_t)stroke_log, &info);
233 return;
234 }
235
236 }
237 enumerator->destroy(enumerator);
238 DBG1(DBG_CFG, "no such SA found");
239 }
240
241 /**
242 * Implementation of stroke_control_t.terminate_srcip.
243 */
244 static void terminate_srcip(private_stroke_control_t *this,
245 stroke_msg_t *msg, FILE *out)
246 {
247 enumerator_t *enumerator;
248 ike_sa_t *ike_sa;
249 host_t *start = NULL, *end = NULL, *vip;
250 chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip;
251
252 if (msg->terminate_srcip.start)
253 {
254 start = host_create_from_string(msg->terminate_srcip.start, 0);
255 }
256 if (!start)
257 {
258 DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
259 return;
260 }
261 chunk_start = start->get_address(start);
262 if (msg->terminate_srcip.end)
263 {
264 end = host_create_from_string(msg->terminate_srcip.end, 0);
265 if (!end)
266 {
267 DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
268 start->destroy(start);
269 return;
270 }
271 chunk_end = end->get_address(end);
272 }
273
274 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
275 while (enumerator->enumerate(enumerator, &ike_sa))
276 {
277 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
278 if (!vip)
279 {
280 continue;
281 }
282 if (!end)
283 {
284 if (!vip->ip_equals(vip, start))
285 {
286 continue;
287 }
288 }
289 else
290 {
291 chunk_vip = vip->get_address(vip);
292 if (chunk_vip.len != chunk_start.len ||
293 chunk_vip.len != chunk_end.len ||
294 memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 ||
295 memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0)
296 {
297 continue;
298 }
299 }
300
301 /* schedule delete asynchronously */
302 charon->processor->queue_job(charon->processor, (job_t*)
303 delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
304 }
305 enumerator->destroy(enumerator);
306 start->destroy(start);
307 DESTROY_IF(end);
308 }
309
310 /**
311 * Implementation of stroke_control_t.route.
312 */
313 static void route(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
314 {
315 peer_cfg_t *peer_cfg;
316 child_cfg_t *child_cfg;
317 stroke_log_info_t info;
318
319 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
320 msg->route.name);
321 if (peer_cfg == NULL)
322 {
323 fprintf(out, "no config named '%s'\n", msg->route.name);
324 return;
325 }
326 if (peer_cfg->get_ike_version(peer_cfg) != 2)
327 {
328 peer_cfg->destroy(peer_cfg);
329 return;
330 }
331
332 child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
333 if (child_cfg == NULL)
334 {
335 fprintf(out, "no child config named '%s'\n", msg->route.name);
336 peer_cfg->destroy(peer_cfg);
337 return;
338 }
339
340 info.out = out;
341 info.level = msg->output_verbosity;
342 charon->controller->route(charon->controller, peer_cfg, child_cfg,
343 (controller_cb_t)stroke_log, &info);
344 peer_cfg->destroy(peer_cfg);
345 child_cfg->destroy(child_cfg);
346 }
347
348 /**
349 * Implementation of stroke_control_t.unroute.
350 */
351 static void unroute(private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
352 {
353 char *name;
354 ike_sa_t *ike_sa;
355 enumerator_t *enumerator;
356 stroke_log_info_t info;
357
358 name = msg->terminate.name;
359
360 info.out = out;
361 info.level = msg->output_verbosity;
362
363 enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
364 while (enumerator->enumerate(enumerator, &ike_sa))
365 {
366 child_sa_t *child_sa;
367 iterator_t *children;
368 u_int32_t id;
369
370 children = ike_sa->create_child_sa_iterator(ike_sa);
371 while (children->iterate(children, (void**)&child_sa))
372 {
373 if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
374 streq(name, child_sa->get_name(child_sa)))
375 {
376 id = child_sa->get_reqid(child_sa);
377 children->destroy(children);
378 enumerator->destroy(enumerator);
379 charon->controller->unroute(charon->controller, id,
380 (controller_cb_t)stroke_log, &info);
381 return;
382 }
383 }
384 children->destroy(children);
385 }
386 enumerator->destroy(enumerator);
387 DBG1(DBG_CFG, "no such SA found");
388 }
389
390 /**
391 * Implementation of stroke_control_t.destroy
392 */
393 static void destroy(private_stroke_control_t *this)
394 {
395 free(this);
396 }
397
398 /*
399 * see header file
400 */
401 stroke_control_t *stroke_control_create()
402 {
403 private_stroke_control_t *this = malloc_thing(private_stroke_control_t);
404
405 this->public.initiate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))initiate;
406 this->public.terminate = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate;
407 this->public.terminate_srcip = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))terminate_srcip;
408 this->public.route = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))route;
409 this->public.unroute = (void(*)(stroke_control_t*, stroke_msg_t *msg, FILE *out))unroute;
410 this->public.destroy = (void(*)(stroke_control_t*))destroy;
411
412 return &this->public;
413 }
414