2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include "child_cfg.h"
24 ENUM(action_names
, ACTION_NONE
, ACTION_RESTART
,
30 typedef struct private_child_cfg_t private_child_cfg_t
;
33 * Private data of an child_cfg_t object
35 struct private_child_cfg_t
{
43 * Number of references hold by others to this child_cfg
48 * Name of the child_cfg, used to query it
53 * list for all proposals
55 linked_list_t
*proposals
;
58 * list for traffic selectors for my site
63 * list for traffic selectors for others site
65 linked_list_t
*other_ts
;
78 * Mode to propose for a initiated CHILD: tunnel/transport
83 * action to take to start CHILD_SA
85 action_t start_action
;
88 * action to take on DPD
93 * action to take on CHILD_SA close
95 action_t close_action
;
98 * CHILD_SA lifetime config
100 lifetime_cfg_t lifetime
;
110 u_int32_t inactivity
;
113 * Reqid to install CHILD_SA with
118 * Optional mark to install inbound CHILD_SA with
123 * Optional mark to install outbound CHILD_SA with
128 * Traffic Flow Confidentiality padding, if enabled
133 * set up IPsec transport SA in MIPv6 proxy mode
138 * enable installation and removal of kernel IPsec policies
143 METHOD(child_cfg_t
, get_name
, char*,
144 private_child_cfg_t
*this)
149 METHOD(child_cfg_t
, add_proposal
, void,
150 private_child_cfg_t
*this, proposal_t
*proposal
)
152 this->proposals
->insert_last(this->proposals
, proposal
);
155 METHOD(child_cfg_t
, get_proposals
, linked_list_t
*,
156 private_child_cfg_t
*this, bool strip_dh
)
158 enumerator_t
*enumerator
;
160 linked_list_t
*proposals
= linked_list_create();
162 enumerator
= this->proposals
->create_enumerator(this->proposals
);
163 while (enumerator
->enumerate(enumerator
, ¤t
))
165 current
= current
->clone(current
);
168 current
->strip_dh(current
, MODP_NONE
);
170 proposals
->insert_last(proposals
, current
);
172 enumerator
->destroy(enumerator
);
174 DBG2(DBG_CFG
, "configured proposals: %#P", proposals
);
179 METHOD(child_cfg_t
, select_proposal
, proposal_t
*,
180 private_child_cfg_t
*this, linked_list_t
*proposals
, bool strip_dh
,
183 enumerator_t
*stored_enum
, *supplied_enum
;
184 proposal_t
*stored
, *supplied
, *selected
= NULL
;
186 stored_enum
= this->proposals
->create_enumerator(this->proposals
);
187 supplied_enum
= proposals
->create_enumerator(proposals
);
189 /* compare all stored proposals with all supplied. Stored ones are preferred. */
190 while (stored_enum
->enumerate(stored_enum
, &stored
))
192 stored
= stored
->clone(stored
);
193 while (supplied_enum
->enumerate(supplied_enum
, &supplied
))
197 stored
->strip_dh(stored
, MODP_NONE
);
199 selected
= stored
->select(stored
, supplied
, private);
202 DBG2(DBG_CFG
, "received proposals: %#P", proposals
);
203 DBG2(DBG_CFG
, "configured proposals: %#P", this->proposals
);
204 DBG2(DBG_CFG
, "selected proposal: %P", selected
);
208 stored
->destroy(stored
);
213 supplied_enum
->destroy(supplied_enum
);
214 supplied_enum
= proposals
->create_enumerator(proposals
);
216 stored_enum
->destroy(stored_enum
);
217 supplied_enum
->destroy(supplied_enum
);
218 if (selected
== NULL
)
220 DBG1(DBG_CFG
, "received proposals: %#P", proposals
);
221 DBG1(DBG_CFG
, "configured proposals: %#P", this->proposals
);
226 METHOD(child_cfg_t
, add_traffic_selector
, void,
227 private_child_cfg_t
*this, bool local
, traffic_selector_t
*ts
)
231 this->my_ts
->insert_last(this->my_ts
, ts
);
235 this->other_ts
->insert_last(this->other_ts
, ts
);
239 METHOD(child_cfg_t
, get_traffic_selectors
, linked_list_t
*,
240 private_child_cfg_t
*this, bool local
, linked_list_t
*supplied
,
241 linked_list_t
*hosts
)
243 enumerator_t
*e1
, *e2
;
244 traffic_selector_t
*ts1
, *ts2
, *selected
;
245 linked_list_t
*result
, *derived
;
248 result
= linked_list_create();
249 derived
= linked_list_create();
252 e1
= this->my_ts
->create_enumerator(this->my_ts
);
256 e1
= this->other_ts
->create_enumerator(this->other_ts
);
258 /* In a first step, replace "dynamic" TS with the host list */
259 while (e1
->enumerate(e1
, &ts1
))
261 if (hosts
&& hosts
->get_count(hosts
) &&
262 ts1
->is_dynamic(ts1
))
264 e2
= hosts
->create_enumerator(hosts
);
265 while (e2
->enumerate(e2
, &host
))
267 ts2
= ts1
->clone(ts1
);
268 ts2
->set_address(ts2
, host
);
269 derived
->insert_last(derived
, ts2
);
275 derived
->insert_last(derived
, ts1
->clone(ts1
));
280 DBG2(DBG_CFG
, "%s traffic selectors for %s:",
281 supplied ?
"selecting" : "proposing", local ?
"us" : "other");
282 if (supplied
== NULL
)
284 while (derived
->remove_first(derived
, (void**)&ts1
) == SUCCESS
)
286 DBG2(DBG_CFG
, " %R", ts1
);
287 result
->insert_last(result
, ts1
);
289 derived
->destroy(derived
);
293 e1
= derived
->create_enumerator(derived
);
294 e2
= supplied
->create_enumerator(supplied
);
295 /* enumerate all configured/derived selectors */
296 while (e1
->enumerate(e1
, &ts1
))
298 /* enumerate all supplied traffic selectors */
299 while (e2
->enumerate(e2
, &ts2
))
301 selected
= ts1
->get_subset(ts1
, ts2
);
304 DBG2(DBG_CFG
, " config: %R, received: %R => match: %R",
306 result
->insert_last(result
, selected
);
310 DBG2(DBG_CFG
, " config: %R, received: %R => no match",
314 supplied
->reset_enumerator(supplied
, e2
);
319 /* check if we/peer did any narrowing, raise alert */
320 e1
= derived
->create_enumerator(derived
);
321 e2
= result
->create_enumerator(result
);
322 while (e1
->enumerate(e1
, &ts1
))
324 if (!e2
->enumerate(e2
, &ts2
) || !ts1
->equals(ts1
, ts2
))
326 charon
->bus
->alert(charon
->bus
, ALERT_TS_NARROWED
,
327 local
, result
, this);
334 derived
->destroy_offset(derived
, offsetof(traffic_selector_t
, destroy
));
337 /* remove any redundant traffic selectors in the list */
338 e1
= result
->create_enumerator(result
);
339 e2
= result
->create_enumerator(result
);
340 while (e1
->enumerate(e1
, &ts1
))
342 while (e2
->enumerate(e2
, &ts2
))
346 if (ts2
->is_contained_in(ts2
, ts1
))
348 result
->remove_at(result
, e2
);
350 result
->reset_enumerator(result
, e1
);
353 if (ts1
->is_contained_in(ts1
, ts2
))
355 result
->remove_at(result
, e1
);
361 result
->reset_enumerator(result
, e2
);
369 METHOD(child_cfg_t
, get_updown
, char*,
370 private_child_cfg_t
*this)
375 METHOD(child_cfg_t
, get_hostaccess
, bool,
376 private_child_cfg_t
*this)
378 return this->hostaccess
;
382 * Applies jitter to the rekey value. Returns the new rekey value.
383 * Note: The distribution of random values is not perfect, but it
384 * should get the job done.
386 static u_int64_t
apply_jitter(u_int64_t rekey
, u_int64_t jitter
)
392 jitter
= (jitter
== UINT64_MAX
) ? jitter
: jitter
+ 1;
393 return rekey
- jitter
* (random() / (RAND_MAX
+ 1.0));
395 #define APPLY_JITTER(l) l.rekey = apply_jitter(l.rekey, l.jitter)
397 METHOD(child_cfg_t
, get_lifetime
, lifetime_cfg_t
*,
398 private_child_cfg_t
*this)
400 lifetime_cfg_t
*lft
= malloc_thing(lifetime_cfg_t
);
401 memcpy(lft
, &this->lifetime
, sizeof(lifetime_cfg_t
));
402 APPLY_JITTER(lft
->time
);
403 APPLY_JITTER(lft
->bytes
);
404 APPLY_JITTER(lft
->packets
);
408 METHOD(child_cfg_t
, get_mode
, ipsec_mode_t
,
409 private_child_cfg_t
*this)
414 METHOD(child_cfg_t
, get_start_action
, action_t
,
415 private_child_cfg_t
*this)
417 return this->start_action
;
420 METHOD(child_cfg_t
, get_dpd_action
, action_t
,
421 private_child_cfg_t
*this)
423 return this->dpd_action
;
426 METHOD(child_cfg_t
, get_close_action
, action_t
,
427 private_child_cfg_t
*this)
429 return this->close_action
;
432 METHOD(child_cfg_t
, get_dh_group
, diffie_hellman_group_t
,
433 private_child_cfg_t
*this)
435 enumerator_t
*enumerator
;
436 proposal_t
*proposal
;
437 u_int16_t dh_group
= MODP_NONE
;
439 enumerator
= this->proposals
->create_enumerator(this->proposals
);
440 while (enumerator
->enumerate(enumerator
, &proposal
))
442 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &dh_group
, NULL
))
447 enumerator
->destroy(enumerator
);
451 METHOD(child_cfg_t
, use_ipcomp
, bool,
452 private_child_cfg_t
*this)
454 return this->use_ipcomp
;
457 METHOD(child_cfg_t
, get_inactivity
, u_int32_t
,
458 private_child_cfg_t
*this)
460 return this->inactivity
;
463 METHOD(child_cfg_t
, get_reqid
, u_int32_t
,
464 private_child_cfg_t
*this)
469 METHOD(child_cfg_t
, get_mark
, mark_t
,
470 private_child_cfg_t
*this, bool inbound
)
472 return inbound ?
this->mark_in
: this->mark_out
;
475 METHOD(child_cfg_t
, get_tfc
, u_int32_t
,
476 private_child_cfg_t
*this)
481 METHOD(child_cfg_t
, set_mipv6_options
, void,
482 private_child_cfg_t
*this, bool proxy_mode
, bool install_policy
)
484 this->proxy_mode
= proxy_mode
;
485 this->install_policy
= install_policy
;
488 METHOD(child_cfg_t
, use_proxy_mode
, bool,
489 private_child_cfg_t
*this)
491 return this->proxy_mode
;
494 METHOD(child_cfg_t
, install_policy
, bool,
495 private_child_cfg_t
*this)
497 return this->install_policy
;
500 METHOD(child_cfg_t
, get_ref
, child_cfg_t
*,
501 private_child_cfg_t
*this)
503 ref_get(&this->refcount
);
504 return &this->public;
507 METHOD(child_cfg_t
, destroy
, void,
508 private_child_cfg_t
*this)
510 if (ref_put(&this->refcount
))
512 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
513 this->my_ts
->destroy_offset(this->my_ts
, offsetof(traffic_selector_t
, destroy
));
514 this->other_ts
->destroy_offset(this->other_ts
, offsetof(traffic_selector_t
, destroy
));
525 * Described in header-file
527 child_cfg_t
*child_cfg_create(char *name
, lifetime_cfg_t
*lifetime
,
528 char *updown
, bool hostaccess
,
529 ipsec_mode_t mode
, action_t start_action
,
530 action_t dpd_action
, action_t close_action
,
531 bool ipcomp
, u_int32_t inactivity
, u_int32_t reqid
,
532 mark_t
*mark_in
, mark_t
*mark_out
, u_int32_t tfc
)
534 private_child_cfg_t
*this;
538 .get_name
= _get_name
,
539 .add_traffic_selector
= _add_traffic_selector
,
540 .get_traffic_selectors
= _get_traffic_selectors
,
541 .add_proposal
= _add_proposal
,
542 .get_proposals
= _get_proposals
,
543 .select_proposal
= _select_proposal
,
544 .get_updown
= _get_updown
,
545 .get_hostaccess
= _get_hostaccess
,
546 .get_mode
= _get_mode
,
547 .get_start_action
= _get_start_action
,
548 .get_dpd_action
= _get_dpd_action
,
549 .get_close_action
= _get_close_action
,
550 .get_lifetime
= _get_lifetime
,
551 .get_dh_group
= _get_dh_group
,
552 .set_mipv6_options
= _set_mipv6_options
,
553 .use_ipcomp
= _use_ipcomp
,
554 .get_inactivity
= _get_inactivity
,
555 .get_reqid
= _get_reqid
,
556 .get_mark
= _get_mark
,
558 .use_proxy_mode
= _use_proxy_mode
,
559 .install_policy
= _install_policy
,
563 .name
= strdup(name
),
564 .updown
= strdupnull(updown
),
565 .hostaccess
= hostaccess
,
567 .start_action
= start_action
,
568 .dpd_action
= dpd_action
,
569 .close_action
= close_action
,
570 .use_ipcomp
= ipcomp
,
571 .inactivity
= inactivity
,
574 .install_policy
= TRUE
,
576 .proposals
= linked_list_create(),
577 .my_ts
= linked_list_create(),
578 .other_ts
= linked_list_create(),
584 this->mark_in
= *mark_in
;
588 this->mark_out
= *mark_out
;
590 memcpy(&this->lifetime
, lifetime
, sizeof(lifetime_cfg_t
));
592 return &this->public;