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