440f7710b9ebbc1d5f3b0bda1634f145accb33b7
[strongswan.git] / src / charon / config / child_cfg.c
1 /**
2 * @file child_cfg.c
3 *
4 * @brief Implementation of child_cfg_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2007 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24
25 #include "child_cfg.h"
26
27 #include <daemon.h>
28
29 ENUM(mode_names, MODE_TRANSPORT, MODE_BEET,
30 "TRANSPORT",
31 "TUNNEL",
32 "2",
33 "3",
34 "BEET",
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 * Time before an SA gets invalid
91 */
92 u_int32_t lifetime;
93
94 /**
95 * Time before an SA gets rekeyed
96 */
97 u_int32_t rekeytime;
98
99 /**
100 * Time, which specifies the range of a random value
101 * substracted from rekeytime.
102 */
103 u_int32_t jitter;
104 };
105
106 /**
107 * Implementation of child_cfg_t.get_name
108 */
109 static char *get_name(private_child_cfg_t *this)
110 {
111 return this->name;
112 }
113
114 /**
115 * Implementation of child_cfg_t.add_proposal
116 */
117 static void add_proposal(private_child_cfg_t *this, proposal_t *proposal)
118 {
119 this->proposals->insert_last(this->proposals, proposal);
120 }
121
122 /**
123 * strip out DH groups from a proposal
124 */
125 static void strip_dh_from_proposal(proposal_t *proposal)
126 {
127 iterator_t *iterator;
128 algorithm_t *algo;
129
130 iterator = proposal->create_algorithm_iterator(proposal, DIFFIE_HELLMAN_GROUP);
131 while (iterator->iterate(iterator, (void**)&algo))
132 {
133 iterator->remove(iterator);
134 free(algo);
135 }
136 iterator->destroy(iterator);
137 }
138
139 /**
140 * Implementation of child_cfg_t.get_proposals
141 */
142 static linked_list_t* get_proposals(private_child_cfg_t *this, bool strip_dh)
143 {
144 iterator_t *iterator;
145 proposal_t *current;
146 linked_list_t *proposals = linked_list_create();
147
148 iterator = this->proposals->create_iterator(this->proposals, TRUE);
149 while (iterator->iterate(iterator, (void**)&current))
150 {
151 current = current->clone(current);
152 if (strip_dh)
153 {
154 strip_dh_from_proposal(current);
155 }
156 proposals->insert_last(proposals, current);
157 }
158 iterator->destroy(iterator);
159
160 return proposals;
161 }
162
163 /**
164 * Implementation of child_cfg_t.get_name
165 */
166 static proposal_t* select_proposal(private_child_cfg_t*this,
167 linked_list_t *proposals, bool strip_dh)
168 {
169 iterator_t *stored_iter, *supplied_iter;
170 proposal_t *stored, *supplied, *selected = NULL;
171
172 stored_iter = this->proposals->create_iterator(this->proposals, TRUE);
173 supplied_iter = proposals->create_iterator(proposals, TRUE);
174
175 /* compare all stored proposals with all supplied. Stored ones are preferred. */
176 while (stored_iter->iterate(stored_iter, (void**)&stored))
177 {
178 supplied_iter->reset(supplied_iter);
179 while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
180 {
181 if (strip_dh)
182 {
183 /* remove DH groups on a copy */
184 stored = stored->clone(stored);
185 strip_dh_from_proposal(stored);
186 selected = stored->select(stored, supplied);
187 stored->destroy(stored);
188 }
189 else
190 {
191 selected = stored->select(stored, supplied);
192 }
193 if (selected)
194 {
195 break;
196 }
197 }
198 if (selected)
199 {
200 break;
201 }
202 }
203 stored_iter->destroy(stored_iter);
204 supplied_iter->destroy(supplied_iter);
205 return selected;
206 }
207
208 /**
209 * Implementation of child_cfg_t.get_name
210 */
211 static void add_traffic_selector(private_child_cfg_t *this, bool local,
212 traffic_selector_t *ts)
213 {
214 if (local)
215 {
216 this->my_ts->insert_last(this->my_ts, ts);
217 }
218 else
219 {
220 this->other_ts->insert_last(this->other_ts, ts);
221 }
222 }
223
224 /**
225 * Implementation of child_cfg_t.get_name
226 */
227 static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
228 linked_list_t *supplied,
229 host_t *host)
230 {
231 iterator_t *i1, *i2;
232 traffic_selector_t *ts1, *ts2, *selected;
233 linked_list_t *result = linked_list_create();
234
235 if (local)
236 {
237 i1 = this->my_ts->create_iterator(this->my_ts, TRUE);
238 }
239 else
240 {
241 i1 = this->other_ts->create_iterator(this->other_ts, FALSE);
242 }
243
244 /* no list supplied, just fetch the stored traffic selectors */
245 if (supplied == NULL)
246 {
247 while (i1->iterate(i1, (void**)&ts1))
248 {
249 /* we make a copy of the TS, this allows us to update dynamic TS' */
250 ts1 = ts1->clone(ts1);
251 if (host)
252 {
253 ts1->set_address(ts1, host);
254 }
255 result->insert_last(result, ts1);
256 }
257 i1->destroy(i1);
258 }
259 else
260 {
261 DBG2(DBG_CFG, "selecting traffic selectors");
262 i2 = supplied->create_iterator(supplied, TRUE);
263 /* iterate over all stored selectors */
264 while (i1->iterate(i1, (void**)&ts1))
265 {
266 /* we make a copy of the TS, as we have to update dynamic TS' */
267 ts1 = ts1->clone(ts1);
268 if (host)
269 {
270 ts1->set_address(ts1, host);
271 }
272
273 i2->reset(i2);
274 /* iterate over all supplied traffic selectors */
275 while (i2->iterate(i2, (void**)&ts2))
276 {
277 DBG2(DBG_CFG, "stored %R <=> %R received", ts1, ts2);
278 selected = ts1->get_subset(ts1, ts2);
279 if (selected)
280 {
281 result->insert_last(result, selected);
282 DBG2(DBG_CFG, "found traffic selector for %s: %R",
283 local ? "us" : "other", selected);
284 }
285 }
286 ts1->destroy(ts1);
287 }
288 i1->destroy(i1);
289 i2->destroy(i2);
290 }
291
292 /* remove any redundant traffic selectors in the list */
293 i1 = result->create_iterator(result, TRUE);
294 i2 = result->create_iterator(result, TRUE);
295 while (i1->iterate(i1, (void**)&ts1))
296 {
297 while (i2->iterate(i2, (void**)&ts2))
298 {
299 if (ts1 != ts2)
300 {
301 if (ts2->is_contained_in(ts2, ts1))
302 {
303 i2->remove(i2);
304 ts2->destroy(ts2);
305 i1->reset(i1);
306 break;
307 }
308 if (ts1->is_contained_in(ts1, ts2))
309 {
310 i1->remove(i1);
311 ts1->destroy(ts1);
312 i2->reset(i2);
313 break;
314 }
315 }
316 }
317 }
318 i1->destroy(i1);
319 i2->destroy(i2);
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_name
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_dh_group.
366 */
367 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
368 {
369 iterator_t *iterator;
370 proposal_t *proposal;
371 algorithm_t *algo;
372 diffie_hellman_group_t dh_group = MODP_NONE;
373
374 iterator = this->proposals->create_iterator(this->proposals, TRUE);
375 while (iterator->iterate(iterator, (void**)&proposal))
376 {
377 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &algo))
378 {
379 dh_group = algo->algorithm;
380 break;
381 }
382 }
383 iterator->destroy(iterator);
384 return dh_group;
385 }
386
387 /**
388 * Implementation of child_cfg_t.get_name
389 */
390 static void get_ref(private_child_cfg_t *this)
391 {
392 ref_get(&this->refcount);
393 }
394
395 /**
396 * Implements child_cfg_t.destroy.
397 */
398 static void destroy(private_child_cfg_t *this)
399 {
400 if (ref_put(&this->refcount))
401 {
402 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
403 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
404 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
405 if (this->updown)
406 {
407 free(this->updown);
408 }
409 free(this->name);
410 free(this);
411 }
412 }
413
414 /*
415 * Described in header-file
416 */
417 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
418 u_int32_t rekeytime, u_int32_t jitter,
419 char *updown, bool hostaccess, mode_t mode)
420 {
421 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
422
423 /* public functions */
424 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
425 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
426 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
427 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
428 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
429 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
430 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
431 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
432 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
433 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
434 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
435 this->public.get_ref = (void (*) (child_cfg_t*))get_ref;
436 this->public.destroy = (void (*) (child_cfg_t*))destroy;
437
438 /* apply init values */
439 this->name = strdup(name);
440 this->lifetime = lifetime;
441 this->rekeytime = rekeytime;
442 this->jitter = jitter;
443 this->updown = updown ? strdup(updown) : NULL;
444 this->hostaccess = hostaccess;
445 this->mode = mode;
446
447 /* initialize private members*/
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 }