2c7201972e5831aa1ee1f872856ab7d7e5bedf77
[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
91 */
92 action_t dpd_action;
93
94 /**
95 * action to take on CHILD_SA close
96 */
97 action_t close_action;
98
99 /**
100 * Time before an SA gets invalid
101 */
102 u_int32_t lifetime;
103
104 /**
105 * Time before an SA gets rekeyed
106 */
107 u_int32_t rekeytime;
108
109 /**
110 * Time, which specifies the range of a random value
111 * substracted from rekeytime.
112 */
113 u_int32_t jitter;
114 };
115
116 /**
117 * Implementation of child_cfg_t.get_name
118 */
119 static char *get_name(private_child_cfg_t *this)
120 {
121 return this->name;
122 }
123
124 /**
125 * Implementation of child_cfg_t.add_proposal
126 */
127 static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
128 {
129 this->proposals->insert_last(this->proposals, proposal);
130 }
131
132 /**
133 * Implementation of child_cfg_t.get_proposals
134 */
135 static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
136 {
137 enumerator_t *enumerator;
138 proposal_t *current;
139 linked_list_t *proposals = linked_list_create();
140
141 enumerator = this->proposals->create_enumerator(this->proposals);
142 while (enumerator->enumerate(enumerator, &current))
143 {
144 current = current->clone(current);
145 if (strip_dh)
146 {
147 current->strip_dh(current);
148 }
149 proposals->insert_last(proposals, current);
150 }
151 enumerator->destroy(enumerator);
152
153 return proposals;
154 }
155
156 /**
157 * Implementation of child_cfg_t.get_name
158 */
159 static proposal_t* select_proposal(private_child_cfg_t*this,
160 linked_list_t *proposals, bool strip_dh)
161 {
162 enumerator_t *stored_enum, *supplied_enum;
163 proposal_t *stored, *supplied, *selected = NULL;
164
165 stored_enum = this->proposals->create_enumerator(this->proposals);
166 supplied_enum = proposals->create_enumerator(proposals);
167
168 /* compare all stored proposals with all supplied. Stored ones are preferred. */
169 while (stored_enum->enumerate(stored_enum, &stored))
170 {
171 stored = stored->clone(stored);
172 while (supplied_enum->enumerate(supplied_enum, &supplied))
173 {
174 if (strip_dh)
175 {
176 stored->strip_dh(stored);
177 }
178 selected = stored->select(stored, supplied);
179 if (selected)
180 {
181 break;
182 }
183 }
184 stored->destroy(stored);
185 if (selected)
186 {
187 break;
188 }
189 supplied_enum->destroy(supplied_enum);
190 supplied_enum = proposals->create_enumerator(proposals);
191 }
192 stored_enum->destroy(stored_enum);
193 supplied_enum->destroy(supplied_enum);
194 return selected;
195 }
196
197 /**
198 * Implementation of child_cfg_t.get_name
199 */
200 static void add_traffic_selector(private_child_cfg_t *this, bool local,
201 traffic_selector_t *ts)
202 {
203 if (local)
204 {
205 this->my_ts->insert_last(this->my_ts, ts);
206 }
207 else
208 {
209 this->other_ts->insert_last(this->other_ts, ts);
210 }
211 }
212
213 /**
214 * Implementation of child_cfg_t.get_name
215 */
216 static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
217 linked_list_t *supplied,
218 host_t *host)
219 {
220 enumerator_t *e1, *e2;
221 traffic_selector_t *ts1, *ts2, *selected;
222 linked_list_t *result = linked_list_create();
223
224 if (local)
225 {
226 e1 = this->my_ts->create_enumerator(this->my_ts);
227 }
228 else
229 {
230 e1 = this->other_ts->create_enumerator(this->other_ts);
231 }
232
233 /* no list supplied, just fetch the stored traffic selectors */
234 if (supplied == NULL)
235 {
236 DBG2(DBG_CFG, "proposing traffic selectors for %s:",
237 local ? "us" : "other");
238 while (e1->enumerate(e1, &ts1))
239 {
240 /* we make a copy of the TS, this allows us to update dynamic TS' */
241 selected = ts1->clone(ts1);
242 if (host)
243 {
244 selected->set_address(selected, host);
245 }
246 DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
247 result->insert_last(result, selected);
248 }
249 e1->destroy(e1);
250 }
251 else
252 {
253 DBG2(DBG_CFG, "selecting traffic selectors for %s:",
254 local ? "us" : "other");
255 e2 = supplied->create_enumerator(supplied);
256 /* iterate over all stored selectors */
257 while (e1->enumerate(e1, &ts1))
258 {
259 /* we make a copy of the TS, as we have to update dynamic TS' */
260 ts1 = ts1->clone(ts1);
261 if (host)
262 {
263 ts1->set_address(ts1, host);
264 }
265
266 /* iterate over all supplied traffic selectors */
267 while (e2->enumerate(e2, &ts2))
268 {
269 selected = ts1->get_subset(ts1, ts2);
270 if (selected)
271 {
272 DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
273 ts1, ts2, selected);
274 result->insert_last(result, selected);
275 }
276 else
277 {
278 DBG2(DBG_CFG, " config: %R, received: %R => no match",
279 ts1, ts2, selected);
280 }
281 }
282 e2->destroy(e2);
283 e2 = supplied->create_enumerator(supplied);
284 ts1->destroy(ts1);
285 }
286 e1->destroy(e1);
287 e2->destroy(e2);
288 }
289
290 /* remove any redundant traffic selectors in the list */
291 e1 = result->create_enumerator(result);
292 e2 = result->create_enumerator(result);
293 while (e1->enumerate(e1, &ts1))
294 {
295 while (e2->enumerate(e2, &ts2))
296 {
297 if (ts1 != ts2)
298 {
299 if (ts2->is_contained_in(ts2, ts1))
300 {
301 result->remove_at(result, e2);
302 ts2->destroy(ts2);
303 e1->destroy(e1);
304 e1 = result->create_enumerator(result);
305 break;
306 }
307 if (ts1->is_contained_in(ts1, ts2))
308 {
309 result->remove_at(result, e1);
310 ts1->destroy(ts1);
311 e2->destroy(e2);
312 e2 = result->create_enumerator(result);
313 break;
314 }
315 }
316 }
317 }
318 e1->destroy(e1);
319 e2->destroy(e2);
320
321 return result;
322 }
323
324 /**
325 * Implementation of child_cfg_t.get_name
326 */
327 static char* get_updown(private_child_cfg_t *this)
328 {
329 return this->updown;
330 }
331
332 /**
333 * Implementation of child_cfg_t.get_name
334 */
335 static bool get_hostaccess(private_child_cfg_t *this)
336 {
337 return this->hostaccess;
338 }
339
340 /**
341 * Implementation of child_cfg_t.get_name
342 */
343 static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey)
344 {
345 if (rekey)
346 {
347 if (this->jitter == 0)
348 {
349 return this->rekeytime;
350 }
351 return this->rekeytime - (random() % this->jitter);
352 }
353 return this->lifetime;
354 }
355
356 /**
357 * Implementation of child_cfg_t.get_mode
358 */
359 static mode_t get_mode(private_child_cfg_t *this)
360 {
361 return this->mode;
362 }
363
364 /**
365 * Implementation of child_cfg_t.get_dpd_action
366 */
367 static action_t get_dpd_action(private_child_cfg_t *this)
368 {
369 return this->dpd_action;
370 }
371
372 /**
373 * Implementation of child_cfg_t.get_close_action
374 */
375 static action_t get_close_action(private_child_cfg_t *this)
376 {
377 return this->close_action;
378 }
379
380 /**
381 * Implementation of child_cfg_t.get_dh_group.
382 */
383 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
384 {
385 enumerator_t *enumerator;
386 proposal_t *proposal;
387 u_int16_t dh_group = MODP_NONE;
388
389 enumerator = this->proposals->create_enumerator(this->proposals);
390 while (enumerator->enumerate(enumerator, &proposal))
391 {
392 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &dh_group, NULL))
393 {
394 break;
395 }
396 }
397 enumerator->destroy(enumerator);
398 return dh_group;
399 }
400
401 /**
402 * Implementation of child_cfg_t.get_name
403 */
404 static child_cfg_t* get_ref(private_child_cfg_t *this)
405 {
406 ref_get(&this->refcount);
407 return &this->public;
408 }
409
410 /**
411 * Implements child_cfg_t.destroy.
412 */
413 static void destroy(private_child_cfg_t *this)
414 {
415 if (ref_put(&this->refcount))
416 {
417 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
418 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
419 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
420 if (this->updown)
421 {
422 free(this->updown);
423 }
424 free(this->name);
425 free(this);
426 }
427 }
428
429 /*
430 * Described in header-file
431 */
432 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
433 u_int32_t rekeytime, u_int32_t jitter,
434 char *updown, bool hostaccess, mode_t mode,
435 action_t dpd_action, action_t close_action)
436 {
437 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
438
439 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
440 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
441 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
442 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
443 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
444 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
445 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
446 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
447 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
448 this->public.get_dpd_action = (action_t (*) (child_cfg_t *))get_dpd_action;
449 this->public.get_close_action = (action_t (*) (child_cfg_t *))get_close_action;
450 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
451 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
452 this->public.get_ref = (child_cfg_t* (*) (child_cfg_t*))get_ref;
453 this->public.destroy = (void (*) (child_cfg_t*))destroy;
454
455 this->name = strdup(name);
456 this->lifetime = lifetime;
457 this->rekeytime = rekeytime;
458 this->jitter = jitter;
459 this->updown = updown ? strdup(updown) : NULL;
460 this->hostaccess = hostaccess;
461 this->mode = mode;
462 this->dpd_action = dpd_action;
463 this->close_action = close_action;
464 this->refcount = 1;
465 this->proposals = linked_list_create();
466 this->my_ts = linked_list_create();
467 this->other_ts = linked_list_create();
468
469 return &this->public;
470 }
471