b4bc95707abb59467b47122ce41823a9f5b4ebc4
[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 typedef struct private_child_cfg_t private_child_cfg_t;
32
33 /**
34 * Private data of an child_cfg_t object
35 */
36 struct private_child_cfg_t {
37
38 /**
39 * Public part
40 */
41 child_cfg_t public;
42
43 /**
44 * Number of references hold by others to this child_cfg
45 */
46 refcount_t refcount;
47
48 /**
49 * Name of the child_cfg, used to query it
50 */
51 char *name;
52
53 /**
54 * list for all proposals
55 */
56 linked_list_t *proposals;
57
58 /**
59 * list for traffic selectors for my site
60 */
61 linked_list_t *my_ts;
62
63 /**
64 * list for traffic selectors for others site
65 */
66 linked_list_t *other_ts;
67
68 /**
69 * updown script
70 */
71 char *updown;
72
73 /**
74 * allow host access
75 */
76 bool hostaccess;
77
78 /**
79 * Mode to propose for a initiated CHILD: tunnel/transport
80 */
81 mode_t mode;
82
83 /**
84 * Time before an SA gets invalid
85 */
86 u_int32_t lifetime;
87
88 /**
89 * Time before an SA gets rekeyed
90 */
91 u_int32_t rekeytime;
92
93 /**
94 * Time, which specifies the range of a random value
95 * substracted from rekeytime.
96 */
97 u_int32_t jitter;
98 };
99
100 /**
101 * Implementation of child_cfg_t.get_name
102 */
103 static char *get_name(private_child_cfg_t *this)
104 {
105 return this->name;
106 }
107
108 /**
109 * Implementation of child_cfg_t.add_proposal
110 */
111 static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
112 {
113 this->proposals->insert_last(this->proposals, proposal);
114 }
115
116 /**
117 * strip out DH groups from a proposal
118 */
119 static void strip_dh_from_proposal(proposal_t *proposal)
120 {
121 iterator_t *iterator;
122 algorithm_t *algo;
123
124 iterator = proposal->create_algorithm_iterator(proposal, DIFFIE_HELLMAN_GROUP);
125 while (iterator->iterate(iterator, (void**)&algo))
126 {
127 iterator->remove(iterator);
128 free(algo);
129 }
130 iterator->destroy(iterator);
131 }
132
133 /**
134 * Implementation of child_cfg_t.get_proposals
135 */
136 static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
137 {
138 iterator_t *iterator;
139 proposal_t *current;
140 linked_list_t *proposals = linked_list_create();
141
142 iterator = this->proposals->create_iterator(this->proposals, TRUE);
143 while (iterator->iterate(iterator, (void**)&current))
144 {
145 current = current->clone(current);
146 if (strip_dh)
147 {
148 strip_dh_from_proposal(current);
149 }
150 proposals->insert_last(proposals, current);
151 }
152 iterator->destroy(iterator);
153
154 return proposals;
155 }
156
157 /**
158 * Implementation of child_cfg_t.get_name
159 */
160 static proposal_t* select_proposal(private_child_cfg_t*this,
161 linked_list_t *proposals, bool strip_dh)
162 {
163 iterator_t *stored_iter, *supplied_iter;
164 proposal_t *stored, *supplied, *selected = NULL;
165
166 stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
167 supplied_iter = proposals->create_iterator(proposals, TRUE);
168
169 /* compare all stored proposals with all supplied. Stored ones are preferred. */
170 while (stored_iter->iterate(stored_iter, (void**)&stored))
171 {
172 stored = stored->clone(stored);
173 supplied_iter->reset(supplied_iter);
174 while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
175 {
176 if (strip_dh)
177 {
178 strip_dh_from_proposal(stored);
179 }
180 selected = stored->select(stored, supplied);
181 if (selected)
182 {
183 break;
184 }
185 }
186 stored->destroy(stored);
187 if (selected)
188 {
189 break;
190 }
191 }
192 stored_iter->destroy(stored_iter);
193 supplied_iter->destroy(supplied_iter);
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 iterator_t *i1, *i2;
221 traffic_selector_t *ts1, *ts2, *selected;
222 linked_list_t *result = linked_list_create();
223
224 if (local)
225 {
226 i1 = this->my_ts->create_iterator(this->my_ts, TRUE);
227 }
228 else
229 {
230 i1 = this->other_ts->create_iterator(this->other_ts, FALSE);
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 (i1->iterate(i1, (void**)&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 i1->destroy(i1);
250 }
251 else
252 {
253 DBG2(DBG_CFG, "selecting traffic selectors for %s:",
254 local ? "us" : "other");
255 i2 = supplied->create_iterator(supplied, TRUE);
256 /* iterate over all stored selectors */
257 while (i1->iterate(i1, (void**)&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 i2->reset(i2);
267 /* iterate over all supplied traffic selectors */
268 while (i2->iterate(i2, (void**)&ts2))
269 {
270 selected = ts1->get_subset(ts1, ts2);
271 if (selected)
272 {
273 DBG2(DBG_CFG, " config: %R, received: %R => match: %R",
274 ts1, ts2, selected);
275 result->insert_last(result, selected);
276 }
277 else
278 {
279 DBG2(DBG_CFG, " config: %R, received: %R => no match",
280 ts1, ts2, selected);
281 }
282 }
283 ts1->destroy(ts1);
284 }
285 i1->destroy(i1);
286 i2->destroy(i2);
287 }
288
289 /* remove any redundant traffic selectors in the list */
290 i1 = result->create_iterator(result, TRUE);
291 i2 = result->create_iterator(result, TRUE);
292 while (i1->iterate(i1, (void**)&ts1))
293 {
294 while (i2->iterate(i2, (void**)&ts2))
295 {
296 if (ts1 != ts2)
297 {
298 if (ts2->is_contained_in(ts2, ts1))
299 {
300 i2->remove(i2);
301 ts2->destroy(ts2);
302 i1->reset(i1);
303 break;
304 }
305 if (ts1->is_contained_in(ts1, ts2))
306 {
307 i1->remove(i1);
308 ts1->destroy(ts1);
309 i2->reset(i2);
310 break;
311 }
312 }
313 }
314 }
315 i1->destroy(i1);
316 i2->destroy(i2);
317
318 return result;
319 }
320
321 /**
322 * Implementation of child_cfg_t.get_name
323 */
324 static char* get_updown(private_child_cfg_t *this)
325 {
326 return this->updown;
327 }
328
329 /**
330 * Implementation of child_cfg_t.get_name
331 */
332 static bool get_hostaccess(private_child_cfg_t *this)
333 {
334 return this->hostaccess;
335 }
336
337 /**
338 * Implementation of child_cfg_t.get_name
339 */
340 static u_int32_t get_lifetime(private_child_cfg_t *this, bool rekey)
341 {
342 if (rekey)
343 {
344 if (this->jitter == 0)
345 {
346 return this->rekeytime;
347 }
348 return this->rekeytime - (random() % this->jitter);
349 }
350 return this->lifetime;
351 }
352
353 /**
354 * Implementation of child_cfg_t.get_name
355 */
356 static mode_t get_mode(private_child_cfg_t *this)
357 {
358 return this->mode;
359 }
360
361 /**
362 * Implementation of child_cfg_t.get_dh_group.
363 */
364 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
365 {
366 iterator_t *iterator;
367 proposal_t *proposal;
368 algorithm_t *algo;
369 diffie_hellman_group_t dh_group = MODP_NONE;
370
371 iterator = this->proposals->create_iterator(this->proposals, TRUE);
372 while (iterator->iterate(iterator, (void**)&proposal))
373 {
374 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &algo))
375 {
376 dh_group = algo->algorithm;
377 break;
378 }
379 }
380 iterator->destroy(iterator);
381 return dh_group;
382 }
383
384 /**
385 * Implementation of child_cfg_t.get_name
386 */
387 static void get_ref(private_child_cfg_t *this)
388 {
389 ref_get(&this->refcount);
390 }
391
392 /**
393 * Implements child_cfg_t.destroy.
394 */
395 static void destroy(private_child_cfg_t *this)
396 {
397 if (ref_put(&this->refcount))
398 {
399 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
400 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
401 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
402 if (this->updown)
403 {
404 free(this->updown);
405 }
406 free(this->name);
407 free(this);
408 }
409 }
410
411 /*
412 * Described in header-file
413 */
414 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
415 u_int32_t rekeytime, u_int32_t jitter,
416 char *updown, bool hostaccess, mode_t mode)
417 {
418 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
419
420 /* public functions */
421 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
422 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
423 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
424 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
425 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
426 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
427 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
428 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
429 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
430 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
431 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
432 this->public.get_ref = (void (*) (child_cfg_t*))get_ref;
433 this->public.destroy = (void (*) (child_cfg_t*))destroy;
434
435 /* apply init values */
436 this->name = strdup(name);
437 this->lifetime = lifetime;
438 this->rekeytime = rekeytime;
439 this->jitter = jitter;
440 this->updown = updown ? strdup(updown) : NULL;
441 this->hostaccess = hostaccess;
442 this->mode = mode;
443
444 /* initialize private members*/
445 this->refcount = 1;
446 this->proposals = linked_list_create();
447 this->my_ts = linked_list_create();
448 this->other_ts = linked_list_create();
449
450 return &this->public;
451 }