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