peer-cfg: Set DPD timeout to at least DPD delay
[strongswan.git] / src / libcharon / config / peer_cfg.c
1 /*
2 * Copyright (C) 2007-2008 Tobias Brunner
3 * Copyright (C) 2005-2009 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
18 #include <string.h>
19
20 #include "peer_cfg.h"
21
22 #include <daemon.h>
23
24 #include <threading/mutex.h>
25 #include <collections/linked_list.h>
26 #include <utils/identification.h>
27
28 ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
29 "CERT_ALWAYS_SEND",
30 "CERT_SEND_IF_ASKED",
31 "CERT_NEVER_SEND",
32 );
33
34 ENUM(unique_policy_names, UNIQUE_NEVER, UNIQUE_KEEP,
35 "UNIQUE_NEVER",
36 "UNIQUE_NO",
37 "UNIQUE_REPLACE",
38 "UNIQUE_KEEP",
39 );
40
41 typedef struct private_peer_cfg_t private_peer_cfg_t;
42
43 /**
44 * Private data of an peer_cfg_t object
45 */
46 struct private_peer_cfg_t {
47
48 /**
49 * Public part
50 */
51 peer_cfg_t public;
52
53 /**
54 * Number of references hold by others to this peer_cfg
55 */
56 refcount_t refcount;
57
58 /**
59 * Name of the peer_cfg, used to query it
60 */
61 char *name;
62
63 /**
64 * IKE config associated to this peer config
65 */
66 ike_cfg_t *ike_cfg;
67
68 /**
69 * list of child configs associated to this peer config
70 */
71 linked_list_t *child_cfgs;
72
73 /**
74 * mutex to lock access to list of child_cfgs
75 */
76 mutex_t *mutex;
77
78 /**
79 * should we send a certificate
80 */
81 cert_policy_t cert_policy;
82
83 /**
84 * uniqueness of an IKE_SA
85 */
86 unique_policy_t unique;
87
88 /**
89 * number of tries after giving up if peer does not respond
90 */
91 u_int32_t keyingtries;
92
93 /**
94 * enable support for MOBIKE
95 */
96 bool use_mobike;
97
98 /**
99 * Use aggressive mode?
100 */
101 bool aggressive;
102
103 /**
104 * Use pull or push in mode config?
105 */
106 bool pull_mode;
107
108 /**
109 * Time before starting rekeying
110 */
111 u_int32_t rekey_time;
112
113 /**
114 * Time before starting reauthentication
115 */
116 u_int32_t reauth_time;
117
118 /**
119 * Time, which specifies the range of a random value subtracted from above.
120 */
121 u_int32_t jitter_time;
122
123 /**
124 * Delay before deleting a rekeying/reauthenticating SA
125 */
126 u_int32_t over_time;
127
128 /**
129 * DPD check intervall
130 */
131 u_int32_t dpd;
132
133 /**
134 * DPD timeout intervall (used for IKEv1 only)
135 */
136 u_int32_t dpd_timeout;
137
138 /**
139 * List of virtual IPs (host_t*) to request
140 */
141 linked_list_t *vips;
142
143 /**
144 * List of pool names to use for virtual IP lookup
145 */
146 linked_list_t *pools;
147
148 /**
149 * local authentication configs (rulesets)
150 */
151 linked_list_t *local_auth;
152
153 /**
154 * remote authentication configs (constraints)
155 */
156 linked_list_t *remote_auth;
157
158 #ifdef ME
159 /**
160 * Is this a mediation connection?
161 */
162 bool mediation;
163
164 /**
165 * Name of the mediation connection to mediate through
166 */
167 peer_cfg_t *mediated_by;
168
169 /**
170 * ID of our peer at the mediation server (= leftid of the peer's conn with
171 * the mediation server)
172 */
173 identification_t *peer_id;
174 #endif /* ME */
175 };
176
177 METHOD(peer_cfg_t, get_name, char*,
178 private_peer_cfg_t *this)
179 {
180 return this->name;
181 }
182
183 METHOD(peer_cfg_t, get_ike_version, ike_version_t,
184 private_peer_cfg_t *this)
185 {
186 return this->ike_cfg->get_version(this->ike_cfg);
187 }
188
189 METHOD(peer_cfg_t, get_ike_cfg, ike_cfg_t*,
190 private_peer_cfg_t *this)
191 {
192 return this->ike_cfg;
193 }
194
195 METHOD(peer_cfg_t, add_child_cfg, void,
196 private_peer_cfg_t *this, child_cfg_t *child_cfg)
197 {
198 this->mutex->lock(this->mutex);
199 this->child_cfgs->insert_last(this->child_cfgs, child_cfg);
200 this->mutex->unlock(this->mutex);
201 }
202
203 /**
204 * child_cfg enumerator
205 */
206 typedef struct {
207 enumerator_t public;
208 enumerator_t *wrapped;
209 mutex_t *mutex;
210 } child_cfg_enumerator_t;
211
212 METHOD(peer_cfg_t, remove_child_cfg, void,
213 private_peer_cfg_t *this, child_cfg_enumerator_t *enumerator)
214 {
215 this->child_cfgs->remove_at(this->child_cfgs, enumerator->wrapped);
216 }
217
218 METHOD(enumerator_t, child_cfg_enumerator_destroy, void,
219 child_cfg_enumerator_t *this)
220 {
221 this->mutex->unlock(this->mutex);
222 this->wrapped->destroy(this->wrapped);
223 free(this);
224 }
225
226 METHOD(enumerator_t, child_cfg_enumerate, bool,
227 child_cfg_enumerator_t *this, child_cfg_t **chd)
228 {
229 return this->wrapped->enumerate(this->wrapped, chd);
230 }
231
232 METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*,
233 private_peer_cfg_t *this)
234 {
235 child_cfg_enumerator_t *enumerator;
236
237 INIT(enumerator,
238 .public = {
239 .enumerate = (void*)_child_cfg_enumerate,
240 .destroy = (void*)_child_cfg_enumerator_destroy,
241 },
242 .mutex = this->mutex,
243 .wrapped = this->child_cfgs->create_enumerator(this->child_cfgs),
244 );
245
246 this->mutex->lock(this->mutex);
247 return &enumerator->public;
248 }
249
250 /**
251 * Check how good a list of TS matches a given child config
252 */
253 static int get_ts_match(child_cfg_t *cfg, bool local,
254 linked_list_t *sup_list, linked_list_t *hosts)
255 {
256 linked_list_t *cfg_list;
257 enumerator_t *sup_enum, *cfg_enum;
258 traffic_selector_t *sup_ts, *cfg_ts, *subset;
259 int match = 0, round;
260
261 /* fetch configured TS list, narrowing dynamic TS */
262 cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts);
263
264 /* use a round counter to rate leading TS with higher priority */
265 round = sup_list->get_count(sup_list);
266
267 sup_enum = sup_list->create_enumerator(sup_list);
268 while (sup_enum->enumerate(sup_enum, &sup_ts))
269 {
270 cfg_enum = cfg_list->create_enumerator(cfg_list);
271 while (cfg_enum->enumerate(cfg_enum, &cfg_ts))
272 {
273 if (cfg_ts->equals(cfg_ts, sup_ts))
274 { /* equality is honored better than matches */
275 match += round * 5;
276 }
277 else
278 {
279 subset = cfg_ts->get_subset(cfg_ts, sup_ts);
280 if (subset)
281 {
282 subset->destroy(subset);
283 match += round * 1;
284 }
285 }
286 }
287 cfg_enum->destroy(cfg_enum);
288 round--;
289 }
290 sup_enum->destroy(sup_enum);
291
292 cfg_list->destroy_offset(cfg_list, offsetof(traffic_selector_t, destroy));
293
294 return match;
295 }
296
297 METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*,
298 private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts,
299 linked_list_t *my_hosts, linked_list_t *other_hosts)
300 {
301 child_cfg_t *current, *found = NULL;
302 enumerator_t *enumerator;
303 int best = 0;
304
305 DBG2(DBG_CFG, "looking for a child config for %#R === %#R", my_ts, other_ts);
306 enumerator = create_child_cfg_enumerator(this);
307 while (enumerator->enumerate(enumerator, &current))
308 {
309 int my_prio, other_prio;
310
311 my_prio = get_ts_match(current, TRUE, my_ts, my_hosts);
312 other_prio = get_ts_match(current, FALSE, other_ts, other_hosts);
313
314 if (my_prio && other_prio)
315 {
316 DBG2(DBG_CFG, " candidate \"%s\" with prio %d+%d",
317 current->get_name(current), my_prio, other_prio);
318 if (my_prio + other_prio > best)
319 {
320 best = my_prio + other_prio;
321 DESTROY_IF(found);
322 found = current->get_ref(current);
323 }
324 }
325 }
326 enumerator->destroy(enumerator);
327 if (found)
328 {
329 DBG2(DBG_CFG, "found matching child config \"%s\" with prio %d",
330 found->get_name(found), best);
331 }
332 return found;
333 }
334
335 METHOD(peer_cfg_t, get_cert_policy, cert_policy_t,
336 private_peer_cfg_t *this)
337 {
338 return this->cert_policy;
339 }
340
341 METHOD(peer_cfg_t, get_unique_policy, unique_policy_t,
342 private_peer_cfg_t *this)
343 {
344 return this->unique;
345 }
346
347 METHOD(peer_cfg_t, get_keyingtries, u_int32_t,
348 private_peer_cfg_t *this)
349 {
350 return this->keyingtries;
351 }
352
353 METHOD(peer_cfg_t, get_rekey_time, u_int32_t,
354 private_peer_cfg_t *this, bool jitter)
355 {
356 if (this->rekey_time == 0)
357 {
358 return 0;
359 }
360 if (this->jitter_time == 0 || !jitter)
361 {
362 return this->rekey_time;
363 }
364 return this->rekey_time - (random() % this->jitter_time);
365 }
366
367 METHOD(peer_cfg_t, get_reauth_time, u_int32_t,
368 private_peer_cfg_t *this, bool jitter)
369 {
370 if (this->reauth_time == 0)
371 {
372 return 0;
373 }
374 if (this->jitter_time == 0 || !jitter)
375 {
376 return this->reauth_time;
377 }
378 return this->reauth_time - (random() % this->jitter_time);
379 }
380
381 METHOD(peer_cfg_t, get_over_time, u_int32_t,
382 private_peer_cfg_t *this)
383 {
384 return this->over_time;
385 }
386
387 METHOD(peer_cfg_t, use_mobike, bool,
388 private_peer_cfg_t *this)
389 {
390 return this->use_mobike;
391 }
392
393 METHOD(peer_cfg_t, use_aggressive, bool,
394 private_peer_cfg_t *this)
395 {
396 return this->aggressive;
397 }
398
399 METHOD(peer_cfg_t, use_pull_mode, bool,
400 private_peer_cfg_t *this)
401 {
402 return this->pull_mode;
403 }
404
405 METHOD(peer_cfg_t, get_dpd, u_int32_t,
406 private_peer_cfg_t *this)
407 {
408 return this->dpd;
409 }
410
411 METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t,
412 private_peer_cfg_t *this)
413 {
414 return this->dpd_timeout;
415 }
416
417 METHOD(peer_cfg_t, add_virtual_ip, void,
418 private_peer_cfg_t *this, host_t *vip)
419 {
420 this->vips->insert_last(this->vips, vip);
421 }
422
423 METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*,
424 private_peer_cfg_t *this)
425 {
426 return this->vips->create_enumerator(this->vips);
427 }
428
429 METHOD(peer_cfg_t, add_pool, void,
430 private_peer_cfg_t *this, char *name)
431 {
432 this->pools->insert_last(this->pools, strdup(name));
433 }
434
435 METHOD(peer_cfg_t, create_pool_enumerator, enumerator_t*,
436 private_peer_cfg_t *this)
437 {
438 return this->pools->create_enumerator(this->pools);
439 }
440
441 METHOD(peer_cfg_t, add_auth_cfg, void,
442 private_peer_cfg_t *this, auth_cfg_t *cfg, bool local)
443 {
444 if (local)
445 {
446 this->local_auth->insert_last(this->local_auth, cfg);
447 }
448 else
449 {
450 this->remote_auth->insert_last(this->remote_auth, cfg);
451 }
452 }
453
454 METHOD(peer_cfg_t, create_auth_cfg_enumerator, enumerator_t*,
455 private_peer_cfg_t *this, bool local)
456 {
457 if (local)
458 {
459 return this->local_auth->create_enumerator(this->local_auth);
460 }
461 return this->remote_auth->create_enumerator(this->remote_auth);
462 }
463
464 #ifdef ME
465 METHOD(peer_cfg_t, is_mediation, bool,
466 private_peer_cfg_t *this)
467 {
468 return this->mediation;
469 }
470
471 METHOD(peer_cfg_t, get_mediated_by, peer_cfg_t*,
472 private_peer_cfg_t *this)
473 {
474 return this->mediated_by;
475 }
476
477 METHOD(peer_cfg_t, get_peer_id, identification_t*,
478 private_peer_cfg_t *this)
479 {
480 return this->peer_id;
481 }
482 #endif /* ME */
483
484 /**
485 * check auth configs for equality
486 */
487 static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
488 {
489 enumerator_t *e1, *e2;
490 auth_cfg_t *cfg1, *cfg2;
491 bool equal = TRUE;
492
493 if (this->local_auth->get_count(this->local_auth) !=
494 other->local_auth->get_count(other->local_auth))
495 {
496 return FALSE;
497 }
498 if (this->remote_auth->get_count(this->remote_auth) !=
499 other->remote_auth->get_count(other->remote_auth))
500 {
501 return FALSE;
502 }
503
504 e1 = this->local_auth->create_enumerator(this->local_auth);
505 e2 = other->local_auth->create_enumerator(other->local_auth);
506 while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
507 {
508 if (!cfg1->equals(cfg1, cfg2))
509 {
510 equal = FALSE;
511 break;
512 }
513 }
514 e1->destroy(e1);
515 e2->destroy(e2);
516
517 if (!equal)
518 {
519 return FALSE;
520 }
521
522 e1 = this->remote_auth->create_enumerator(this->remote_auth);
523 e2 = other->remote_auth->create_enumerator(other->remote_auth);
524 while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
525 {
526 if (!cfg1->equals(cfg1, cfg2))
527 {
528 equal = FALSE;
529 break;
530 }
531 }
532 e1->destroy(e1);
533 e2->destroy(e2);
534
535 return equal;
536 }
537
538 METHOD(peer_cfg_t, equals, bool,
539 private_peer_cfg_t *this, private_peer_cfg_t *other)
540 {
541 enumerator_t *e1, *e2;
542 host_t *vip1, *vip2;
543 char *pool1, *pool2;
544
545 if (this == other)
546 {
547 return TRUE;
548 }
549 if (this->public.equals != other->public.equals)
550 {
551 return FALSE;
552 }
553
554 if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips))
555 {
556 return FALSE;
557 }
558 e1 = create_virtual_ip_enumerator(this);
559 e2 = create_virtual_ip_enumerator(other);
560 if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2))
561 {
562 if (!vip1->ip_equals(vip1, vip2))
563 {
564 e1->destroy(e1);
565 e2->destroy(e2);
566 return FALSE;
567 }
568 }
569 e1->destroy(e1);
570 e2->destroy(e2);
571
572 if (this->pools->get_count(this->pools) !=
573 other->pools->get_count(other->pools))
574 {
575 return FALSE;
576 }
577 e1 = create_pool_enumerator(this);
578 e2 = create_pool_enumerator(other);
579 if (e1->enumerate(e1, &pool1) && e2->enumerate(e2, &pool2))
580 {
581 if (!streq(pool1, pool2))
582 {
583 e1->destroy(e1);
584 e2->destroy(e2);
585 return FALSE;
586 }
587 }
588 e1->destroy(e1);
589 e2->destroy(e2);
590
591 return (
592 get_ike_version(this) == get_ike_version(other) &&
593 this->cert_policy == other->cert_policy &&
594 this->unique == other->unique &&
595 this->keyingtries == other->keyingtries &&
596 this->use_mobike == other->use_mobike &&
597 this->rekey_time == other->rekey_time &&
598 this->reauth_time == other->reauth_time &&
599 this->jitter_time == other->jitter_time &&
600 this->over_time == other->over_time &&
601 this->dpd == other->dpd &&
602 this->aggressive == other->aggressive &&
603 this->pull_mode == other->pull_mode &&
604 auth_cfg_equal(this, other)
605 #ifdef ME
606 && this->mediation == other->mediation &&
607 this->mediated_by == other->mediated_by &&
608 (this->peer_id == other->peer_id ||
609 (this->peer_id && other->peer_id &&
610 this->peer_id->equals(this->peer_id, other->peer_id)))
611 #endif /* ME */
612 );
613 }
614
615 METHOD(peer_cfg_t, get_ref, peer_cfg_t*,
616 private_peer_cfg_t *this)
617 {
618 ref_get(&this->refcount);
619 return &this->public;
620 }
621
622 METHOD(peer_cfg_t, destroy, void,
623 private_peer_cfg_t *this)
624 {
625 if (ref_put(&this->refcount))
626 {
627 this->ike_cfg->destroy(this->ike_cfg);
628 this->child_cfgs->destroy_offset(this->child_cfgs,
629 offsetof(child_cfg_t, destroy));
630 this->local_auth->destroy_offset(this->local_auth,
631 offsetof(auth_cfg_t, destroy));
632 this->remote_auth->destroy_offset(this->remote_auth,
633 offsetof(auth_cfg_t, destroy));
634 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
635 this->pools->destroy_function(this->pools, free);
636 #ifdef ME
637 DESTROY_IF(this->mediated_by);
638 DESTROY_IF(this->peer_id);
639 #endif /* ME */
640 this->mutex->destroy(this->mutex);
641 free(this->name);
642 free(this);
643 }
644 }
645
646 /*
647 * Described in header-file
648 */
649 peer_cfg_t *peer_cfg_create(char *name,
650 ike_cfg_t *ike_cfg, cert_policy_t cert_policy,
651 unique_policy_t unique, u_int32_t keyingtries,
652 u_int32_t rekey_time, u_int32_t reauth_time,
653 u_int32_t jitter_time, u_int32_t over_time,
654 bool mobike, bool aggressive, bool pull_mode,
655 u_int32_t dpd, u_int32_t dpd_timeout,
656 bool mediation, peer_cfg_t *mediated_by,
657 identification_t *peer_id)
658 {
659 private_peer_cfg_t *this;
660
661 if (rekey_time && jitter_time > rekey_time)
662 {
663 jitter_time = rekey_time;
664 }
665 if (reauth_time && jitter_time > reauth_time)
666 {
667 jitter_time = reauth_time;
668 }
669 if (dpd && dpd_timeout && dpd > dpd_timeout)
670 {
671 dpd_timeout = dpd;
672 }
673
674 INIT(this,
675 .public = {
676 .get_name = _get_name,
677 .get_ike_version = _get_ike_version,
678 .get_ike_cfg = _get_ike_cfg,
679 .add_child_cfg = _add_child_cfg,
680 .remove_child_cfg = (void*)_remove_child_cfg,
681 .create_child_cfg_enumerator = _create_child_cfg_enumerator,
682 .select_child_cfg = _select_child_cfg,
683 .get_cert_policy = _get_cert_policy,
684 .get_unique_policy = _get_unique_policy,
685 .get_keyingtries = _get_keyingtries,
686 .get_rekey_time = _get_rekey_time,
687 .get_reauth_time = _get_reauth_time,
688 .get_over_time = _get_over_time,
689 .use_mobike = _use_mobike,
690 .use_aggressive = _use_aggressive,
691 .use_pull_mode = _use_pull_mode,
692 .get_dpd = _get_dpd,
693 .get_dpd_timeout = _get_dpd_timeout,
694 .add_virtual_ip = _add_virtual_ip,
695 .create_virtual_ip_enumerator = _create_virtual_ip_enumerator,
696 .add_pool = _add_pool,
697 .create_pool_enumerator = _create_pool_enumerator,
698 .add_auth_cfg = _add_auth_cfg,
699 .create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
700 .equals = (void*)_equals,
701 .get_ref = _get_ref,
702 .destroy = _destroy,
703 #ifdef ME
704 .is_mediation = _is_mediation,
705 .get_mediated_by = _get_mediated_by,
706 .get_peer_id = _get_peer_id,
707 #endif /* ME */
708 },
709 .name = strdup(name),
710 .ike_cfg = ike_cfg,
711 .child_cfgs = linked_list_create(),
712 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
713 .cert_policy = cert_policy,
714 .unique = unique,
715 .keyingtries = keyingtries,
716 .rekey_time = rekey_time,
717 .reauth_time = reauth_time,
718 .jitter_time = jitter_time,
719 .over_time = over_time,
720 .use_mobike = mobike,
721 .aggressive = aggressive,
722 .pull_mode = pull_mode,
723 .dpd = dpd,
724 .dpd_timeout = dpd_timeout,
725 .vips = linked_list_create(),
726 .pools = linked_list_create(),
727 .local_auth = linked_list_create(),
728 .remote_auth = linked_list_create(),
729 .refcount = 1,
730 );
731
732 #ifdef ME
733 this->mediation = mediation;
734 this->mediated_by = mediated_by;
735 this->peer_id = peer_id;
736 #else /* ME */
737 DESTROY_IF(mediated_by);
738 DESTROY_IF(peer_id);
739 #endif /* ME */
740
741 return &this->public;
742 }