2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
16 #include "stroke_config.h"
19 #include <threading/mutex.h>
20 #include <utils/lexparser.h>
22 typedef struct private_stroke_config_t private_stroke_config_t
;
25 * private data of stroke_config
27 struct private_stroke_config_t
{
32 stroke_config_t
public;
40 * mutex to lock config list
56 * Implementation of backend_t.create_peer_cfg_enumerator.
58 static enumerator_t
* create_peer_cfg_enumerator(private_stroke_config_t
*this,
60 identification_t
*other
)
62 this->mutex
->lock(this->mutex
);
63 return enumerator_create_cleaner(this->list
->create_enumerator(this->list
),
64 (void*)this->mutex
->unlock
, this->mutex
);
68 * filter function for ike configs
70 static bool ike_filter(void *data
, peer_cfg_t
**in
, ike_cfg_t
**out
)
72 *out
= (*in
)->get_ike_cfg(*in
);
77 * Implementation of backend_t.create_ike_cfg_enumerator.
79 static enumerator_t
* create_ike_cfg_enumerator(private_stroke_config_t
*this,
80 host_t
*me
, host_t
*other
)
82 this->mutex
->lock(this->mutex
);
83 return enumerator_create_filter(this->list
->create_enumerator(this->list
),
84 (void*)ike_filter
, this->mutex
,
85 (void*)this->mutex
->unlock
);
89 * implements backend_t.get_peer_cfg_by_name.
91 static peer_cfg_t
*get_peer_cfg_by_name(private_stroke_config_t
*this, char *name
)
93 enumerator_t
*e1
, *e2
;
94 peer_cfg_t
*current
, *found
= NULL
;
97 this->mutex
->lock(this->mutex
);
98 e1
= this->list
->create_enumerator(this->list
);
99 while (e1
->enumerate(e1
, ¤t
))
101 /* compare peer_cfgs name first */
102 if (streq(current
->get_name(current
), name
))
105 found
->get_ref(found
);
108 /* compare all child_cfg names otherwise */
109 e2
= current
->create_child_cfg_enumerator(current
);
110 while (e2
->enumerate(e2
, &child
))
112 if (streq(child
->get_name(child
), name
))
115 found
->get_ref(found
);
126 this->mutex
->unlock(this->mutex
);
131 * parse a proposal string, either into ike_cfg or child_cfg
133 static void add_proposals(private_stroke_config_t
*this, char *string
,
134 ike_cfg_t
*ike_cfg
, child_cfg_t
*child_cfg
)
140 proposal_t
*proposal
;
141 protocol_id_t proto
= PROTO_ESP
;
147 strict
= string
+ strlen(string
) - 1;
156 while ((single
= strsep(&string
, ",")))
158 proposal
= proposal_create_from_string(proto
, single
);
163 ike_cfg
->add_proposal(ike_cfg
, proposal
);
167 child_cfg
->add_proposal(child_cfg
, proposal
);
171 DBG1(DBG_CFG
, "skipped invalid proposal string: %s", single
);
177 /* add default porposal to the end if not strict */
181 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
185 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
190 * Build an IKE config from a stroke message
192 static ike_cfg_t
*build_ike_cfg(private_stroke_config_t
*this, stroke_msg_t
*msg
)
194 stroke_end_t tmp_end
;
199 host
= host_create_from_dns(msg
->add_conn
.other
.address
, 0, 0);
202 interface
= charon
->kernel_interface
->get_interface(
203 charon
->kernel_interface
, host
);
207 DBG2(DBG_CFG
, "left is other host, swapping ends");
208 tmp_end
= msg
->add_conn
.me
;
209 msg
->add_conn
.me
= msg
->add_conn
.other
;
210 msg
->add_conn
.other
= tmp_end
;
215 host
= host_create_from_dns(msg
->add_conn
.me
.address
, 0, 0);
218 interface
= charon
->kernel_interface
->get_interface(
219 charon
->kernel_interface
, host
);
223 DBG1(DBG_CFG
, "left nor right host is our side, "
224 "assuming left=local");
234 ike_cfg
= ike_cfg_create(msg
->add_conn
.other
.sendcert
!= CERT_NEVER_SEND
,
235 msg
->add_conn
.force_encap
,
236 msg
->add_conn
.me
.address
, msg
->add_conn
.me
.ikeport
,
237 msg
->add_conn
.other
.address
, msg
->add_conn
.other
.ikeport
);
238 add_proposals(this, msg
->add_conn
.algorithms
.ike
, ike_cfg
, NULL
);
243 * Add CRL constraint to config
245 static void build_crl_policy(auth_cfg_t
*cfg
, bool local
, int policy
)
247 /* CRL/OCSP policy, for remote config only */
253 /* if yes, we require a GOOD validation */
254 cfg
->add(cfg
, AUTH_RULE_CRL_VALIDATION
, VALIDATION_GOOD
);
256 case CRL_STRICT_IFURI
:
257 /* for ifuri, a SKIPPED validation is sufficient */
258 cfg
->add(cfg
, AUTH_RULE_CRL_VALIDATION
, VALIDATION_SKIPPED
);
267 * build authentication config
269 static auth_cfg_t
*build_auth_cfg(private_stroke_config_t
*this,
270 stroke_msg_t
*msg
, bool local
, bool primary
)
272 identification_t
*identity
;
273 certificate_t
*certificate
;
274 char *auth
, *id
, *cert
, *ca
;
275 stroke_end_t
*end
, *other_end
;
282 end
= &msg
->add_conn
.me
;
283 other_end
= &msg
->add_conn
.other
;
287 end
= &msg
->add_conn
.other
;
288 other_end
= &msg
->add_conn
.me
;
295 { /* leftid/rightid fallback to address */
300 if (ca
&& streq(ca
, "%same"))
310 { /* leftid2 falls back to leftid */
315 if (ca
&& streq(ca
, "%same"))
326 { /* "leftauth" not defined, fall back to deprecated "authby" */
327 switch (msg
->add_conn
.auth_method
)
330 case AUTH_CLASS_PUBKEY
:
342 { /* "rightauth" not defined, fall back to deprecated "eap" */
343 if (msg
->add_conn
.eap_type
)
345 if (msg
->add_conn
.eap_vendor
)
347 snprintf(eap_buf
, sizeof(eap_buf
), "eap-%d-%d",
348 msg
->add_conn
.eap_type
,
349 msg
->add_conn
.eap_vendor
);
353 snprintf(eap_buf
, sizeof(eap_buf
), "eap-%d",
354 msg
->add_conn
.eap_type
);
359 { /* not EAP => no constraints for this peer */
365 { /* no second authentication round, fine */
370 cfg
= auth_cfg_create();
372 /* add identity and peer certifcate */
373 identity
= identification_create_from_string(id
);
376 certificate
= this->cred
->load_peer(this->cred
, cert
);
381 this->ca
->check_for_hash_and_url(this->ca
, certificate
);
383 cfg
->add(cfg
, AUTH_RULE_SUBJECT_CERT
, certificate
);
384 if (identity
->get_type(identity
) == ID_ANY
||
385 !certificate
->has_subject(certificate
, identity
))
387 DBG1(DBG_CFG
, " id '%Y' not confirmed by certificate, "
388 "defaulting to '%Y'", identity
,
389 certificate
->get_subject(certificate
));
390 identity
->destroy(identity
);
391 identity
= certificate
->get_subject(certificate
);
392 identity
= identity
->clone(identity
);
396 cfg
->add(cfg
, AUTH_RULE_IDENTITY
, identity
);
401 identity
= identification_create_from_string(ca
);
402 certificate
= charon
->credentials
->get_cert(charon
->credentials
,
403 CERT_X509
, KEY_ANY
, identity
, TRUE
);
404 identity
->destroy(identity
);
407 cfg
->add(cfg
, AUTH_RULE_CA_CERT
, certificate
);
411 DBG1(DBG_CFG
, "CA certificate %s not found, discarding CA "
419 enumerator_t
*enumerator
;
422 enumerator
= enumerator_create_token(end
->groups
, ",", " ");
423 while (enumerator
->enumerate(enumerator
, &group
))
425 identity
= identification_create_from_encoding(ID_IETF_ATTR_STRING
,
426 chunk_create(group
, strlen(group
)));
427 cfg
->add(cfg
, AUTH_RULE_AC_GROUP
, identity
);
429 enumerator
->destroy(enumerator
);
432 /* authentication metod (class, actually) */
433 if (streq(auth
, "pubkey") ||
434 streq(auth
, "rsasig") || streq(auth
, "rsa") ||
435 streq(auth
, "ecdsasig") || streq(auth
, "ecdsa"))
437 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
438 build_crl_policy(cfg
, local
, msg
->add_conn
.crl_policy
);
440 else if (streq(auth
, "psk") || streq(auth
, "secret"))
442 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
444 else if (strneq(auth
, "eap", 3))
446 enumerator_t
*enumerator
;
448 int i
= 0, type
= 0, vendor
;
450 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
452 /* parse EAP string, format: eap[-type[-vendor]] */
453 enumerator
= enumerator_create_token(auth
, "-", " ");
454 while (enumerator
->enumerate(enumerator
, &str
))
459 type
= eap_type_from_string(str
);
465 DBG1(DBG_CFG
, "unknown EAP method: %s", str
);
469 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
);
477 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, vendor
);
481 DBG1(DBG_CFG
, "unknown EAP vendor: %s", str
);
490 enumerator
->destroy(enumerator
);
492 if (msg
->add_conn
.eap_identity
)
494 if (streq(msg
->add_conn
.eap_identity
, "%identity"))
496 identity
= identification_create_from_encoding(ID_ANY
,
501 identity
= identification_create_from_string(
502 msg
->add_conn
.eap_identity
);
504 cfg
->add(cfg
, AUTH_RULE_EAP_IDENTITY
, identity
);
509 if (!streq(auth
, "any"))
511 DBG1(DBG_CFG
, "authentication method %s unknown, fallback to any",
514 build_crl_policy(cfg
, local
, msg
->add_conn
.crl_policy
);
520 * build a peer_cfg from a stroke msg
522 static peer_cfg_t
*build_peer_cfg(private_stroke_config_t
*this,
523 stroke_msg_t
*msg
, ike_cfg_t
*ike_cfg
)
525 identification_t
*peer_id
= NULL
;
526 peer_cfg_t
*mediated_by
= NULL
;
528 unique_policy_t unique
;
529 u_int32_t rekey
= 0, reauth
= 0, over
, jitter
;
530 peer_cfg_t
*peer_cfg
;
531 auth_cfg_t
*auth_cfg
;
534 if (msg
->add_conn
.ikeme
.mediation
&& msg
->add_conn
.ikeme
.mediated_by
)
536 DBG1(DBG_CFG
, "a mediation connection cannot be a mediated connection "
537 "at the same time, aborting");
541 if (msg
->add_conn
.ikeme
.mediation
)
543 /* force unique connections for mediation connections */
544 msg
->add_conn
.unique
= 1;
547 if (msg
->add_conn
.ikeme
.mediated_by
)
549 mediated_by
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
550 msg
->add_conn
.ikeme
.mediated_by
);
553 DBG1(DBG_CFG
, "mediation connection '%s' not found, aborting",
554 msg
->add_conn
.ikeme
.mediated_by
);
557 if (!mediated_by
->is_mediation(mediated_by
))
559 DBG1(DBG_CFG
, "connection '%s' as referred to by '%s' is "
560 "no mediation connection, aborting",
561 msg
->add_conn
.ikeme
.mediated_by
, msg
->add_conn
.name
);
562 mediated_by
->destroy(mediated_by
);
565 if (msg
->add_conn
.ikeme
.peerid
)
567 peer_id
= identification_create_from_string(msg
->add_conn
.ikeme
.peerid
);
569 else if (msg
->add_conn
.other
.id
)
571 peer_id
= identification_create_from_string(msg
->add_conn
.other
.id
);
576 jitter
= msg
->add_conn
.rekey
.margin
* msg
->add_conn
.rekey
.fuzz
/ 100;
577 over
= msg
->add_conn
.rekey
.margin
;
578 if (msg
->add_conn
.rekey
.reauth
)
580 reauth
= msg
->add_conn
.rekey
.ike_lifetime
- over
;
584 rekey
= msg
->add_conn
.rekey
.ike_lifetime
- over
;
586 if (msg
->add_conn
.me
.sourceip_mask
)
588 if (msg
->add_conn
.me
.sourceip
)
590 vip
= host_create_from_string(msg
->add_conn
.me
.sourceip
, 0);
593 { /* if it is set to something like %poolname, request an address */
594 if (msg
->add_conn
.me
.subnets
)
595 { /* use the same address as in subnet, if any */
596 if (strchr(msg
->add_conn
.me
.subnets
, '.'))
598 vip
= host_create_any(AF_INET
);
602 vip
= host_create_any(AF_INET6
);
607 if (strchr(ike_cfg
->get_my_addr(ike_cfg
), ':'))
609 vip
= host_create_any(AF_INET6
);
613 vip
= host_create_any(AF_INET
);
618 switch (msg
->add_conn
.unique
)
621 case 2: /* replace */
622 unique
= UNIQUE_REPLACE
;
625 unique
= UNIQUE_KEEP
;
631 if (msg
->add_conn
.dpd
.action
== 0)
632 { /* dpdaction=none disables DPD */
633 msg
->add_conn
.dpd
.delay
= 0;
636 /* other.sourceip is managed in stroke_attributes. If it is set, we define
637 * the pool name as the connection name, which the attribute provider
638 * uses to serve pool addresses. */
639 peer_cfg
= peer_cfg_create(msg
->add_conn
.name
,
640 msg
->add_conn
.ikev2
? 2 : 1, ike_cfg
,
641 msg
->add_conn
.me
.sendcert
, unique
,
642 msg
->add_conn
.rekey
.tries
, rekey
, reauth
, jitter
, over
,
643 msg
->add_conn
.mobike
, msg
->add_conn
.dpd
.delay
,
644 vip
, msg
->add_conn
.other
.sourceip_mask
?
645 msg
->add_conn
.name
: msg
->add_conn
.other
.sourceip
,
646 msg
->add_conn
.ikeme
.mediation
, mediated_by
, peer_id
);
648 /* build leftauth= */
649 auth_cfg
= build_auth_cfg(this, msg
, TRUE
, TRUE
);
652 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, TRUE
);
655 { /* we require at least one config on our side */
656 peer_cfg
->destroy(peer_cfg
);
659 /* build leftauth2= */
660 auth_cfg
= build_auth_cfg(this, msg
, TRUE
, FALSE
);
663 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, TRUE
);
665 /* build rightauth= */
666 auth_cfg
= build_auth_cfg(this, msg
, FALSE
, TRUE
);
669 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, FALSE
);
671 /* build rightauth2= */
672 auth_cfg
= build_auth_cfg(this, msg
, FALSE
, FALSE
);
675 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, FALSE
);
681 * build a traffic selector from a stroke_end
683 static void add_ts(private_stroke_config_t
*this,
684 stroke_end_t
*end
, child_cfg_t
*child_cfg
, bool local
)
686 traffic_selector_t
*ts
;
690 ts
= traffic_selector_create_dynamic(end
->protocol
,
691 end
->port
? end
->port
: 0, end
->port
? end
->port
: 65535);
692 child_cfg
->add_traffic_selector(child_cfg
, local
, ts
);
700 net
= host_create_from_string(end
->address
, 0);
703 ts
= traffic_selector_create_from_subnet(net
, 0, end
->protocol
,
705 child_cfg
->add_traffic_selector(child_cfg
, local
, ts
);
710 char *del
, *start
, *bits
;
712 start
= end
->subnets
;
717 del
= strchr(start
, ',');
722 bits
= strchr(start
, '/');
726 intbits
= atoi(bits
+ 1);
729 net
= host_create_from_string(start
, 0);
732 ts
= traffic_selector_create_from_subnet(net
, intbits
,
733 end
->protocol
, end
->port
);
734 child_cfg
->add_traffic_selector(child_cfg
, local
, ts
);
738 DBG1(DBG_CFG
, "invalid subnet: %s, skipped", start
);
748 * build a child config from the stroke message
750 static child_cfg_t
*build_child_cfg(private_stroke_config_t
*this,
753 child_cfg_t
*child_cfg
;
755 lifetime_cfg_t lifetime
= {
757 .life
= msg
->add_conn
.rekey
.ipsec_lifetime
,
758 .rekey
= msg
->add_conn
.rekey
.ipsec_lifetime
- msg
->add_conn
.rekey
.margin
,
759 .jitter
= msg
->add_conn
.rekey
.margin
* msg
->add_conn
.rekey
.fuzz
/ 100
762 .life
= msg
->add_conn
.rekey
.life_bytes
,
763 .rekey
= msg
->add_conn
.rekey
.life_bytes
- msg
->add_conn
.rekey
.margin_bytes
,
764 .jitter
= msg
->add_conn
.rekey
.margin_bytes
* msg
->add_conn
.rekey
.fuzz
/ 100
767 .life
= msg
->add_conn
.rekey
.life_packets
,
768 .rekey
= msg
->add_conn
.rekey
.life_packets
- msg
->add_conn
.rekey
.margin_packets
,
769 .jitter
= msg
->add_conn
.rekey
.margin_packets
* msg
->add_conn
.rekey
.fuzz
/ 100
773 switch (msg
->add_conn
.dpd
.action
)
774 { /* map startes magic values to our action type */
778 case 3: /* =restart */
779 dpd
= ACTION_RESTART
;
786 child_cfg
= child_cfg_create(
787 msg
->add_conn
.name
, &lifetime
,
788 msg
->add_conn
.me
.updown
, msg
->add_conn
.me
.hostaccess
,
789 msg
->add_conn
.mode
, dpd
, dpd
, msg
->add_conn
.ipcomp
,
790 msg
->add_conn
.inactivity
, msg
->add_conn
.reqid
);
791 child_cfg
->set_mipv6_options(child_cfg
, msg
->add_conn
.proxy_mode
,
792 msg
->add_conn
.install_policy
);
793 add_ts(this, &msg
->add_conn
.me
, child_cfg
, TRUE
);
794 add_ts(this, &msg
->add_conn
.other
, child_cfg
, FALSE
);
796 add_proposals(this, msg
->add_conn
.algorithms
.esp
, NULL
, child_cfg
);
802 * Implementation of stroke_config_t.add.
804 static void add(private_stroke_config_t
*this, stroke_msg_t
*msg
)
806 ike_cfg_t
*ike_cfg
, *existing_ike
;
807 peer_cfg_t
*peer_cfg
, *existing
;
808 child_cfg_t
*child_cfg
;
809 enumerator_t
*enumerator
;
810 bool use_existing
= FALSE
;
812 ike_cfg
= build_ike_cfg(this, msg
);
817 peer_cfg
= build_peer_cfg(this, msg
, ike_cfg
);
820 ike_cfg
->destroy(ike_cfg
);
824 enumerator
= create_peer_cfg_enumerator(this, NULL
, NULL
);
825 while (enumerator
->enumerate(enumerator
, &existing
))
827 existing_ike
= existing
->get_ike_cfg(existing
);
828 if (existing
->equals(existing
, peer_cfg
) &&
829 existing_ike
->equals(existing_ike
, peer_cfg
->get_ike_cfg(peer_cfg
)))
832 peer_cfg
->destroy(peer_cfg
);
834 peer_cfg
->get_ref(peer_cfg
);
835 DBG1(DBG_CFG
, "added child to existing configuration '%s'",
836 peer_cfg
->get_name(peer_cfg
));
840 enumerator
->destroy(enumerator
);
842 child_cfg
= build_child_cfg(this, msg
);
845 peer_cfg
->destroy(peer_cfg
);
848 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
852 peer_cfg
->destroy(peer_cfg
);
856 /* add config to backend */
857 DBG1(DBG_CFG
, "added configuration '%s'", msg
->add_conn
.name
);
858 this->mutex
->lock(this->mutex
);
859 this->list
->insert_last(this->list
, peer_cfg
);
860 this->mutex
->unlock(this->mutex
);
865 * Implementation of stroke_config_t.del.
867 static void del(private_stroke_config_t
*this, stroke_msg_t
*msg
)
869 enumerator_t
*enumerator
, *children
;
872 bool deleted
= FALSE
;
874 this->mutex
->lock(this->mutex
);
875 enumerator
= this->list
->create_enumerator(this->list
);
876 while (enumerator
->enumerate(enumerator
, (void**)&peer
))
880 /* remove any child with such a name */
881 children
= peer
->create_child_cfg_enumerator(peer
);
882 while (children
->enumerate(children
, &child
))
884 if (streq(child
->get_name(child
), msg
->del_conn
.name
))
886 peer
->remove_child_cfg(peer
, children
);
887 child
->destroy(child
);
895 children
->destroy(children
);
897 /* if peer config matches, or has no children anymore, remove it */
898 if (!keep
|| streq(peer
->get_name(peer
), msg
->del_conn
.name
))
900 this->list
->remove_at(this->list
, enumerator
);
905 enumerator
->destroy(enumerator
);
906 this->mutex
->unlock(this->mutex
);
910 DBG1(DBG_CFG
, "deleted connection '%s'", msg
->del_conn
.name
);
914 DBG1(DBG_CFG
, "connection '%s' not found", msg
->del_conn
.name
);
919 * Implementation of stroke_config_t.destroy
921 static void destroy(private_stroke_config_t
*this)
923 this->list
->destroy_offset(this->list
, offsetof(peer_cfg_t
, destroy
));
924 this->mutex
->destroy(this->mutex
);
931 stroke_config_t
*stroke_config_create(stroke_ca_t
*ca
, stroke_cred_t
*cred
)
933 private_stroke_config_t
*this = malloc_thing(private_stroke_config_t
);
935 this->public.backend
.create_peer_cfg_enumerator
= (enumerator_t
*(*)(backend_t
*, identification_t
*me
, identification_t
*other
))create_peer_cfg_enumerator
;
936 this->public.backend
.create_ike_cfg_enumerator
= (enumerator_t
*(*)(backend_t
*, host_t
*me
, host_t
*other
))create_ike_cfg_enumerator
;
937 this->public.backend
.get_peer_cfg_by_name
= (peer_cfg_t
* (*)(backend_t
*,char*))get_peer_cfg_by_name
;
938 this->public.add
= (void(*)(stroke_config_t
*, stroke_msg_t
*msg
))add
;
939 this->public.del
= (void(*)(stroke_config_t
*, stroke_msg_t
*msg
))del
;
940 this->public.destroy
= (void(*)(stroke_config_t
*))destroy
;
942 this->list
= linked_list_create();
943 this->mutex
= mutex_create(MUTEX_TYPE_RECURSIVE
);
947 return &this->public;