ipsec statusall displays dpd options
[strongswan.git] / src / charon / config / child_cfg.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * $Id$
18 */
19
20 #include "child_cfg.h"
21
22 #include <daemon.h>
23
24 ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
25 "TRANSPORT",
26 "TUNNEL",
27 "2",
28 "3",
29 "BEET",
30 );
31
32 ENUM(action_names, ACTION_NONE, ACTION_RESTART,
33 "clear",
34 "hold",
35 "restart",
36 );
37
38 ENUM_BEGIN(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_NONE,
39 "IPCOMP_NONE");
40 ENUM_NEXT(ipcomp_transform_names, IPCOMP_OUI, IPCOMP_LZJH, IPCOMP_NONE,
41 "IPCOMP_OUI",
42 "IPCOMP_DEFLATE",
43 "IPCOMP_LZS",
44 "IPCOMP_LZJH");
45 ENUM_END(ipcomp_transform_names, IPCOMP_LZJH);
46
47 typedef struct private_child_cfg_t private_child_cfg_t;
48
49 /**
50 * Private data of an child_cfg_t object
51 */
52 struct private_child_cfg_t {
53
54 /**
55 * Public part
56 */
57 child_cfg_t public;
58
59 /**
60 * Number of references hold by others to this child_cfg
61 */
62 refcount_t refcount;
63
64 /**
65 * Name of the child_cfg, used to query it
66 */
67 char *name;
68
69 /**
70 * list for all proposals
71 */
72 linked_list_t *proposals;
73
74 /**
75 * list for traffic selectors for my site
76 */
77 linked_list_t *my_ts;
78
79 /**
80 * list for traffic selectors for others site
81 */
82 linked_list_t *other_ts;
83
84 /**
85 * updown script
86 */
87 char *updown;
88
89 /**
90 * allow host access
91 */
92 bool hostaccess;
93
94 /**
95 * Mode to propose for a initiated CHILD: tunnel/transport
96 */
97 mode_t mode;
98
99 /**
100 * action to take on DPD
101 */
102 action_t dpd_action;
103
104 /**
105 * action to take on CHILD_SA close
106 */
107 action_t close_action;
108
109 /**
110 * Time before an SA gets invalid
111 */
112 u_int32_t lifetime;
113
114 /**
115 * Time before an SA gets rekeyed
116 */
117 u_int32_t rekeytime;
118
119 /**
120 * Time, which specifies the range of a random value
121 * substracted from rekeytime.
122 */
123 u_int32_t jitter;
124
125 /**
126 * enable IPComp
127 */
128 bool use_ipcomp;
129 };
130
131 /**
132 * Implementation of child_cfg_t.get_name
133 */
134 static char *get_name(private_child_cfg_t *this)
135 {
136 return this->name;
137 }
138
139 /**
140 * Implementation of child_cfg_t.add_proposal
141 */
142 static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
143 {
144 this->proposals->insert_last(this->proposals, proposal);
145 }
146
147 /**
148 * Implementation of child_cfg_t.get_proposals
149 */
150 static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
151 {
152 enumerator_t *enumerator;
153 proposal_t *current;
154 linked_list_t *proposals = linked_list_create();
155
156 enumerator = this->proposals->create_enumerator(this->proposals);
157 while (enumerator->enumerate(enumerator, &current))
158 {
159 current = current->clone(current);
160 if (strip_dh)
161 {
162 current->strip_dh(current);
163 }
164 proposals->insert_last(proposals, current);
165 }
166 enumerator->destroy(enumerator);
167
168 return proposals;
169 }
170
171 /**
172 * Implementation of child_cfg_t.get_name
173 */
174 static proposal_t* select_proposal(private_child_cfg_t*this,
175 linked_list_t *proposals, bool strip_dh)
176 {
177 enumerator_t *stored_enum, *supplied_enum;
178 proposal_t *stored, *supplied, *selected = NULL;
179
180 stored_enum = this->proposals->create_enumerator(this->proposals);
181 supplied_enum = proposals->create_enumerator(proposals);
182
183 /* compare all stored proposals with all supplied. Stored ones are preferred. */
184 while (stored_enum->enumerate(stored_enum, &stored))
185 {
186 stored = stored->clone(stored);
187 while (supplied_enum->enumerate(supplied_enum, &supplied))
188 {
189 if (strip_dh)
190 {
191 stored->strip_dh(stored);
192 }
193 selected = stored->select(stored, supplied);
194 if (selected)
195 {
196 DBG2(DBG_CFG, "received proposals: %#P", proposals);
197 DBG2(DBG_CFG, "configured proposals: %#P", this->proposals);
198 DBG2(DBG_CFG, "selected proposal: %P", selected);
199 break;
200 }
201 }
202 stored->destroy(stored);
203 if (selected)
204 {
205 break;
206 }
207 supplied_enum->destroy(supplied_enum);
208 supplied_enum = proposals->create_enumerator(proposals);
209 }
210 stored_enum->destroy(stored_enum);
211 supplied_enum->destroy(supplied_enum);
212 if (selected == NULL)
213 {
214 DBG1(DBG_CFG, "received proposals: %#P", proposals);
215 DBG1(DBG_CFG, "configured proposals: %#P", this->proposals);
216 }
217 return selected;
218 }
219
220 /**
221 * Implementation of child_cfg_t.get_name
222 */
223 static void add_traffic_selector(private_child_cfg_t *this, bool local,
224 traffic_selector_t *ts)
225 {
226 if (local)
227 {
228 this->my_ts->insert_last(this->my_ts, ts);
229 }
230 else
231 {
232 this->other_ts->insert_last(this->other_ts, ts);
233 }
234 }
235
236 /**
237 * Implementation of child_cfg_t.get_name
238 */
239 static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
240 linked_list_t *supplied,
241 host_t *host)
242 {
243 enumerator_t *e1, *e2;
244 traffic_selector_t *ts1, *ts2, *selected;
245 linked_list_t *result = linked_list_create();
246
247 if (local)
248 {
249 e1 = this->my_ts->create_enumerator(this->my_ts);
250 }
251 else
252 {
253 e1 = this->other_ts->create_enumerator(this->other_ts);
254 }
255
256 /* no list supplied, just fetch the stored traffic selectors */
257 if (supplied == NULL)
258 {
259 DBG2(DBG_CFG, "proposing traffic selectors for %s:",
260 local ? "us" : "other");
261 while (e1->enumerate(e1, &ts1))
262 {
263 /* we make a copy of the TS, this allows us to update dynamic TS' */
264 selected = ts1->clone(ts1);
265 if (host)
266 {
267 selected->set_address(selected, host);
268 }
269 DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
270 result->insert_last(result, selected);
271 }
272 e1->destroy(e1);
273 }
274 else
275 {
276 DBG2(DBG_CFG, "selecting traffic selectors for %s:",
277 local ? "us" : "other");
278 e2 = supplied->create_enumerator(supplied);
279 /* iterate over all stored selectors */
280 while (e1->enumerate(e1, &ts1))
281 {
282 /* we make a copy of the TS, as we have to update dynamic TS' */
283 ts1 = ts1->clone(ts1);
284 if (host)
285 {
286 ts1->set_address(ts1, host);
287 }
288
289 /* iterate over all supplied traffic selectors */
290 while (e2->enumerate(e2, &ts2))
291 {
292 selected = ts1->get_subset(ts1, ts2);
293 if (selected)
294 {
295 DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
296 ts1, ts2, selected);
297 result->insert_last(result, selected);
298 }
299 else
300 {
301 DBG2(DBG_CFG, " config: %R, received: %R => no match",
302 ts1, ts2, selected);
303 }
304 }
305 e2->destroy(e2);
306 e2 = supplied->create_enumerator(supplied);
307 ts1->destroy(ts1);
308 }
309 e1->destroy(e1);
310 e2->destroy(e2);
311 }
312
313 /* remove any redundant traffic selectors in the list */
314 e1 = result->create_enumerator(result);
315 e2 = result->create_enumerator(result);
316 while (e1->enumerate(e1, &ts1))
317 {
318 while (e2->enumerate(e2, &ts2))
319 {
320 if (ts1 != ts2)
321 {
322 if (ts2->is_contained_in(ts2, ts1))
323 {
324 result->remove_at(result, e2);
325 ts2->destroy(ts2);
326 e1->destroy(e1);
327 e1 = result->create_enumerator(result);
328 break;
329 }
330 if (ts1->is_contained_in(ts1, ts2))
331 {
332 result->remove_at(result, e1);
333 ts1->destroy(ts1);
334 e2->destroy(e2);
335 e2 = result->create_enumerator(result);
336 break;
337 }
338 }
339 }
340 }
341 e1->destroy(e1);
342 e2->destroy(e2);
343
344 return result;
345 }
346
347 /**
348 * Implementation of child_cfg_t.get_name
349 */
350 static char* get_updown(private_child_cfg_t *this)
351 {
352 return this->updown;
353 }
354
355 /**
356 * Implementation of child_cfg_t.get_name
357 */
358 static bool get_hostaccess(private_child_cfg_t *this)
359 {
360 return this->hostaccess;
361 }
362
363 /**
364 * Implementation of child_cfg_t.get_name
365 */
366 static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey)
367 {
368 if (rekey)
369 {
370 if (this->jitter == 0)
371 {
372 return this->rekeytime;
373 }
374 return this->rekeytime - (random() % this->jitter);
375 }
376 return this->lifetime;
377 }
378
379 /**
380 * Implementation of child_cfg_t.get_mode
381 */
382 static mode_t get_mode(private_child_cfg_t *this)
383 {
384 return this->mode;
385 }
386
387 /**
388 * Implementation of child_cfg_t.get_dpd_action
389 */
390 static action_t get_dpd_action(private_child_cfg_t *this)
391 {
392 return this->dpd_action;
393 }
394
395 /**
396 * Implementation of child_cfg_t.get_close_action
397 */
398 static action_t get_close_action(private_child_cfg_t *this)
399 {
400 return this->close_action;
401 }
402
403 /**
404 * Implementation of child_cfg_t.get_dh_group.
405 */
406 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
407 {
408 enumerator_t *enumerator;
409 proposal_t *proposal;
410 u_int16_t dh_group = MODP_NONE;
411
412 enumerator = this->proposals->create_enumerator(this->proposals);
413 while (enumerator->enumerate(enumerator, &proposal))
414 {
415 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
416 {
417 break;
418 }
419 }
420 enumerator->destroy(enumerator);
421 return dh_group;
422 }
423
424 /**
425 * Implementation of child_cfg_t.use_ipcomp.
426 */
427 static bool use_ipcomp(private_child_cfg_t *this)
428 {
429 return this->use_ipcomp;
430 }
431
432 /**
433 * Implementation of child_cfg_t.get_name
434 */
435 static child_cfg_t* get_ref(private_child_cfg_t *this)
436 {
437 ref_get(&this->refcount);
438 return &this->public;
439 }
440
441 /**
442 * Implements child_cfg_t.destroy.
443 */
444 static void destroy(private_child_cfg_t *this)
445 {
446 if (ref_put(&this->refcount))
447 {
448 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
449 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
450 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
451 if (this->updown)
452 {
453 free(this->updown);
454 }
455 free(this->name);
456 free(this);
457 }
458 }
459
460 /*
461 * Described in header-file
462 */
463 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
464 u_int32_t rekeytime, u_int32_t jitter,
465 char *updown, bool hostaccess, mode_t mode,
466 action_t dpd_action, action_t close_action, bool ipcomp)
467 {
468 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
469
470 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
471 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
472 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
473 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
474 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
475 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
476 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
477 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
478 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
479 this->public.get_dpd_action = (action_t (*) (child_cfg_t *))get_dpd_action;
480 this->public.get_close_action = (action_t (*) (child_cfg_t *))get_close_action;
481 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
482 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
483 this->public.use_ipcomp = (bool (*) (child_cfg_t *))use_ipcomp;
484 this->public.get_ref = (child_cfg_t* (*) (child_cfg_t*))get_ref;
485 this->public.destroy = (void (*) (child_cfg_t*))destroy;
486
487 this->name = strdup(name);
488 this->lifetime = lifetime;
489 this->rekeytime = rekeytime;
490 this->jitter = jitter;
491 this->updown = updown ? strdup(updown) : NULL;
492 this->hostaccess = hostaccess;
493 this->mode = mode;
494 this->dpd_action = dpd_action;
495 this->close_action = close_action;
496 this->use_ipcomp = ipcomp;
497 this->refcount = 1;
498 this->proposals = linked_list_create();
499 this->my_ts = linked_list_create();
500 this->other_ts = linked_list_create();
501
502 return &this->public;
503 }
504