fixed CHILD_SA proposal selection when not using DH exchange
[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 stored = stored->clone(stored);
179 supplied_iter->reset(supplied_iter);
180 while (supplied_iter->iterate(supplied_iter, (void**)&supplied))
181 {
182 if (strip_dh)
183 {
184 strip_dh_from_proposal(stored);
185 }
186 selected = stored->select(stored, supplied);
187 if (selected)
188 {
189 break;
190 }
191 }
192 stored->destroy(stored);
193 if (selected)
194 {
195 break;
196 }
197 }
198 stored_iter->destroy(stored_iter);
199 supplied_iter->destroy(supplied_iter);
200 return selected;
201 }
202
203 /**
204 * Implementation of child_cfg_t.get_name
205 */
206 static void add_traffic_selector(private_child_cfg_t *this, bool local,
207 traffic_selector_t *ts)
208 {
209 if (local)
210 {
211 this->my_ts->insert_last(this->my_ts, ts);
212 }
213 else
214 {
215 this->other_ts->insert_last(this->other_ts, ts);
216 }
217 }
218
219 /**
220 * Implementation of child_cfg_t.get_name
221 */
222 static linked_list_t* get_traffic_selectors(private_child_cfg_t *this, bool local,
223 linked_list_t *supplied,
224 host_t *host)
225 {
226 iterator_t *i1, *i2;
227 traffic_selector_t *ts1, *ts2, *selected;
228 linked_list_t *result = linked_list_create();
229
230 if (local)
231 {
232 i1 = this->my_ts->create_iterator(this->my_ts, TRUE);
233 }
234 else
235 {
236 i1 = this->other_ts->create_iterator(this->other_ts, FALSE);
237 }
238
239 /* no list supplied, just fetch the stored traffic selectors */
240 if (supplied == NULL)
241 {
242 while (i1->iterate(i1, (void**)&ts1))
243 {
244 /* we make a copy of the TS, this allows us to update dynamic TS' */
245 ts1 = ts1->clone(ts1);
246 if (host)
247 {
248 ts1->set_address(ts1, host);
249 }
250 result->insert_last(result, ts1);
251 }
252 i1->destroy(i1);
253 }
254 else
255 {
256 DBG2(DBG_CFG, "selecting traffic selectors");
257 i2 = supplied->create_iterator(supplied, TRUE);
258 /* iterate over all stored selectors */
259 while (i1->iterate(i1, (void**)&ts1))
260 {
261 /* we make a copy of the TS, as we have to update dynamic TS' */
262 ts1 = ts1->clone(ts1);
263 if (host)
264 {
265 ts1->set_address(ts1, host);
266 }
267
268 i2->reset(i2);
269 /* iterate over all supplied traffic selectors */
270 while (i2->iterate(i2, (void**)&ts2))
271 {
272 DBG2(DBG_CFG, "stored %R <=> %R received", ts1, ts2);
273 selected = ts1->get_subset(ts1, ts2);
274 if (selected)
275 {
276 result->insert_last(result, selected);
277 DBG2(DBG_CFG, "found traffic selector for %s: %R",
278 local ? "us" : "other", selected);
279 }
280 }
281 ts1->destroy(ts1);
282 }
283 i1->destroy(i1);
284 i2->destroy(i2);
285 }
286
287 /* remove any redundant traffic selectors in the list */
288 i1 = result->create_iterator(result, TRUE);
289 i2 = result->create_iterator(result, TRUE);
290 while (i1->iterate(i1, (void**)&ts1))
291 {
292 while (i2->iterate(i2, (void**)&ts2))
293 {
294 if (ts1 != ts2)
295 {
296 if (ts2->is_contained_in(ts2, ts1))
297 {
298 i2->remove(i2);
299 ts2->destroy(ts2);
300 i1->reset(i1);
301 break;
302 }
303 if (ts1->is_contained_in(ts1, ts2))
304 {
305 i1->remove(i1);
306 ts1->destroy(ts1);
307 i2->reset(i2);
308 break;
309 }
310 }
311 }
312 }
313 i1->destroy(i1);
314 i2->destroy(i2);
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_name
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_dh_group.
361 */
362 static diffie_hellman_group_t get_dh_group(private_child_cfg_t *this)
363 {
364 iterator_t *iterator;
365 proposal_t *proposal;
366 algorithm_t *algo;
367 diffie_hellman_group_t dh_group = MODP_NONE;
368
369 iterator = this->proposals->create_iterator(this->proposals, TRUE);
370 while (iterator->iterate(iterator, (void**)&proposal))
371 {
372 if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &algo))
373 {
374 dh_group = algo->algorithm;
375 break;
376 }
377 }
378 iterator->destroy(iterator);
379 return dh_group;
380 }
381
382 /**
383 * Implementation of child_cfg_t.get_name
384 */
385 static void get_ref(private_child_cfg_t *this)
386 {
387 ref_get(&this->refcount);
388 }
389
390 /**
391 * Implements child_cfg_t.destroy.
392 */
393 static void destroy(private_child_cfg_t *this)
394 {
395 if (ref_put(&this->refcount))
396 {
397 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
398 this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
399 this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
400 if (this->updown)
401 {
402 free(this->updown);
403 }
404 free(this->name);
405 free(this);
406 }
407 }
408
409 /*
410 * Described in header-file
411 */
412 child_cfg_t *child_cfg_create(char *name, u_int32_t lifetime,
413 u_int32_t rekeytime, u_int32_t jitter,
414 char *updown, bool hostaccess, mode_t mode)
415 {
416 private_child_cfg_t *this = malloc_thing(private_child_cfg_t);
417
418 /* public functions */
419 this->public.get_name = (char* (*) (child_cfg_t*))get_name;
420 this->public.add_traffic_selector = (void (*)(child_cfg_t*,bool,traffic_selector_t*))add_traffic_selector;
421 this->public.get_traffic_selectors = (linked_list_t*(*)(child_cfg_t*,bool,linked_list_t*,host_t*))get_traffic_selectors;
422 this->public.add_proposal = (void (*) (child_cfg_t*,proposal_t*))add_proposal;
423 this->public.get_proposals = (linked_list_t* (*) (child_cfg_t*,bool))get_proposals;
424 this->public.select_proposal = (proposal_t* (*) (child_cfg_t*,linked_list_t*,bool))select_proposal;
425 this->public.get_updown = (char* (*) (child_cfg_t*))get_updown;
426 this->public.get_hostaccess = (bool (*) (child_cfg_t*))get_hostaccess;
427 this->public.get_mode = (mode_t (*) (child_cfg_t *))get_mode;
428 this->public.get_lifetime = (u_int32_t (*) (child_cfg_t *,bool))get_lifetime;
429 this->public.get_dh_group = (diffie_hellman_group_t(*)(child_cfg_t*)) get_dh_group;
430 this->public.get_ref = (void (*) (child_cfg_t*))get_ref;
431 this->public.destroy = (void (*) (child_cfg_t*))destroy;
432
433 /* apply init values */
434 this->name = strdup(name);
435 this->lifetime = lifetime;
436 this->rekeytime = rekeytime;
437 this->jitter = jitter;
438 this->updown = updown ? strdup(updown) : NULL;
439 this->hostaccess = hostaccess;
440 this->mode = mode;
441
442 /* initialize private members*/
443 this->refcount = 1;
444 this->proposals = linked_list_create();
445 this->my_ts = linked_list_create();
446 this->other_ts = linked_list_create();
447
448 return &this->public;
449 }