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