2 * Copyright (C) 2005-2007 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
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>.
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
19 #include "child_cfg.h"
23 ENUM(mode_names
, MODE_TRANSPORT
, MODE_BEET
,
31 ENUM(action_names
, ACTION_NONE
, ACTION_RESTART
,
37 typedef struct private_child_cfg_t private_child_cfg_t
;
40 * Private data of an child_cfg_t object
42 struct private_child_cfg_t
{
50 * Number of references hold by others to this child_cfg
55 * Name of the child_cfg, used to query it
60 * list for all proposals
62 linked_list_t
*proposals
;
65 * list for traffic selectors for my site
70 * list for traffic selectors for others site
72 linked_list_t
*other_ts
;
85 * Mode to propose for a initiated CHILD: tunnel/transport
90 * action to take on DPD
95 * action to take on CHILD_SA close
97 action_t close_action
;
100 * Time before an SA gets invalid
105 * Time before an SA gets rekeyed
110 * Time, which specifies the range of a random value
111 * substracted from rekeytime.
117 * Implementation of child_cfg_t.get_name
119 static char *get_name(private_child_cfg_t
*this)
125 * Implementation of child_cfg_t.add_proposal
127 static void add_proposal(private_child_cfg_t
*this, proposal_t
*proposal
)
129 this->proposals
->insert_last(this->proposals
, proposal
);
133 * Implementation of child_cfg_t.get_proposals
135 static linked_list_t
* get_proposals(private_child_cfg_t
*this, bool strip_dh
)
137 enumerator_t
*enumerator
;
139 linked_list_t
*proposals
= linked_list_create();
141 enumerator
= this->proposals
->create_enumerator(this->proposals
);
142 while (enumerator
->enumerate(enumerator
, ¤t
))
144 current
= current
->clone(current
);
147 current
->strip_dh(current
);
149 proposals
->insert_last(proposals
, current
);
151 enumerator
->destroy(enumerator
);
157 * Implementation of child_cfg_t.get_name
159 static proposal_t
* select_proposal(private_child_cfg_t
*this,
160 linked_list_t
*proposals
, bool strip_dh
)
162 enumerator_t
*stored_enum
, *supplied_enum
;
163 proposal_t
*stored
, *supplied
, *selected
= NULL
;
165 stored_enum
= this->proposals
->create_enumerator(this->proposals
);
166 supplied_enum
= proposals
->create_enumerator(proposals
);
168 /* compare all stored proposals with all supplied. Stored ones are preferred. */
169 while (stored_enum
->enumerate(stored_enum
, &stored
))
171 stored
= stored
->clone(stored
);
172 while (supplied_enum
->enumerate(supplied_enum
, &supplied
))
176 stored
->strip_dh(stored
);
178 selected
= stored
->select(stored
, supplied
);
184 stored
->destroy(stored
);
189 supplied_enum
->destroy(supplied_enum
);
190 supplied_enum
= proposals
->create_enumerator(proposals
);
192 stored_enum
->destroy(stored_enum
);
193 supplied_enum
->destroy(supplied_enum
);
198 * Implementation of child_cfg_t.get_name
200 static void add_traffic_selector(private_child_cfg_t
*this, bool local
,
201 traffic_selector_t
*ts
)
205 this->my_ts
->insert_last(this->my_ts
, ts
);
209 this->other_ts
->insert_last(this->other_ts
, ts
);
214 * Implementation of child_cfg_t.get_name
216 static linked_list_t
* get_traffic_selectors(private_child_cfg_t
*this, bool local
,
217 linked_list_t
*supplied
,
220 enumerator_t
*e1
, *e2
;
221 traffic_selector_t
*ts1
, *ts2
, *selected
;
222 linked_list_t
*result
= linked_list_create();
226 e1
= this->my_ts
->create_enumerator(this->my_ts
);
230 e1
= this->other_ts
->create_enumerator(this->other_ts
);
233 /* no list supplied, just fetch the stored traffic selectors */
234 if (supplied
== NULL
)
236 DBG2(DBG_CFG
, "proposing traffic selectors for %s:",
237 local ?
"us" : "other");
238 while (e1
->enumerate(e1
, &ts1
))
240 /* we make a copy of the TS, this allows us to update dynamic TS' */
241 selected
= ts1
->clone(ts1
);
244 selected
->set_address(selected
, host
);
246 DBG2(DBG_CFG
, " %R (derived from %R)", selected
, ts1
);
247 result
->insert_last(result
, selected
);
253 DBG2(DBG_CFG
, "selecting traffic selectors for %s:",
254 local ?
"us" : "other");
255 e2
= supplied
->create_enumerator(supplied
);
256 /* iterate over all stored selectors */
257 while (e1
->enumerate(e1
, &ts1
))
259 /* we make a copy of the TS, as we have to update dynamic TS' */
260 ts1
= ts1
->clone(ts1
);
263 ts1
->set_address(ts1
, host
);
266 /* iterate over all supplied traffic selectors */
267 while (e2
->enumerate(e2
, &ts2
))
269 selected
= ts1
->get_subset(ts1
, ts2
);
272 DBG2(DBG_CFG
, " config: %R, received: %R => match: %R",
274 result
->insert_last(result
, selected
);
278 DBG2(DBG_CFG
, " config: %R, received: %R => no match",
283 e2
= supplied
->create_enumerator(supplied
);
290 /* remove any redundant traffic selectors in the list */
291 e1
= result
->create_enumerator(result
);
292 e2
= result
->create_enumerator(result
);
293 while (e1
->enumerate(e1
, &ts1
))
295 while (e2
->enumerate(e2
, &ts2
))
299 if (ts2
->is_contained_in(ts2
, ts1
))
301 result
->remove_at(result
, e2
);
304 e1
= result
->create_enumerator(result
);
307 if (ts1
->is_contained_in(ts1
, ts2
))
309 result
->remove_at(result
, e1
);
312 e2
= result
->create_enumerator(result
);
325 * Implementation of child_cfg_t.get_name
327 static char* get_updown(private_child_cfg_t
*this)
333 * Implementation of child_cfg_t.get_name
335 static bool get_hostaccess(private_child_cfg_t
*this)
337 return this->hostaccess
;
341 * Implementation of child_cfg_t.get_name
343 static u_int32_t
get_lifetime(private_child_cfg_t
*this, bool rekey
)
347 if (this->jitter
== 0)
349 return this->rekeytime
;
351 return this->rekeytime
- (random() % this->jitter
);
353 return this->lifetime
;
357 * Implementation of child_cfg_t.get_mode
359 static mode_t
get_mode(private_child_cfg_t
*this)
365 * Implementation of child_cfg_t.get_dpd_action
367 static action_t
get_dpd_action(private_child_cfg_t
*this)
369 return this->dpd_action
;
373 * Implementation of child_cfg_t.get_close_action
375 static action_t
get_close_action(private_child_cfg_t
*this)
377 return this->close_action
;
381 * Implementation of child_cfg_t.get_dh_group.
383 static diffie_hellman_group_t
get_dh_group(private_child_cfg_t
*this)
385 enumerator_t
*enumerator
;
386 proposal_t
*proposal
;
387 u_int16_t dh_group
= MODP_NONE
;
389 enumerator
= this->proposals
->create_enumerator(this->proposals
);
390 while (enumerator
->enumerate(enumerator
, &proposal
))
392 if (proposal
->get_algorithm(proposal
, DIFFIE_HELLMAN_GROUP
, &dh_group
, NULL
))
397 enumerator
->destroy(enumerator
);
402 * Implementation of child_cfg_t.get_name
404 static void get_ref(private_child_cfg_t
*this)
406 ref_get(&this->refcount
);
410 * Implements child_cfg_t.destroy.
412 static void destroy(private_child_cfg_t
*this)
414 if (ref_put(&this->refcount
))
416 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
417 this->my_ts
->destroy_offset(this->my_ts
, offsetof(traffic_selector_t
, destroy
));
418 this->other_ts
->destroy_offset(this->other_ts
, offsetof(traffic_selector_t
, destroy
));
429 * Described in header-file
431 child_cfg_t
*child_cfg_create(char *name
, u_int32_t lifetime
,
432 u_int32_t rekeytime
, u_int32_t jitter
,
433 char *updown
, bool hostaccess
, mode_t mode
,
434 action_t dpd_action
, action_t close_action
)
436 private_child_cfg_t
*this = malloc_thing(private_child_cfg_t
);
438 this->public.get_name
= (char* (*) (child_cfg_t
*))get_name
;
439 this->public.add_traffic_selector
= (void (*)(child_cfg_t
*,bool,traffic_selector_t
*))add_traffic_selector
;
440 this->public.get_traffic_selectors
= (linked_list_t
*(*)(child_cfg_t
*,bool,linked_list_t
*,host_t
*))get_traffic_selectors
;
441 this->public.add_proposal
= (void (*) (child_cfg_t
*,proposal_t
*))add_proposal
;
442 this->public.get_proposals
= (linked_list_t
* (*) (child_cfg_t
*,bool))get_proposals
;
443 this->public.select_proposal
= (proposal_t
* (*) (child_cfg_t
*,linked_list_t
*,bool))select_proposal
;
444 this->public.get_updown
= (char* (*) (child_cfg_t
*))get_updown
;
445 this->public.get_hostaccess
= (bool (*) (child_cfg_t
*))get_hostaccess
;
446 this->public.get_mode
= (mode_t (*) (child_cfg_t
*))get_mode
;
447 this->public.get_dpd_action
= (action_t (*) (child_cfg_t
*))get_dpd_action
;
448 this->public.get_close_action
= (action_t (*) (child_cfg_t
*))get_close_action
;
449 this->public.get_lifetime
= (u_int32_t (*) (child_cfg_t
*,bool))get_lifetime
;
450 this->public.get_dh_group
= (diffie_hellman_group_t(*)(child_cfg_t
*)) get_dh_group
;
451 this->public.get_ref
= (void (*) (child_cfg_t
*))get_ref
;
452 this->public.destroy
= (void (*) (child_cfg_t
*))destroy
;
454 this->name
= strdup(name
);
455 this->lifetime
= lifetime
;
456 this->rekeytime
= rekeytime
;
457 this->jitter
= jitter
;
458 this->updown
= updown ?
strdup(updown
) : NULL
;
459 this->hostaccess
= hostaccess
;
461 this->dpd_action
= dpd_action
;
462 this->close_action
= close_action
;
464 this->proposals
= linked_list_create();
465 this->my_ts
= linked_list_create();
466 this->other_ts
= linked_list_create();
468 return &this->public;