b278dc3370b6e800f386e5cdd9ba0fc3a7814b3c
[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 <utils/linked_list.h>
26 #include <utils/identification.h>
27
28 ENUM(ike_version_names, IKE_ANY, IKEV2,
29 "IKEv1/2",
30 "IKEv1",
31 "IKEv2",
32 );
33
34 ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
35 "CERT_ALWAYS_SEND",
36 "CERT_SEND_IF_ASKED",
37 "CERT_NEVER_SEND",
38 );
39
40 ENUM(unique_policy_names, UNIQUE_NO, UNIQUE_KEEP,
41 "UNIQUE_NO",
42 "UNIQUE_REPLACE",
43 "UNIQUE_KEEP",
44 );
45
46 typedef struct private_peer_cfg_t private_peer_cfg_t;
47
48 /**
49 * Private data of an peer_cfg_t object
50 */
51 struct private_peer_cfg_t {
52
53 /**
54 * Public part
55 */
56 peer_cfg_t public;
57
58 /**
59 * Number of references hold by others to this peer_cfg
60 */
61 refcount_t refcount;
62
63 /**
64 * Name of the peer_cfg, used to query it
65 */
66 char *name;
67
68 /**
69 * IKE version to use for initiation
70 */
71 ike_version_t ike_version;
72
73 /**
74 * IKE config associated to this peer config
75 */
76 ike_cfg_t *ike_cfg;
77
78 /**
79 * list of child configs associated to this peer config
80 */
81 linked_list_t *child_cfgs;
82
83 /**
84 * mutex to lock access to list of child_cfgs
85 */
86 mutex_t *mutex;
87
88 /**
89 * should we send a certificate
90 */
91 cert_policy_t cert_policy;
92
93 /**
94 * uniqueness of an IKE_SA
95 */
96 unique_policy_t unique;
97
98 /**
99 * number of tries after giving up if peer does not respond
100 */
101 u_int32_t keyingtries;
102
103 /**
104 * enable support for MOBIKE
105 */
106 bool use_mobike;
107
108 /**
109 * Use aggressive mode?
110 */
111 bool aggressive;
112
113 /**
114 * Time before starting rekeying
115 */
116 u_int32_t rekey_time;
117
118 /**
119 * Time before starting reauthentication
120 */
121 u_int32_t reauth_time;
122
123 /**
124 * Time, which specifies the range of a random value subtracted from above.
125 */
126 u_int32_t jitter_time;
127
128 /**
129 * Delay before deleting a rekeying/reauthenticating SA
130 */
131 u_int32_t over_time;
132
133 /**
134 * DPD check intervall
135 */
136 u_int32_t dpd;
137
138 /**
139 * virtual IP to use locally
140 */
141 host_t *virtual_ip;
142
143 /**
144 * pool to acquire configuration attributes from
145 */
146 char *pool;
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_version;
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, host_t *host)
255 {
256 linked_list_t *cfg_list;
257 enumerator_t *sup_enum, *cfg_enum;
258 traffic_selector_t *sup_ts, *cfg_ts;
259 int match = 0, round;
260
261 /* fetch configured TS list, narrowing dynamic TS */
262 cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host);
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 if (cfg_ts->is_contained_in(cfg_ts, sup_ts) ||
278 sup_ts->is_contained_in(sup_ts, cfg_ts))
279 {
280 match += round * 1;
281 }
282 }
283 cfg_enum->destroy(cfg_enum);
284 round--;
285 }
286 sup_enum->destroy(sup_enum);
287
288 cfg_list->destroy_offset(cfg_list, offsetof(traffic_selector_t, destroy));
289
290 return match;
291 }
292
293 METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*,
294 private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts,
295 host_t *my_host, host_t *other_host)
296 {
297 child_cfg_t *current, *found = NULL;
298 enumerator_t *enumerator;
299 int best = 0;
300
301 DBG2(DBG_CFG, "looking for a child config for %#R=== %#R", my_ts, other_ts);
302 enumerator = create_child_cfg_enumerator(this);
303 while (enumerator->enumerate(enumerator, &current))
304 {
305 int my_prio, other_prio;
306
307 my_prio = get_ts_match(current, TRUE, my_ts, my_host);
308 other_prio = get_ts_match(current, FALSE, other_ts, other_host);
309
310 if (my_prio && other_prio)
311 {
312 DBG2(DBG_CFG, " candidate \"%s\" with prio %d+%d",
313 current->get_name(current), my_prio, other_prio);
314 if (my_prio + other_prio > best)
315 {
316 best = my_prio + other_prio;
317 DESTROY_IF(found);
318 found = current->get_ref(current);
319 }
320 }
321 }
322 enumerator->destroy(enumerator);
323 if (found)
324 {
325 DBG2(DBG_CFG, "found matching child config \"%s\" with prio %d",
326 found->get_name(found), best);
327 }
328 return found;
329 }
330
331 METHOD(peer_cfg_t, get_cert_policy, cert_policy_t,
332 private_peer_cfg_t *this)
333 {
334 return this->cert_policy;
335 }
336
337 METHOD(peer_cfg_t, get_unique_policy, unique_policy_t,
338 private_peer_cfg_t *this)
339 {
340 return this->unique;
341 }
342
343 METHOD(peer_cfg_t, get_keyingtries, u_int32_t,
344 private_peer_cfg_t *this)
345 {
346 return this->keyingtries;
347 }
348
349 METHOD(peer_cfg_t, get_rekey_time, u_int32_t,
350 private_peer_cfg_t *this, bool jitter)
351 {
352 if (this->rekey_time == 0)
353 {
354 return 0;
355 }
356 if (this->jitter_time == 0 || !jitter)
357 {
358 return this->rekey_time;
359 }
360 return this->rekey_time - (random() % this->jitter_time);
361 }
362
363 METHOD(peer_cfg_t, get_reauth_time, u_int32_t,
364 private_peer_cfg_t *this, bool jitter)
365 {
366 if (this->reauth_time == 0)
367 {
368 return 0;
369 }
370 if (this->jitter_time == 0 || !jitter)
371 {
372 return this->reauth_time;
373 }
374 return this->reauth_time - (random() % this->jitter_time);
375 }
376
377 METHOD(peer_cfg_t, get_over_time, u_int32_t,
378 private_peer_cfg_t *this)
379 {
380 return this->over_time;
381 }
382
383 METHOD(peer_cfg_t, use_mobike, bool,
384 private_peer_cfg_t *this)
385 {
386 return this->use_mobike;
387 }
388
389 METHOD(peer_cfg_t, use_aggressive, bool,
390 private_peer_cfg_t *this)
391 {
392 return this->aggressive;
393 }
394
395 METHOD(peer_cfg_t, get_dpd, u_int32_t,
396 private_peer_cfg_t *this)
397 {
398 return this->dpd;
399 }
400
401 METHOD(peer_cfg_t, get_virtual_ip, host_t*,
402 private_peer_cfg_t *this)
403 {
404 return this->virtual_ip;
405 }
406
407 METHOD(peer_cfg_t, get_pool, char*,
408 private_peer_cfg_t *this)
409 {
410 return this->pool;
411 }
412
413 METHOD(peer_cfg_t, add_auth_cfg, void,
414 private_peer_cfg_t *this, auth_cfg_t *cfg, bool local)
415 {
416 if (local)
417 {
418 this->local_auth->insert_last(this->local_auth, cfg);
419 }
420 else
421 {
422 this->remote_auth->insert_last(this->remote_auth, cfg);
423 }
424 }
425
426 METHOD(peer_cfg_t, create_auth_cfg_enumerator, enumerator_t*,
427 private_peer_cfg_t *this, bool local)
428 {
429 if (local)
430 {
431 return this->local_auth->create_enumerator(this->local_auth);
432 }
433 return this->remote_auth->create_enumerator(this->remote_auth);
434 }
435
436 #ifdef ME
437 METHOD(peer_cfg_t, is_mediation, bool,
438 private_peer_cfg_t *this)
439 {
440 return this->mediation;
441 }
442
443 METHOD(peer_cfg_t, get_mediated_by, peer_cfg_t*,
444 private_peer_cfg_t *this)
445 {
446 return this->mediated_by;
447 }
448
449 METHOD(peer_cfg_t, get_peer_id, identification_t*,
450 private_peer_cfg_t *this)
451 {
452 return this->peer_id;
453 }
454 #endif /* ME */
455
456 /**
457 * check auth configs for equality
458 */
459 static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
460 {
461 enumerator_t *e1, *e2;
462 auth_cfg_t *cfg1, *cfg2;
463 bool equal = TRUE;
464
465 if (this->local_auth->get_count(this->local_auth) !=
466 other->local_auth->get_count(other->local_auth))
467 {
468 return FALSE;
469 }
470 if (this->remote_auth->get_count(this->remote_auth) !=
471 other->remote_auth->get_count(other->remote_auth))
472 {
473 return FALSE;
474 }
475
476 e1 = this->local_auth->create_enumerator(this->local_auth);
477 e2 = other->local_auth->create_enumerator(other->local_auth);
478 while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
479 {
480 if (!cfg1->equals(cfg1, cfg2))
481 {
482 equal = FALSE;
483 break;
484 }
485 }
486 e1->destroy(e1);
487 e2->destroy(e2);
488
489 if (!equal)
490 {
491 return FALSE;
492 }
493
494 e1 = this->remote_auth->create_enumerator(this->remote_auth);
495 e2 = other->remote_auth->create_enumerator(other->remote_auth);
496 while (e1->enumerate(e1, &cfg1) && e2->enumerate(e2, &cfg2))
497 {
498 if (!cfg1->equals(cfg1, cfg2))
499 {
500 equal = FALSE;
501 break;
502 }
503 }
504 e1->destroy(e1);
505 e2->destroy(e2);
506
507 return equal;
508 }
509
510 METHOD(peer_cfg_t, equals, bool,
511 private_peer_cfg_t *this, private_peer_cfg_t *other)
512 {
513 if (this == other)
514 {
515 return TRUE;
516 }
517 if (this->public.equals != other->public.equals)
518 {
519 return FALSE;
520 }
521
522 return (
523 this->ike_version == other->ike_version &&
524 this->cert_policy == other->cert_policy &&
525 this->unique == other->unique &&
526 this->keyingtries == other->keyingtries &&
527 this->use_mobike == other->use_mobike &&
528 this->rekey_time == other->rekey_time &&
529 this->reauth_time == other->reauth_time &&
530 this->jitter_time == other->jitter_time &&
531 this->over_time == other->over_time &&
532 this->dpd == other->dpd &&
533 (this->virtual_ip == other->virtual_ip ||
534 (this->virtual_ip && other->virtual_ip &&
535 this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
536 (this->pool == other->pool ||
537 (this->pool && other->pool && streq(this->pool, other->pool))) &&
538 auth_cfg_equal(this, other)
539 #ifdef ME
540 && this->mediation == other->mediation &&
541 this->mediated_by == other->mediated_by &&
542 (this->peer_id == other->peer_id ||
543 (this->peer_id && other->peer_id &&
544 this->peer_id->equals(this->peer_id, other->peer_id)))
545 #endif /* ME */
546 );
547 }
548
549 METHOD(peer_cfg_t, get_ref, peer_cfg_t*,
550 private_peer_cfg_t *this)
551 {
552 ref_get(&this->refcount);
553 return &this->public;
554 }
555
556 METHOD(peer_cfg_t, destroy, void,
557 private_peer_cfg_t *this)
558 {
559 if (ref_put(&this->refcount))
560 {
561 this->ike_cfg->destroy(this->ike_cfg);
562 this->child_cfgs->destroy_offset(this->child_cfgs,
563 offsetof(child_cfg_t, destroy));
564 DESTROY_IF(this->virtual_ip);
565 this->local_auth->destroy_offset(this->local_auth,
566 offsetof(auth_cfg_t, destroy));
567 this->remote_auth->destroy_offset(this->remote_auth,
568 offsetof(auth_cfg_t, destroy));
569 #ifdef ME
570 DESTROY_IF(this->mediated_by);
571 DESTROY_IF(this->peer_id);
572 #endif /* ME */
573 this->mutex->destroy(this->mutex);
574 free(this->name);
575 free(this->pool);
576 free(this);
577 }
578 }
579
580 /*
581 * Described in header-file
582 */
583 peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version,
584 ike_cfg_t *ike_cfg, cert_policy_t cert_policy,
585 unique_policy_t unique, u_int32_t keyingtries,
586 u_int32_t rekey_time, u_int32_t reauth_time,
587 u_int32_t jitter_time, u_int32_t over_time,
588 bool mobike, bool aggressive, u_int32_t dpd,
589 host_t *virtual_ip, char *pool, bool mediation,
590 peer_cfg_t *mediated_by, identification_t *peer_id)
591 {
592 private_peer_cfg_t *this;
593
594 if (rekey_time && jitter_time > rekey_time)
595 {
596 jitter_time = rekey_time;
597 }
598 if (reauth_time && jitter_time > reauth_time)
599 {
600 jitter_time = reauth_time;
601 }
602
603 INIT(this,
604 .public = {
605 .get_name = _get_name,
606 .get_ike_version = _get_ike_version,
607 .get_ike_cfg = _get_ike_cfg,
608 .add_child_cfg = _add_child_cfg,
609 .remove_child_cfg = (void*)_remove_child_cfg,
610 .create_child_cfg_enumerator = _create_child_cfg_enumerator,
611 .select_child_cfg = _select_child_cfg,
612 .get_cert_policy = _get_cert_policy,
613 .get_unique_policy = _get_unique_policy,
614 .get_keyingtries = _get_keyingtries,
615 .get_rekey_time = _get_rekey_time,
616 .get_reauth_time = _get_reauth_time,
617 .get_over_time = _get_over_time,
618 .use_mobike = _use_mobike,
619 .use_aggressive = _use_aggressive,
620 .get_dpd = _get_dpd,
621 .get_virtual_ip = _get_virtual_ip,
622 .get_pool = _get_pool,
623 .add_auth_cfg = _add_auth_cfg,
624 .create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
625 .equals = (void*)_equals,
626 .get_ref = _get_ref,
627 .destroy = _destroy,
628 #ifdef ME
629 .is_mediation = _is_mediation,
630 .get_mediated_by = _get_mediated_by,
631 .get_peer_id = _get_peer_id,
632 #endif /* ME */
633 },
634 .name = strdup(name),
635 .ike_version = ike_version,
636 .ike_cfg = ike_cfg,
637 .child_cfgs = linked_list_create(),
638 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
639 .cert_policy = cert_policy,
640 .unique = unique,
641 .keyingtries = keyingtries,
642 .rekey_time = rekey_time,
643 .reauth_time = reauth_time,
644 .jitter_time = jitter_time,
645 .over_time = over_time,
646 .use_mobike = mobike,
647 .aggressive = aggressive,
648 .dpd = dpd,
649 .virtual_ip = virtual_ip,
650 .pool = strdupnull(pool),
651 .local_auth = linked_list_create(),
652 .remote_auth = linked_list_create(),
653 .refcount = 1,
654 );
655
656 #ifdef ME
657 this->mediation = mediation;
658 this->mediated_by = mediated_by;
659 this->peer_id = peer_id;
660 #else /* ME */
661 DESTROY_IF(mediated_by);
662 DESTROY_IF(peer_id);
663 #endif /* ME */
664
665 return &this->public;
666 }