2 * Copyright (C) 2007-2015 Tobias Brunner
3 * Copyright (C) 2005-2009 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
24 #include <threading/mutex.h>
25 #include <collections/linked_list.h>
26 #include <utils/identification.h>
28 ENUM(cert_policy_names
, CERT_ALWAYS_SEND
, CERT_NEVER_SEND
,
34 ENUM(unique_policy_names
, UNIQUE_NEVER
, UNIQUE_KEEP
,
41 typedef struct private_peer_cfg_t private_peer_cfg_t
;
44 * Private data of an peer_cfg_t object
46 struct private_peer_cfg_t
{
54 * Number of references hold by others to this peer_cfg
59 * Name of the peer_cfg, used to query it
64 * IKE config associated to this peer config
69 * list of child configs associated to this peer config
71 linked_list_t
*child_cfgs
;
74 * mutex to lock access to list of child_cfgs
79 * should we send a certificate
81 cert_policy_t cert_policy
;
84 * uniqueness of an IKE_SA
86 unique_policy_t unique
;
89 * number of tries after giving up if peer does not respond
94 * enable support for MOBIKE
99 * Use aggressive mode?
104 * Use pull or push in mode config?
109 * Time before starting rekeying
114 * Time before starting reauthentication
116 uint32_t reauth_time
;
119 * Time, which specifies the range of a random value subtracted from above.
121 uint32_t jitter_time
;
124 * Delay before deleting a rekeying/reauthenticating SA
129 * DPD check intervall
134 * DPD timeout intervall (used for IKEv1 only)
136 uint32_t dpd_timeout
;
139 * List of virtual IPs (host_t*) to request
144 * List of pool names to use for virtual IP lookup
146 linked_list_t
*pools
;
149 * local authentication configs (rulesets)
151 linked_list_t
*local_auth
;
154 * remote authentication configs (constraints)
156 linked_list_t
*remote_auth
;
160 * Is this a mediation connection?
165 * Name of the mediation connection to mediate through
167 peer_cfg_t
*mediated_by
;
170 * ID of our peer at the mediation server (= leftid of the peer's conn with
171 * the mediation server)
173 identification_t
*peer_id
;
177 METHOD(peer_cfg_t
, get_name
, char*,
178 private_peer_cfg_t
*this)
183 METHOD(peer_cfg_t
, get_ike_version
, ike_version_t
,
184 private_peer_cfg_t
*this)
186 return this->ike_cfg
->get_version(this->ike_cfg
);
189 METHOD(peer_cfg_t
, get_ike_cfg
, ike_cfg_t
*,
190 private_peer_cfg_t
*this)
192 return this->ike_cfg
;
195 METHOD(peer_cfg_t
, add_child_cfg
, void,
196 private_peer_cfg_t
*this, child_cfg_t
*child_cfg
)
198 this->mutex
->lock(this->mutex
);
199 this->child_cfgs
->insert_last(this->child_cfgs
, child_cfg
);
200 this->mutex
->unlock(this->mutex
);
205 linked_list_t
*removed
;
206 linked_list_t
*added
;
207 enumerator_t
*wrapped
;
209 } child_cfgs_replace_enumerator_t
;
211 METHOD(enumerator_t
, child_cfgs_replace_enumerate
, bool,
212 child_cfgs_replace_enumerator_t
*this, child_cfg_t
**chd
, bool *added
)
214 child_cfg_t
*child_cfg
;
218 this->wrapped
= this->removed
->create_enumerator(this->removed
);
222 if (this->wrapped
->enumerate(this->wrapped
, &child_cfg
))
238 this->wrapped
= this->added
->create_enumerator(this->added
);
244 METHOD(enumerator_t
, child_cfgs_replace_enumerator_destroy
, void,
245 child_cfgs_replace_enumerator_t
*this)
247 DESTROY_IF(this->wrapped
);
248 this->removed
->destroy_offset(this->removed
, offsetof(child_cfg_t
, destroy
));
249 this->added
->destroy_offset(this->added
, offsetof(child_cfg_t
, destroy
));
253 METHOD(peer_cfg_t
, replace_child_cfgs
, enumerator_t
*,
254 private_peer_cfg_t
*this, peer_cfg_t
*other_pub
)
256 private_peer_cfg_t
*other
= (private_peer_cfg_t
*)other_pub
;
257 linked_list_t
*removed
, *added
;
258 enumerator_t
*mine
, *others
;
259 child_cfg_t
*my_cfg
, *other_cfg
;
260 child_cfgs_replace_enumerator_t
*enumerator
;
263 removed
= linked_list_create();
265 other
->mutex
->lock(other
->mutex
);
266 added
= linked_list_create_from_enumerator(
267 other
->child_cfgs
->create_enumerator(other
->child_cfgs
));
268 added
->invoke_offset(added
, offsetof(child_cfg_t
, get_ref
));
269 other
->mutex
->unlock(other
->mutex
);
271 this->mutex
->lock(this->mutex
);
272 others
= added
->create_enumerator(added
);
273 mine
= this->child_cfgs
->create_enumerator(this->child_cfgs
);
274 while (mine
->enumerate(mine
, &my_cfg
))
277 while (others
->enumerate(others
, &other_cfg
))
279 if (my_cfg
->equals(my_cfg
, other_cfg
))
281 added
->remove_at(added
, others
);
282 other_cfg
->destroy(other_cfg
);
287 added
->reset_enumerator(added
, others
);
290 this->child_cfgs
->remove_at(this->child_cfgs
, mine
);
291 removed
->insert_last(removed
, my_cfg
);
294 while (others
->enumerate(others
, &other_cfg
))
296 this->child_cfgs
->insert_last(this->child_cfgs
,
297 other_cfg
->get_ref(other_cfg
));
299 others
->destroy(others
);
301 this->mutex
->unlock(this->mutex
);
305 .enumerate
= (void*)_child_cfgs_replace_enumerate
,
306 .destroy
= (void*)_child_cfgs_replace_enumerator_destroy
,
311 return &enumerator
->public;
315 * child_cfg enumerator
319 enumerator_t
*wrapped
;
321 } child_cfg_enumerator_t
;
323 METHOD(peer_cfg_t
, remove_child_cfg
, void,
324 private_peer_cfg_t
*this, child_cfg_enumerator_t
*enumerator
)
326 this->child_cfgs
->remove_at(this->child_cfgs
, enumerator
->wrapped
);
329 METHOD(enumerator_t
, child_cfg_enumerator_destroy
, void,
330 child_cfg_enumerator_t
*this)
332 this->mutex
->unlock(this->mutex
);
333 this->wrapped
->destroy(this->wrapped
);
337 METHOD(enumerator_t
, child_cfg_enumerate
, bool,
338 child_cfg_enumerator_t
*this, child_cfg_t
**chd
)
340 return this->wrapped
->enumerate(this->wrapped
, chd
);
343 METHOD(peer_cfg_t
, create_child_cfg_enumerator
, enumerator_t
*,
344 private_peer_cfg_t
*this)
346 child_cfg_enumerator_t
*enumerator
;
350 .enumerate
= (void*)_child_cfg_enumerate
,
351 .destroy
= (void*)_child_cfg_enumerator_destroy
,
353 .mutex
= this->mutex
,
354 .wrapped
= this->child_cfgs
->create_enumerator(this->child_cfgs
),
357 this->mutex
->lock(this->mutex
);
358 return &enumerator
->public;
362 * Check how good a list of TS matches a given child config
364 static int get_ts_match(child_cfg_t
*cfg
, bool local
,
365 linked_list_t
*sup_list
, linked_list_t
*hosts
)
367 linked_list_t
*cfg_list
;
368 enumerator_t
*sup_enum
, *cfg_enum
;
369 traffic_selector_t
*sup_ts
, *cfg_ts
, *subset
;
370 int match
= 0, round
;
372 /* fetch configured TS list, narrowing dynamic TS */
373 cfg_list
= cfg
->get_traffic_selectors(cfg
, local
, NULL
, hosts
);
375 /* use a round counter to rate leading TS with higher priority */
376 round
= sup_list
->get_count(sup_list
);
378 sup_enum
= sup_list
->create_enumerator(sup_list
);
379 while (sup_enum
->enumerate(sup_enum
, &sup_ts
))
381 cfg_enum
= cfg_list
->create_enumerator(cfg_list
);
382 while (cfg_enum
->enumerate(cfg_enum
, &cfg_ts
))
384 if (cfg_ts
->equals(cfg_ts
, sup_ts
))
385 { /* equality is honored better than matches */
390 subset
= cfg_ts
->get_subset(cfg_ts
, sup_ts
);
393 subset
->destroy(subset
);
398 cfg_enum
->destroy(cfg_enum
);
401 sup_enum
->destroy(sup_enum
);
403 cfg_list
->destroy_offset(cfg_list
, offsetof(traffic_selector_t
, destroy
));
408 METHOD(peer_cfg_t
, select_child_cfg
, child_cfg_t
*,
409 private_peer_cfg_t
*this, linked_list_t
*my_ts
, linked_list_t
*other_ts
,
410 linked_list_t
*my_hosts
, linked_list_t
*other_hosts
)
412 child_cfg_t
*current
, *found
= NULL
;
413 enumerator_t
*enumerator
;
416 DBG2(DBG_CFG
, "looking for a child config for %#R === %#R", my_ts
, other_ts
);
417 enumerator
= create_child_cfg_enumerator(this);
418 while (enumerator
->enumerate(enumerator
, ¤t
))
420 int my_prio
, other_prio
;
422 my_prio
= get_ts_match(current
, TRUE
, my_ts
, my_hosts
);
423 other_prio
= get_ts_match(current
, FALSE
, other_ts
, other_hosts
);
425 if (my_prio
&& other_prio
)
427 DBG2(DBG_CFG
, " candidate \"%s\" with prio %d+%d",
428 current
->get_name(current
), my_prio
, other_prio
);
429 if (my_prio
+ other_prio
> best
)
431 best
= my_prio
+ other_prio
;
433 found
= current
->get_ref(current
);
437 enumerator
->destroy(enumerator
);
440 DBG2(DBG_CFG
, "found matching child config \"%s\" with prio %d",
441 found
->get_name(found
), best
);
446 METHOD(peer_cfg_t
, get_cert_policy
, cert_policy_t
,
447 private_peer_cfg_t
*this)
449 return this->cert_policy
;
452 METHOD(peer_cfg_t
, get_unique_policy
, unique_policy_t
,
453 private_peer_cfg_t
*this)
458 METHOD(peer_cfg_t
, get_keyingtries
, uint32_t,
459 private_peer_cfg_t
*this)
461 return this->keyingtries
;
464 METHOD(peer_cfg_t
, get_rekey_time
, uint32_t,
465 private_peer_cfg_t
*this, bool jitter
)
467 if (this->rekey_time
== 0)
471 if (this->jitter_time
== 0 || !jitter
)
473 return this->rekey_time
;
475 return this->rekey_time
- (random() % this->jitter_time
);
478 METHOD(peer_cfg_t
, get_reauth_time
, uint32_t,
479 private_peer_cfg_t
*this, bool jitter
)
481 if (this->reauth_time
== 0)
485 if (this->jitter_time
== 0 || !jitter
)
487 return this->reauth_time
;
489 return this->reauth_time
- (random() % this->jitter_time
);
492 METHOD(peer_cfg_t
, get_over_time
, uint32_t,
493 private_peer_cfg_t
*this)
495 return this->over_time
;
498 METHOD(peer_cfg_t
, use_mobike
, bool,
499 private_peer_cfg_t
*this)
501 return this->use_mobike
;
504 METHOD(peer_cfg_t
, use_aggressive
, bool,
505 private_peer_cfg_t
*this)
507 return this->aggressive
;
510 METHOD(peer_cfg_t
, use_pull_mode
, bool,
511 private_peer_cfg_t
*this)
513 return this->pull_mode
;
516 METHOD(peer_cfg_t
, get_dpd
, uint32_t,
517 private_peer_cfg_t
*this)
522 METHOD(peer_cfg_t
, get_dpd_timeout
, uint32_t,
523 private_peer_cfg_t
*this)
525 return this->dpd_timeout
;
528 METHOD(peer_cfg_t
, add_virtual_ip
, void,
529 private_peer_cfg_t
*this, host_t
*vip
)
531 this->vips
->insert_last(this->vips
, vip
);
534 METHOD(peer_cfg_t
, create_virtual_ip_enumerator
, enumerator_t
*,
535 private_peer_cfg_t
*this)
537 return this->vips
->create_enumerator(this->vips
);
540 METHOD(peer_cfg_t
, add_pool
, void,
541 private_peer_cfg_t
*this, char *name
)
543 this->pools
->insert_last(this->pools
, strdup(name
));
546 METHOD(peer_cfg_t
, create_pool_enumerator
, enumerator_t
*,
547 private_peer_cfg_t
*this)
549 return this->pools
->create_enumerator(this->pools
);
552 METHOD(peer_cfg_t
, add_auth_cfg
, void,
553 private_peer_cfg_t
*this, auth_cfg_t
*cfg
, bool local
)
557 this->local_auth
->insert_last(this->local_auth
, cfg
);
561 this->remote_auth
->insert_last(this->remote_auth
, cfg
);
565 METHOD(peer_cfg_t
, create_auth_cfg_enumerator
, enumerator_t
*,
566 private_peer_cfg_t
*this, bool local
)
570 return this->local_auth
->create_enumerator(this->local_auth
);
572 return this->remote_auth
->create_enumerator(this->remote_auth
);
576 METHOD(peer_cfg_t
, is_mediation
, bool,
577 private_peer_cfg_t
*this)
579 return this->mediation
;
582 METHOD(peer_cfg_t
, get_mediated_by
, peer_cfg_t
*,
583 private_peer_cfg_t
*this)
585 return this->mediated_by
;
588 METHOD(peer_cfg_t
, get_peer_id
, identification_t
*,
589 private_peer_cfg_t
*this)
591 return this->peer_id
;
596 * check auth configs for equality
598 static bool auth_cfg_equal(private_peer_cfg_t
*this, private_peer_cfg_t
*other
)
600 enumerator_t
*e1
, *e2
;
601 auth_cfg_t
*cfg1
, *cfg2
;
604 if (this->local_auth
->get_count(this->local_auth
) !=
605 other
->local_auth
->get_count(other
->local_auth
))
609 if (this->remote_auth
->get_count(this->remote_auth
) !=
610 other
->remote_auth
->get_count(other
->remote_auth
))
615 e1
= this->local_auth
->create_enumerator(this->local_auth
);
616 e2
= other
->local_auth
->create_enumerator(other
->local_auth
);
617 while (e1
->enumerate(e1
, &cfg1
) && e2
->enumerate(e2
, &cfg2
))
619 if (!cfg1
->equals(cfg1
, cfg2
))
633 e1
= this->remote_auth
->create_enumerator(this->remote_auth
);
634 e2
= other
->remote_auth
->create_enumerator(other
->remote_auth
);
635 while (e1
->enumerate(e1
, &cfg1
) && e2
->enumerate(e2
, &cfg2
))
637 if (!cfg1
->equals(cfg1
, cfg2
))
649 METHOD(peer_cfg_t
, equals
, bool,
650 private_peer_cfg_t
*this, private_peer_cfg_t
*other
)
656 if (this->public.equals
!= other
->public.equals
)
660 if (!this->vips
->equals_offset(this->vips
, other
->vips
,
661 offsetof(host_t
, ip_equals
)))
665 if (!this->pools
->equals_function(this->pools
, other
->pools
, (void*)streq
))
670 get_ike_version(this) == get_ike_version(other
) &&
671 this->cert_policy
== other
->cert_policy
&&
672 this->unique
== other
->unique
&&
673 this->keyingtries
== other
->keyingtries
&&
674 this->use_mobike
== other
->use_mobike
&&
675 this->rekey_time
== other
->rekey_time
&&
676 this->reauth_time
== other
->reauth_time
&&
677 this->jitter_time
== other
->jitter_time
&&
678 this->over_time
== other
->over_time
&&
679 this->dpd
== other
->dpd
&&
680 this->aggressive
== other
->aggressive
&&
681 this->pull_mode
== other
->pull_mode
&&
682 auth_cfg_equal(this, other
)
684 && this->mediation
== other
->mediation
&&
685 this->mediated_by
== other
->mediated_by
&&
686 (this->peer_id
== other
->peer_id
||
687 (this->peer_id
&& other
->peer_id
&&
688 this->peer_id
->equals(this->peer_id
, other
->peer_id
)))
693 METHOD(peer_cfg_t
, get_ref
, peer_cfg_t
*,
694 private_peer_cfg_t
*this)
696 ref_get(&this->refcount
);
697 return &this->public;
700 METHOD(peer_cfg_t
, destroy
, void,
701 private_peer_cfg_t
*this)
703 if (ref_put(&this->refcount
))
705 this->ike_cfg
->destroy(this->ike_cfg
);
706 this->child_cfgs
->destroy_offset(this->child_cfgs
,
707 offsetof(child_cfg_t
, destroy
));
708 this->local_auth
->destroy_offset(this->local_auth
,
709 offsetof(auth_cfg_t
, destroy
));
710 this->remote_auth
->destroy_offset(this->remote_auth
,
711 offsetof(auth_cfg_t
, destroy
));
712 this->vips
->destroy_offset(this->vips
, offsetof(host_t
, destroy
));
713 this->pools
->destroy_function(this->pools
, free
);
715 DESTROY_IF(this->mediated_by
);
716 DESTROY_IF(this->peer_id
);
718 this->mutex
->destroy(this->mutex
);
725 * Described in header-file
727 peer_cfg_t
*peer_cfg_create(char *name
,
728 ike_cfg_t
*ike_cfg
, cert_policy_t cert_policy
,
729 unique_policy_t unique
, uint32_t keyingtries
,
730 uint32_t rekey_time
, uint32_t reauth_time
,
731 uint32_t jitter_time
, uint32_t over_time
,
732 bool mobike
, bool aggressive
, bool pull_mode
,
733 uint32_t dpd
, uint32_t dpd_timeout
,
734 bool mediation
, peer_cfg_t
*mediated_by
,
735 identification_t
*peer_id
)
737 private_peer_cfg_t
*this;
739 if (rekey_time
&& jitter_time
> rekey_time
)
741 jitter_time
= rekey_time
;
743 if (reauth_time
&& jitter_time
> reauth_time
)
745 jitter_time
= reauth_time
;
747 if (dpd
&& dpd_timeout
&& dpd
> dpd_timeout
)
754 .get_name
= _get_name
,
755 .get_ike_version
= _get_ike_version
,
756 .get_ike_cfg
= _get_ike_cfg
,
757 .add_child_cfg
= _add_child_cfg
,
758 .remove_child_cfg
= (void*)_remove_child_cfg
,
759 .replace_child_cfgs
= _replace_child_cfgs
,
760 .create_child_cfg_enumerator
= _create_child_cfg_enumerator
,
761 .select_child_cfg
= _select_child_cfg
,
762 .get_cert_policy
= _get_cert_policy
,
763 .get_unique_policy
= _get_unique_policy
,
764 .get_keyingtries
= _get_keyingtries
,
765 .get_rekey_time
= _get_rekey_time
,
766 .get_reauth_time
= _get_reauth_time
,
767 .get_over_time
= _get_over_time
,
768 .use_mobike
= _use_mobike
,
769 .use_aggressive
= _use_aggressive
,
770 .use_pull_mode
= _use_pull_mode
,
772 .get_dpd_timeout
= _get_dpd_timeout
,
773 .add_virtual_ip
= _add_virtual_ip
,
774 .create_virtual_ip_enumerator
= _create_virtual_ip_enumerator
,
775 .add_pool
= _add_pool
,
776 .create_pool_enumerator
= _create_pool_enumerator
,
777 .add_auth_cfg
= _add_auth_cfg
,
778 .create_auth_cfg_enumerator
= _create_auth_cfg_enumerator
,
779 .equals
= (void*)_equals
,
783 .is_mediation
= _is_mediation
,
784 .get_mediated_by
= _get_mediated_by
,
785 .get_peer_id
= _get_peer_id
,
788 .name
= strdup(name
),
790 .child_cfgs
= linked_list_create(),
791 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
792 .cert_policy
= cert_policy
,
794 .keyingtries
= keyingtries
,
795 .rekey_time
= rekey_time
,
796 .reauth_time
= reauth_time
,
797 .jitter_time
= jitter_time
,
798 .over_time
= over_time
,
799 .use_mobike
= mobike
,
800 .aggressive
= aggressive
,
801 .pull_mode
= pull_mode
,
803 .dpd_timeout
= dpd_timeout
,
804 .vips
= linked_list_create(),
805 .pools
= linked_list_create(),
806 .local_auth
= linked_list_create(),
807 .remote_auth
= linked_list_create(),
812 this->mediation
= mediation
;
813 this->mediated_by
= mediated_by
;
814 this->peer_id
= peer_id
;
816 DESTROY_IF(mediated_by
);
820 return &this->public;