97d2a78369bdb2abdcaf4c745abf167af6bebad0
[strongswan.git] / src / libcharon / plugins / stroke / stroke_config.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "stroke_config.h"
17
18 #include <hydra.h>
19 #include <daemon.h>
20 #include <threading/mutex.h>
21 #include <utils/lexparser.h>
22
23 typedef struct private_stroke_config_t private_stroke_config_t;
24
25 /**
26 * private data of stroke_config
27 */
28 struct private_stroke_config_t {
29
30 /**
31 * public functions
32 */
33 stroke_config_t public;
34
35 /**
36 * list of peer_cfg_t
37 */
38 linked_list_t *list;
39
40 /**
41 * mutex to lock config list
42 */
43 mutex_t *mutex;
44
45 /**
46 * ca sections
47 */
48 stroke_ca_t *ca;
49
50 /**
51 * credentials
52 */
53 stroke_cred_t *cred;
54 };
55
56 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
57 private_stroke_config_t *this, identification_t *me, identification_t *other)
58 {
59 this->mutex->lock(this->mutex);
60 return enumerator_create_cleaner(this->list->create_enumerator(this->list),
61 (void*)this->mutex->unlock, this->mutex);
62 }
63
64 /**
65 * filter function for ike configs
66 */
67 static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
68 {
69 *out = (*in)->get_ike_cfg(*in);
70 return TRUE;
71 }
72
73 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
74 private_stroke_config_t *this, host_t *me, host_t *other)
75 {
76 this->mutex->lock(this->mutex);
77 return enumerator_create_filter(this->list->create_enumerator(this->list),
78 (void*)ike_filter, this->mutex,
79 (void*)this->mutex->unlock);
80 }
81
82 METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
83 private_stroke_config_t *this, char *name)
84 {
85 enumerator_t *e1, *e2;
86 peer_cfg_t *current, *found = NULL;
87 child_cfg_t *child;
88
89 this->mutex->lock(this->mutex);
90 e1 = this->list->create_enumerator(this->list);
91 while (e1->enumerate(e1, &current))
92 {
93 /* compare peer_cfgs name first */
94 if (streq(current->get_name(current), name))
95 {
96 found = current;
97 found->get_ref(found);
98 break;
99 }
100 /* compare all child_cfg names otherwise */
101 e2 = current->create_child_cfg_enumerator(current);
102 while (e2->enumerate(e2, &child))
103 {
104 if (streq(child->get_name(child), name))
105 {
106 found = current;
107 found->get_ref(found);
108 break;
109 }
110 }
111 e2->destroy(e2);
112 if (found)
113 {
114 break;
115 }
116 }
117 e1->destroy(e1);
118 this->mutex->unlock(this->mutex);
119 return found;
120 }
121
122 /**
123 * parse a proposal string, either into ike_cfg or child_cfg
124 */
125 static void add_proposals(private_stroke_config_t *this, char *string,
126 ike_cfg_t *ike_cfg, child_cfg_t *child_cfg)
127 {
128 if (string)
129 {
130 char *single;
131 char *strict;
132 proposal_t *proposal;
133 protocol_id_t proto = PROTO_ESP;
134
135 if (ike_cfg)
136 {
137 proto = PROTO_IKE;
138 }
139 strict = string + strlen(string) - 1;
140 if (*strict == '!')
141 {
142 *strict = '\0';
143 }
144 else
145 {
146 strict = NULL;
147 }
148 while ((single = strsep(&string, ",")))
149 {
150 proposal = proposal_create_from_string(proto, single);
151 if (proposal)
152 {
153 if (ike_cfg)
154 {
155 ike_cfg->add_proposal(ike_cfg, proposal);
156 }
157 else
158 {
159 child_cfg->add_proposal(child_cfg, proposal);
160 }
161 continue;
162 }
163 DBG1(DBG_CFG, "skipped invalid proposal string: %s", single);
164 }
165 if (strict)
166 {
167 return;
168 }
169 /* add default porposal to the end if not strict */
170 }
171 if (ike_cfg)
172 {
173 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
174 }
175 else
176 {
177 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
178 }
179 }
180
181 /**
182 * Build an IKE config from a stroke message
183 */
184 static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg)
185 {
186 stroke_end_t tmp_end;
187 ike_cfg_t *ike_cfg;
188 char *interface;
189 host_t *host;
190
191 host = host_create_from_dns(msg->add_conn.other.address, 0, 0);
192 if (host)
193 {
194 interface = hydra->kernel_interface->get_interface(
195 hydra->kernel_interface, host);
196 host->destroy(host);
197 if (interface)
198 {
199 DBG2(DBG_CFG, "left is other host, swapping ends");
200 tmp_end = msg->add_conn.me;
201 msg->add_conn.me = msg->add_conn.other;
202 msg->add_conn.other = tmp_end;
203 free(interface);
204 }
205 else
206 {
207 host = host_create_from_dns(msg->add_conn.me.address, 0, 0);
208 if (host)
209 {
210 interface = hydra->kernel_interface->get_interface(
211 hydra->kernel_interface, host);
212 host->destroy(host);
213 if (!interface)
214 {
215 DBG1(DBG_CFG, "left nor right host is our side, "
216 "assuming left=local");
217 }
218 else
219 {
220 free(interface);
221 }
222
223 }
224 }
225 }
226 ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND,
227 msg->add_conn.force_encap,
228 msg->add_conn.me.address, msg->add_conn.me.ikeport,
229 msg->add_conn.other.address, msg->add_conn.other.ikeport);
230 add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
231 return ike_cfg;
232 }
233
234 /**
235 * Add CRL constraint to config
236 */
237 static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy)
238 {
239 /* CRL/OCSP policy, for remote config only */
240 if (!local)
241 {
242 switch (policy)
243 {
244 case CRL_STRICT_YES:
245 /* if yes, we require a GOOD validation */
246 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
247 break;
248 case CRL_STRICT_IFURI:
249 /* for ifuri, a SKIPPED validation is sufficient */
250 cfg->add(cfg, AUTH_RULE_CRL_VALIDATION, VALIDATION_SKIPPED);
251 break;
252 default:
253 break;
254 }
255 }
256 }
257
258 /**
259 * build authentication config
260 */
261 static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
262 stroke_msg_t *msg, bool local, bool primary)
263 {
264 identification_t *identity;
265 certificate_t *certificate;
266 char *auth, *id, *cert, *ca;
267 stroke_end_t *end, *other_end;
268 auth_cfg_t *cfg;
269 char eap_buf[32];
270
271 /* select strings */
272 if (local)
273 {
274 end = &msg->add_conn.me;
275 other_end = &msg->add_conn.other;
276 }
277 else
278 {
279 end = &msg->add_conn.other;
280 other_end = &msg->add_conn.me;
281 }
282 if (primary)
283 {
284 auth = end->auth;
285 id = end->id;
286 if (!id)
287 { /* leftid/rightid fallback to address */
288 id = end->address;
289 }
290 cert = end->cert;
291 ca = end->ca;
292 if (ca && streq(ca, "%same"))
293 {
294 ca = other_end->ca;
295 }
296 }
297 else
298 {
299 auth = end->auth2;
300 id = end->id2;
301 if (local && !id)
302 { /* leftid2 falls back to leftid */
303 id = end->id;
304 }
305 cert = end->cert2;
306 ca = end->ca2;
307 if (ca && streq(ca, "%same"))
308 {
309 ca = other_end->ca2;
310 }
311 }
312
313 if (!auth)
314 {
315 if (primary)
316 {
317 if (local)
318 { /* "leftauth" not defined, fall back to deprecated "authby" */
319 switch (msg->add_conn.auth_method)
320 {
321 default:
322 case AUTH_CLASS_PUBKEY:
323 auth = "pubkey";
324 break;
325 case AUTH_CLASS_PSK:
326 auth = "psk";
327 break;
328 case AUTH_CLASS_EAP:
329 auth = "eap";
330 break;
331 case AUTH_CLASS_ANY:
332 auth = "any";
333 break;
334 }
335 }
336 else
337 { /* "rightauth" not defined, fall back to deprecated "eap" */
338 if (msg->add_conn.eap_type)
339 {
340 if (msg->add_conn.eap_vendor)
341 {
342 snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d",
343 msg->add_conn.eap_type,
344 msg->add_conn.eap_vendor);
345 }
346 else
347 {
348 snprintf(eap_buf, sizeof(eap_buf), "eap-%d",
349 msg->add_conn.eap_type);
350 }
351 auth = eap_buf;
352 }
353 else
354 { /* not EAP => no constraints for this peer */
355 auth = "any";
356 }
357 }
358 }
359 else
360 { /* no second authentication round, fine. But load certificates
361 * for other purposes (EAP-TLS) */
362 if (cert)
363 {
364 certificate = this->cred->load_peer(this->cred, cert);
365 if (certificate)
366 {
367 certificate->destroy(certificate);
368 }
369 }
370 return NULL;
371 }
372 }
373
374 cfg = auth_cfg_create();
375
376 /* add identity and peer certifcate */
377 identity = identification_create_from_string(id);
378 if (cert)
379 {
380 certificate = this->cred->load_peer(this->cred, cert);
381 if (certificate)
382 {
383 if (local)
384 {
385 this->ca->check_for_hash_and_url(this->ca, certificate);
386 }
387 cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
388 if (identity->get_type(identity) == ID_ANY ||
389 !certificate->has_subject(certificate, identity))
390 {
391 DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
392 "defaulting to '%Y'", identity,
393 certificate->get_subject(certificate));
394 identity->destroy(identity);
395 identity = certificate->get_subject(certificate);
396 identity = identity->clone(identity);
397 }
398 }
399 }
400 cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
401
402 /* CA constraint */
403 if (ca)
404 {
405 identity = identification_create_from_string(ca);
406 certificate = lib->credmgr->get_cert(lib->credmgr, CERT_X509,
407 KEY_ANY, identity, TRUE);
408 identity->destroy(identity);
409 if (certificate)
410 {
411 cfg->add(cfg, AUTH_RULE_CA_CERT, certificate);
412 }
413 else
414 {
415 DBG1(DBG_CFG, "CA certificate \"%s\" not found, discarding CA "
416 "constraint", ca);
417 }
418 }
419
420 /* groups */
421 if (end->groups)
422 {
423 enumerator_t *enumerator;
424 char *group;
425
426 enumerator = enumerator_create_token(end->groups, ",", " ");
427 while (enumerator->enumerate(enumerator, &group))
428 {
429 cfg->add(cfg, AUTH_RULE_GROUP,
430 identification_create_from_string(group));
431 }
432 enumerator->destroy(enumerator);
433 }
434
435 /* certificatePolicies */
436 if (end->cert_policy)
437 {
438 enumerator_t *enumerator;
439 char *policy;
440
441 enumerator = enumerator_create_token(end->cert_policy, ",", " ");
442 while (enumerator->enumerate(enumerator, &policy))
443 {
444 cfg->add(cfg, AUTH_RULE_CERT_POLICY, strdup(policy));
445 }
446 enumerator->destroy(enumerator);
447 }
448
449 /* authentication metod (class, actually) */
450 if (streq(auth, "pubkey") ||
451 strneq(auth, "rsa", strlen("rsa")) ||
452 strneq(auth, "ecdsa", strlen("ecdsa")))
453 {
454 u_int strength;
455
456 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
457 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
458
459 if (sscanf(auth, "rsa-%d", &strength) == 1)
460 {
461 cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength);
462 }
463 if (sscanf(auth, "ecdsa-%d", &strength) == 1)
464 {
465 cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength);
466 }
467 }
468 else if (streq(auth, "psk") || streq(auth, "secret"))
469 {
470 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
471 }
472 else if (streq(auth, "xauthpsk"))
473 {
474 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PSK);
475 }
476 else if (strneq(auth, "eap", 3))
477 {
478 enumerator_t *enumerator;
479 char *str;
480 int i = 0, type = 0, vendor;
481
482 cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
483
484 /* parse EAP string, format: eap[-type[-vendor]] */
485 enumerator = enumerator_create_token(auth, "-", " ");
486 while (enumerator->enumerate(enumerator, &str))
487 {
488 switch (i)
489 {
490 case 1:
491 type = eap_type_from_string(str);
492 if (!type)
493 {
494 type = atoi(str);
495 if (!type)
496 {
497 DBG1(DBG_CFG, "unknown EAP method: %s", str);
498 break;
499 }
500 }
501 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
502 break;
503 case 2:
504 if (type)
505 {
506 vendor = atoi(str);
507 if (vendor)
508 {
509 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
510 }
511 else
512 {
513 DBG1(DBG_CFG, "unknown EAP vendor: %s", str);
514 }
515 }
516 break;
517 default:
518 break;
519 }
520 i++;
521 }
522 enumerator->destroy(enumerator);
523
524 if (msg->add_conn.eap_identity)
525 {
526 if (streq(msg->add_conn.eap_identity, "%identity"))
527 {
528 identity = identification_create_from_encoding(ID_ANY,
529 chunk_empty);
530 }
531 else
532 {
533 identity = identification_create_from_string(
534 msg->add_conn.eap_identity);
535 }
536 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity);
537 }
538 if (msg->add_conn.aaa_identity)
539 {
540 cfg->add(cfg, AUTH_RULE_AAA_IDENTITY,
541 identification_create_from_string(msg->add_conn.aaa_identity));
542 }
543 }
544 else
545 {
546 if (!streq(auth, "any"))
547 {
548 DBG1(DBG_CFG, "authentication method %s unknown, fallback to any",
549 auth);
550 }
551 build_crl_policy(cfg, local, msg->add_conn.crl_policy);
552 }
553 return cfg;
554 }
555
556 /**
557 * build a peer_cfg from a stroke msg
558 */
559 static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
560 stroke_msg_t *msg, ike_cfg_t *ike_cfg)
561 {
562 identification_t *peer_id = NULL;
563 peer_cfg_t *mediated_by = NULL;
564 host_t *vip = NULL;
565 unique_policy_t unique;
566 u_int32_t rekey = 0, reauth = 0, over, jitter;
567 peer_cfg_t *peer_cfg;
568 auth_cfg_t *auth_cfg;
569
570 #ifdef ME
571 if (msg->add_conn.ikeme.mediation && msg->add_conn.ikeme.mediated_by)
572 {
573 DBG1(DBG_CFG, "a mediation connection cannot be a mediated connection "
574 "at the same time, aborting");
575 return NULL;
576 }
577
578 if (msg->add_conn.ikeme.mediation)
579 {
580 /* force unique connections for mediation connections */
581 msg->add_conn.unique = 1;
582 }
583
584 if (msg->add_conn.ikeme.mediated_by)
585 {
586 mediated_by = charon->backends->get_peer_cfg_by_name(charon->backends,
587 msg->add_conn.ikeme.mediated_by);
588 if (!mediated_by)
589 {
590 DBG1(DBG_CFG, "mediation connection '%s' not found, aborting",
591 msg->add_conn.ikeme.mediated_by);
592 return NULL;
593 }
594 if (!mediated_by->is_mediation(mediated_by))
595 {
596 DBG1(DBG_CFG, "connection '%s' as referred to by '%s' is "
597 "no mediation connection, aborting",
598 msg->add_conn.ikeme.mediated_by, msg->add_conn.name);
599 mediated_by->destroy(mediated_by);
600 return NULL;
601 }
602 if (msg->add_conn.ikeme.peerid)
603 {
604 peer_id = identification_create_from_string(msg->add_conn.ikeme.peerid);
605 }
606 else if (msg->add_conn.other.id)
607 {
608 peer_id = identification_create_from_string(msg->add_conn.other.id);
609 }
610 }
611 #endif /* ME */
612
613 jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100;
614 over = msg->add_conn.rekey.margin;
615 if (msg->add_conn.rekey.reauth)
616 {
617 reauth = msg->add_conn.rekey.ike_lifetime - over;
618 }
619 else
620 {
621 rekey = msg->add_conn.rekey.ike_lifetime - over;
622 }
623 if (msg->add_conn.me.sourceip_mask)
624 {
625 if (msg->add_conn.me.sourceip)
626 {
627 vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
628 }
629 if (!vip)
630 { /* if it is set to something like %poolname, request an address */
631 if (msg->add_conn.me.subnets)
632 { /* use the same address as in subnet, if any */
633 if (strchr(msg->add_conn.me.subnets, '.'))
634 {
635 vip = host_create_any(AF_INET);
636 }
637 else
638 {
639 vip = host_create_any(AF_INET6);
640 }
641 }
642 else
643 {
644 if (strchr(ike_cfg->get_my_addr(ike_cfg), ':'))
645 {
646 vip = host_create_any(AF_INET6);
647 }
648 else
649 {
650 vip = host_create_any(AF_INET);
651 }
652 }
653 }
654 }
655 switch (msg->add_conn.unique)
656 {
657 case 1: /* yes */
658 case 2: /* replace */
659 unique = UNIQUE_REPLACE;
660 break;
661 case 3: /* keep */
662 unique = UNIQUE_KEEP;
663 break;
664 default: /* no */
665 unique = UNIQUE_NO;
666 break;
667 }
668 if (msg->add_conn.dpd.action == 0)
669 { /* dpdaction=none disables DPD */
670 msg->add_conn.dpd.delay = 0;
671 }
672
673 /* other.sourceip is managed in stroke_attributes. If it is set, we define
674 * the pool name as the connection name, which the attribute provider
675 * uses to serve pool addresses. */
676 peer_cfg = peer_cfg_create(msg->add_conn.name,
677 msg->add_conn.ikev2 ? IKEV2 : IKEV1, ike_cfg,
678 msg->add_conn.me.sendcert, unique,
679 msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
680 msg->add_conn.mobike, msg->add_conn.dpd.delay,
681 vip, msg->add_conn.other.sourceip_mask ?
682 msg->add_conn.name : msg->add_conn.other.sourceip,
683 msg->add_conn.ikeme.mediation, mediated_by, peer_id);
684
685 /* build leftauth= */
686 auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE);
687 if (auth_cfg)
688 {
689 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
690 }
691 else
692 { /* we require at least one config on our side */
693 peer_cfg->destroy(peer_cfg);
694 return NULL;
695 }
696 /* build leftauth2= */
697 auth_cfg = build_auth_cfg(this, msg, TRUE, FALSE);
698 if (auth_cfg)
699 {
700 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, TRUE);
701 }
702 /* build rightauth= */
703 auth_cfg = build_auth_cfg(this, msg, FALSE, TRUE);
704 if (auth_cfg)
705 {
706 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
707 }
708 /* build rightauth2= */
709 auth_cfg = build_auth_cfg(this, msg, FALSE, FALSE);
710 if (auth_cfg)
711 {
712 peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
713 }
714 return peer_cfg;
715 }
716
717 /**
718 * build a traffic selector from a stroke_end
719 */
720 static void add_ts(private_stroke_config_t *this,
721 stroke_end_t *end, child_cfg_t *child_cfg, bool local)
722 {
723 traffic_selector_t *ts;
724
725 if (end->tohost)
726 {
727 ts = traffic_selector_create_dynamic(end->protocol,
728 end->port ? end->port : 0, end->port ? end->port : 65535);
729 child_cfg->add_traffic_selector(child_cfg, local, ts);
730 }
731 else
732 {
733 host_t *net;
734
735 if (!end->subnets)
736 {
737 net = host_create_from_string(end->address, 0);
738 if (net)
739 {
740 ts = traffic_selector_create_from_subnet(net, 0, end->protocol,
741 end->port);
742 child_cfg->add_traffic_selector(child_cfg, local, ts);
743 }
744 }
745 else
746 {
747 char *del, *start, *bits;
748
749 start = end->subnets;
750 do
751 {
752 int intbits = 0;
753
754 del = strchr(start, ',');
755 if (del)
756 {
757 *del = '\0';
758 }
759 bits = strchr(start, '/');
760 if (bits)
761 {
762 *bits = '\0';
763 intbits = atoi(bits + 1);
764 }
765
766 net = host_create_from_string(start, 0);
767 if (net)
768 {
769 ts = traffic_selector_create_from_subnet(net, intbits,
770 end->protocol, end->port);
771 child_cfg->add_traffic_selector(child_cfg, local, ts);
772 }
773 else
774 {
775 DBG1(DBG_CFG, "invalid subnet: %s, skipped", start);
776 }
777 start = del + 1;
778 }
779 while (del);
780 }
781 }
782 }
783
784 /**
785 * map starter magic values to our action type
786 */
787 static action_t map_action(int starter_action)
788 {
789 switch (starter_action)
790 {
791 case 2: /* =hold */
792 return ACTION_ROUTE;
793 case 3: /* =restart */
794 return ACTION_RESTART;
795 default:
796 return ACTION_NONE;
797 }
798 }
799
800 /**
801 * build a child config from the stroke message
802 */
803 static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
804 stroke_msg_t *msg)
805 {
806 child_cfg_t *child_cfg;
807 lifetime_cfg_t lifetime = {
808 .time = {
809 .life = msg->add_conn.rekey.ipsec_lifetime,
810 .rekey = msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
811 .jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100
812 },
813 .bytes = {
814 .life = msg->add_conn.rekey.life_bytes,
815 .rekey = msg->add_conn.rekey.life_bytes - msg->add_conn.rekey.margin_bytes,
816 .jitter = msg->add_conn.rekey.margin_bytes * msg->add_conn.rekey.fuzz / 100
817 },
818 .packets = {
819 .life = msg->add_conn.rekey.life_packets,
820 .rekey = msg->add_conn.rekey.life_packets - msg->add_conn.rekey.margin_packets,
821 .jitter = msg->add_conn.rekey.margin_packets * msg->add_conn.rekey.fuzz / 100
822 }
823 };
824 mark_t mark_in = {
825 .value = msg->add_conn.mark_in.value,
826 .mask = msg->add_conn.mark_in.mask
827 };
828 mark_t mark_out = {
829 .value = msg->add_conn.mark_out.value,
830 .mask = msg->add_conn.mark_out.mask
831 };
832
833 child_cfg = child_cfg_create(
834 msg->add_conn.name, &lifetime, msg->add_conn.me.updown,
835 msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE,
836 map_action(msg->add_conn.dpd.action),
837 map_action(msg->add_conn.close_action), msg->add_conn.ipcomp,
838 msg->add_conn.inactivity, msg->add_conn.reqid,
839 &mark_in, &mark_out, msg->add_conn.tfc);
840 child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
841 msg->add_conn.install_policy);
842 add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
843 add_ts(this, &msg->add_conn.other, child_cfg, FALSE);
844
845 add_proposals(this, msg->add_conn.algorithms.esp, NULL, child_cfg);
846
847 return child_cfg;
848 }
849
850 METHOD(stroke_config_t, add, void,
851 private_stroke_config_t *this, stroke_msg_t *msg)
852 {
853 ike_cfg_t *ike_cfg, *existing_ike;
854 peer_cfg_t *peer_cfg, *existing;
855 child_cfg_t *child_cfg;
856 enumerator_t *enumerator;
857 bool use_existing = FALSE;
858
859 ike_cfg = build_ike_cfg(this, msg);
860 if (!ike_cfg)
861 {
862 return;
863 }
864 peer_cfg = build_peer_cfg(this, msg, ike_cfg);
865 if (!peer_cfg)
866 {
867 ike_cfg->destroy(ike_cfg);
868 return;
869 }
870
871 enumerator = create_peer_cfg_enumerator(this, NULL, NULL);
872 while (enumerator->enumerate(enumerator, &existing))
873 {
874 existing_ike = existing->get_ike_cfg(existing);
875 if (existing->equals(existing, peer_cfg) &&
876 existing_ike->equals(existing_ike, peer_cfg->get_ike_cfg(peer_cfg)))
877 {
878 use_existing = TRUE;
879 peer_cfg->destroy(peer_cfg);
880 peer_cfg = existing;
881 peer_cfg->get_ref(peer_cfg);
882 DBG1(DBG_CFG, "added child to existing configuration '%s'",
883 peer_cfg->get_name(peer_cfg));
884 break;
885 }
886 }
887 enumerator->destroy(enumerator);
888
889 child_cfg = build_child_cfg(this, msg);
890 if (!child_cfg)
891 {
892 peer_cfg->destroy(peer_cfg);
893 return;
894 }
895 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
896
897 if (use_existing)
898 {
899 peer_cfg->destroy(peer_cfg);
900 }
901 else
902 {
903 /* add config to backend */
904 DBG1(DBG_CFG, "added configuration '%s'", msg->add_conn.name);
905 this->mutex->lock(this->mutex);
906 this->list->insert_last(this->list, peer_cfg);
907 this->mutex->unlock(this->mutex);
908 }
909 }
910
911 METHOD(stroke_config_t, del, void,
912 private_stroke_config_t *this, stroke_msg_t *msg)
913 {
914 enumerator_t *enumerator, *children;
915 peer_cfg_t *peer;
916 child_cfg_t *child;
917 bool deleted = FALSE;
918
919 this->mutex->lock(this->mutex);
920 enumerator = this->list->create_enumerator(this->list);
921 while (enumerator->enumerate(enumerator, (void**)&peer))
922 {
923 bool keep = FALSE;
924
925 /* remove any child with such a name */
926 children = peer->create_child_cfg_enumerator(peer);
927 while (children->enumerate(children, &child))
928 {
929 if (streq(child->get_name(child), msg->del_conn.name))
930 {
931 peer->remove_child_cfg(peer, children);
932 child->destroy(child);
933 deleted = TRUE;
934 }
935 else
936 {
937 keep = TRUE;
938 }
939 }
940 children->destroy(children);
941
942 /* if peer config matches, or has no children anymore, remove it */
943 if (!keep || streq(peer->get_name(peer), msg->del_conn.name))
944 {
945 this->list->remove_at(this->list, enumerator);
946 peer->destroy(peer);
947 deleted = TRUE;
948 }
949 }
950 enumerator->destroy(enumerator);
951 this->mutex->unlock(this->mutex);
952
953 if (deleted)
954 {
955 DBG1(DBG_CFG, "deleted connection '%s'", msg->del_conn.name);
956 }
957 else
958 {
959 DBG1(DBG_CFG, "connection '%s' not found", msg->del_conn.name);
960 }
961 }
962
963 METHOD(stroke_config_t, destroy, void,
964 private_stroke_config_t *this)
965 {
966 this->list->destroy_offset(this->list, offsetof(peer_cfg_t, destroy));
967 this->mutex->destroy(this->mutex);
968 free(this);
969 }
970
971 /*
972 * see header file
973 */
974 stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred)
975 {
976 private_stroke_config_t *this;
977
978 INIT(this,
979 .public = {
980 .backend = {
981 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
982 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
983 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
984 },
985 .add = _add,
986 .del = _del,
987 .destroy = _destroy,
988 },
989 .list = linked_list_create(),
990 .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
991 .ca = ca,
992 .cred = cred,
993 );
994
995 return &this->public;
996 }
997