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
18 #include "stroke_config.h"
21 #include <utils/mutex.h>
23 typedef struct private_stroke_config_t private_stroke_config_t
;
26 * private data of stroke_config
28 struct private_stroke_config_t
{
33 stroke_config_t
public;
41 * mutex to lock config list
52 * data to pass peer_filter
55 private_stroke_config_t
*this;
57 identification_t
*other
;
61 * destroy id enumerator data and unlock list
63 static void peer_data_destroy(peer_data_t
*data
)
65 data
->this->mutex
->unlock(data
->this->mutex
);
70 * filter function for peer configs
72 static bool peer_filter(peer_data_t
*data
, peer_cfg_t
**in
, peer_cfg_t
**out
)
74 bool match_me
= FALSE
, match_other
= FALSE
;
75 identification_t
*me
, *other
;
77 me
= (*in
)->get_my_id(*in
);
78 other
= (*in
)->get_other_id(*in
);
80 /* own ID may have wildcards in data (no IDr payload) or in config */
81 match_me
= (!data
->me
|| data
->me
->matches(data
->me
, me
) ||
82 me
->matches(me
, data
->me
));
83 /* others ID has wildcards in config only */
84 match_other
= (!data
->other
|| data
->other
->matches(data
->other
, other
));
86 if (match_me
&& match_other
)
95 * Implementation of backend_t.create_peer_cfg_enumerator.
97 static enumerator_t
* create_peer_cfg_enumerator(private_stroke_config_t
*this,
99 identification_t
*other
)
103 data
= malloc_thing(peer_data_t
);
108 this->mutex
->lock(this->mutex
);
109 return enumerator_create_filter(this->list
->create_enumerator(this->list
),
110 (void*)peer_filter
, data
,
111 (void*)peer_data_destroy
);
115 * data to pass ike_filter
118 private_stroke_config_t
*this;
124 * destroy id enumerator data and unlock list
126 static void ike_data_destroy(ike_data_t
*data
)
128 data
->this->mutex
->unlock(data
->this->mutex
);
133 * filter function for ike configs
135 static bool ike_filter(ike_data_t
*data
, peer_cfg_t
**in
, ike_cfg_t
**out
)
140 ike_cfg
= (*in
)->get_ike_cfg(*in
);
142 me
= ike_cfg
->get_my_host(ike_cfg
);
143 other
= ike_cfg
->get_other_host(ike_cfg
);
144 if ((!data
->me
|| me
->is_anyaddr(me
) || me
->ip_equals(me
, data
->me
)) &&
145 (!data
->other
|| other
->is_anyaddr(other
) || other
->ip_equals(other
, data
->other
)))
154 * Implementation of backend_t.create_ike_cfg_enumerator.
156 static enumerator_t
* create_ike_cfg_enumerator(private_stroke_config_t
*this,
157 host_t
*me
, host_t
*other
)
161 data
= malloc_thing(ike_data_t
);
166 this->mutex
->lock(this->mutex
);
167 return enumerator_create_filter(this->list
->create_enumerator(this->list
),
168 (void*)ike_filter
, data
,
169 (void*)ike_data_destroy
);
173 * implements backend_t.get_peer_cfg_by_name.
175 static peer_cfg_t
*get_peer_cfg_by_name(private_stroke_config_t
*this, char *name
)
177 enumerator_t
*e1
, *e2
;
178 peer_cfg_t
*current
, *found
= NULL
;
181 this->mutex
->lock(this->mutex
);
182 e1
= this->list
->create_enumerator(this->list
);
183 while (e1
->enumerate(e1
, ¤t
))
185 /* compare peer_cfgs name first */
186 if (streq(current
->get_name(current
), name
))
189 found
->get_ref(found
);
192 /* compare all child_cfg names otherwise */
193 e2
= current
->create_child_cfg_enumerator(current
);
194 while (e2
->enumerate(e2
, &child
))
196 if (streq(child
->get_name(child
), name
))
199 found
->get_ref(found
);
210 this->mutex
->unlock(this->mutex
);
215 * check if a certificate has an ID
217 static identification_t
*update_peerid(certificate_t
*cert
, identification_t
*id
)
219 if (!cert
->has_subject(cert
, id
))
221 DBG1(DBG_CFG
, " peerid %D not confirmed by certificate, "
222 "defaulting to subject DN", id
);
224 id
= cert
->get_subject(cert
);
225 return id
->clone(id
);
231 * parse a proposal string, either into ike_cfg or child_cfg
233 static void add_proposals(private_stroke_config_t
*this, char *string
,
234 ike_cfg_t
*ike_cfg
, child_cfg_t
*child_cfg
)
240 proposal_t
*proposal
;
241 protocol_id_t proto
= PROTO_ESP
;
247 strict
= string
+ strlen(string
) - 1;
256 while ((single
= strsep(&string
, ",")))
258 proposal
= proposal_create_from_string(proto
, single
);
263 ike_cfg
->add_proposal(ike_cfg
, proposal
);
267 child_cfg
->add_proposal(child_cfg
, proposal
);
271 DBG1(DBG_CFG
, "skipped invalid proposal string: %s", single
);
277 /* add default porposal to the end if not strict */
281 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
285 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
290 * Build an IKE config from a stroke message
292 static ike_cfg_t
*build_ike_cfg(private_stroke_config_t
*this, stroke_msg_t
*msg
)
294 host_t
*me
= NULL
, *other
= NULL
, *tmp
;
295 stroke_end_t tmp_end
;
299 if (msg
->add_conn
.me
.address
)
301 me
= host_create_from_string(msg
->add_conn
.me
.address
, IKEV2_UDP_PORT
);
305 DBG1(DBG_CFG
, "invalid left host: %s", msg
->add_conn
.me
.address
);
308 if (msg
->add_conn
.other
.address
)
310 other
= host_create_from_string(msg
->add_conn
.other
.address
, IKEV2_UDP_PORT
);
314 DBG1(DBG_CFG
, "invalid right host: %s", msg
->add_conn
.other
.address
);
318 interface
= charon
->kernel_interface
->get_interface(
319 charon
->kernel_interface
, other
);
322 DBG2(DBG_CFG
, "left is other host, swapping ends");
326 tmp_end
= msg
->add_conn
.me
;
327 msg
->add_conn
.me
= msg
->add_conn
.other
;
328 msg
->add_conn
.other
= tmp_end
;
333 interface
= charon
->kernel_interface
->get_interface(
334 charon
->kernel_interface
, me
);
337 DBG1(DBG_CFG
, "left nor right host is our side, assuming left=local");
344 ike_cfg
= ike_cfg_create(msg
->add_conn
.other
.sendcert
!= CERT_NEVER_SEND
,
345 msg
->add_conn
.force_encap
, me
, other
);
346 add_proposals(this, msg
->add_conn
.algorithms
.ike
, ike_cfg
, NULL
);
350 * build a peer_cfg from a stroke msg
352 static peer_cfg_t
*build_peer_cfg(private_stroke_config_t
*this,
353 stroke_msg_t
*msg
, ike_cfg_t
*ike_cfg
)
355 identification_t
*me
, *other
, *peer_id
= NULL
;
356 peer_cfg_t
*mediated_by
= NULL
;
357 host_t
*my_vip
= NULL
, *other_vip
= NULL
;
359 u_int32_t rekey
= 0, reauth
= 0, over
, jitter
;
361 me
= identification_create_from_string(msg
->add_conn
.me
.id ?
362 msg
->add_conn
.me
.id
: msg
->add_conn
.me
.address
);
365 DBG1(DBG_CFG
, "invalid ID: %s\n", msg
->add_conn
.me
.id
);
368 other
= identification_create_from_string(msg
->add_conn
.other
.id ?
369 msg
->add_conn
.other
.id
: msg
->add_conn
.other
.address
);
372 DBG1(DBG_CFG
, "invalid ID: %s\n", msg
->add_conn
.other
.id
);
379 if (msg
->add_conn
.p2p
.mediation
&& msg
->add_conn
.p2p
.mediated_by
)
381 DBG1(DBG_CFG
, "a mediation connection cannot be a"
382 " mediated connection at the same time, aborting");
384 other
->destroy(other
);
388 if (msg
->add_conn
.p2p
.mediated_by
)
390 mediated_by
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
,
391 msg
->add_conn
.p2p
.mediated_by
);
394 DBG1(DBG_CFG
, "mediation connection '%s' not found, aborting",
395 msg
->add_conn
.p2p
.mediated_by
);
397 other
->destroy(other
);
401 if (!mediated_by
->is_mediation(mediated_by
))
403 DBG1(DBG_CFG
, "connection '%s' as referred to by '%s' is"
404 "no mediation connection, aborting",
405 msg
->add_conn
.p2p
.mediated_by
, msg
->add_conn
.name
);
406 mediated_by
->destroy(mediated_by
);
408 other
->destroy(other
);
413 if (msg
->add_conn
.p2p
.peerid
)
415 peer_id
= identification_create_from_string(msg
->add_conn
.p2p
.peerid
);
418 DBG1(DBG_CFG
, "invalid peer ID: %s\n", msg
->add_conn
.p2p
.peerid
);
419 mediated_by
->destroy(mediated_by
);
421 other
->destroy(other
);
427 /* no peer ID supplied, assume right ID */
428 peer_id
= other_id
->clone(other_id
);
432 if (msg
->add_conn
.me
.cert
)
434 cert
= this->cred
->load_peer(this->cred
, msg
->add_conn
.me
.cert
);
437 me
= update_peerid(cert
, me
);
441 if (msg
->add_conn
.other
.cert
)
443 cert
= this->cred
->load_peer(this->cred
, msg
->add_conn
.other
.cert
);
446 other
= update_peerid(cert
, other
);
450 jitter
= msg
->add_conn
.rekey
.margin
* msg
->add_conn
.rekey
.fuzz
/ 100;
451 over
= msg
->add_conn
.rekey
.margin
;
452 if (msg
->add_conn
.rekey
.reauth
)
454 reauth
= msg
->add_conn
.rekey
.ike_lifetime
- over
;
458 rekey
= msg
->add_conn
.rekey
.ike_lifetime
- over
;
460 if (msg
->add_conn
.me
.virtual_ip
&& msg
->add_conn
.me
.sourceip
)
462 my_vip
= host_create_from_string(msg
->add_conn
.me
.sourceip
, 0);
464 if (msg
->add_conn
.other
.virtual_ip
&& msg
->add_conn
.other
.sourceip
)
466 other_vip
= host_create_from_string(msg
->add_conn
.other
.sourceip
, 0);
468 return peer_cfg_create(msg
->add_conn
.name
,
469 msg
->add_conn
.ikev2 ?
2 : 1, ike_cfg
, me
, other
,
470 msg
->add_conn
.me
.sendcert
, msg
->add_conn
.auth_method
,
471 msg
->add_conn
.eap_type
, msg
->add_conn
.eap_vendor
,
472 msg
->add_conn
.rekey
.tries
, rekey
, reauth
, jitter
, over
,
473 msg
->add_conn
.mobike
, msg
->add_conn
.dpd
.delay
, msg
->add_conn
.dpd
.action
,
474 my_vip
, other_vip
, msg
->add_conn
.p2p
.mediation
, mediated_by
, peer_id
);
478 * fill in auth_info from stroke message
480 static void build_auth_info(private_stroke_config_t
*this,
481 stroke_msg_t
*msg
, auth_info_t
*auth
)
483 identification_t
*my_ca
= NULL
, *other_ca
= NULL
;
484 bool my_ca_same
= FALSE
;
485 bool other_ca_same
= FALSE
;
486 cert_validation_t valid
;
488 if (msg
->add_conn
.other
.groups
)
490 /* TODO: AC groups */
493 switch (msg
->add_conn
.crl_policy
)
496 valid
= VALIDATION_GOOD
;
497 auth
->add_item(auth
, AUTHZ_CRL_VALIDATION
, &valid
);
499 case CRL_STRICT_IFURI
:
500 valid
= VALIDATION_SKIPPED
;
501 auth
->add_item(auth
, AUTHZ_CRL_VALIDATION
, &valid
);
507 if (msg
->add_conn
.me
.ca
)
509 if (streq(msg
->add_conn
.me
.ca
, "%same"))
515 my_ca
= identification_create_from_string(msg
->add_conn
.me
.ca
);
518 if (msg
->add_conn
.other
.ca
)
520 if (streq(msg
->add_conn
.other
.ca
, "%same"))
522 other_ca_same
= TRUE
;
526 other_ca
= identification_create_from_string(msg
->add_conn
.other
.ca
);
529 if (other_ca_same
&& my_ca
)
531 other_ca
= my_ca
->clone(my_ca
);
533 else if (my_ca_same
&& other_ca
)
535 my_ca
= other_ca
->clone(other_ca
);
540 DBG2(DBG_CFG
, " other ca: %D", other_ca
);
541 certificate_t
*cert
= charon
->credentials
->get_cert(charon
->credentials
,
542 CERT_X509
, KEY_ANY
, other_ca
, TRUE
);
545 auth
->add_item(auth
, AUTHZ_CA_CERT
, cert
);
550 auth
->add_item(auth
, AUTHZ_CA_CERT_NAME
, other_ca
);
552 other_ca
->destroy(other_ca
);
556 DBG2(DBG_CFG
, " my ca: %D", my_ca
);
557 certificate_t
*cert
= charon
->credentials
->get_cert(charon
->credentials
,
558 CERT_X509
, KEY_ANY
, my_ca
, TRUE
);
561 auth
->add_item(auth
, AUTHN_CA_CERT
, cert
);
566 auth
->add_item(auth
, AUTHN_CA_CERT_NAME
, my_ca
);
568 my_ca
->destroy(my_ca
);
573 * build a traffic selector from a stroke_end
575 static traffic_selector_t
*build_ts(private_stroke_config_t
*this,
580 return traffic_selector_create_dynamic(end
->protocol
,
581 end
->port ? end
->port
: 0, end
->port ? end
->port
: 65535);
587 net
= host_create_from_string(end
->subnet ? end
->subnet
: end
->address
,
591 DBG1(DBG_CFG
, "invalid subnet: %s", end
->subnet
);
594 return traffic_selector_create_from_subnet(net
,
595 end
->subnet ? end
->subnet_mask
: 0, end
->protocol
, end
->port
);
600 * build a child config from the stroke message
602 static child_cfg_t
*build_child_cfg(private_stroke_config_t
*this,
605 child_cfg_t
*child_cfg
;
606 traffic_selector_t
*ts
;
608 child_cfg
= child_cfg_create(
609 msg
->add_conn
.name
, msg
->add_conn
.rekey
.ipsec_lifetime
,
610 msg
->add_conn
.rekey
.ipsec_lifetime
- msg
->add_conn
.rekey
.margin
,
611 msg
->add_conn
.rekey
.margin
* msg
->add_conn
.rekey
.fuzz
/ 100,
612 msg
->add_conn
.me
.updown
, msg
->add_conn
.me
.hostaccess
,
615 ts
= build_ts(this, &msg
->add_conn
.me
);
618 child_cfg
->destroy(child_cfg
);
621 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
623 ts
= build_ts(this, &msg
->add_conn
.other
);
626 child_cfg
->destroy(child_cfg
);
629 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
631 add_proposals(this, msg
->add_conn
.algorithms
.esp
, NULL
, child_cfg
);
637 * Implementation of stroke_config_t.add.
639 static void add(private_stroke_config_t
*this, stroke_msg_t
*msg
)
641 ike_cfg_t
*ike_cfg
, *existing_ike
;
642 peer_cfg_t
*peer_cfg
, *existing
;
643 child_cfg_t
*child_cfg
;
644 enumerator_t
*enumerator
;
645 bool use_existing
= FALSE
;
647 ike_cfg
= build_ike_cfg(this, msg
);
652 peer_cfg
= build_peer_cfg(this, msg
, ike_cfg
);
655 ike_cfg
->destroy(ike_cfg
);
659 build_auth_info(this, msg
, peer_cfg
->get_auth(peer_cfg
));
660 enumerator
= create_peer_cfg_enumerator(this, NULL
, NULL
);
661 while (enumerator
->enumerate(enumerator
, &existing
))
663 existing_ike
= existing
->get_ike_cfg(existing
);
664 if (existing
->equals(existing
, peer_cfg
) &&
665 existing_ike
->equals(existing_ike
, peer_cfg
->get_ike_cfg(peer_cfg
)))
668 peer_cfg
->destroy(peer_cfg
);
670 peer_cfg
->get_ref(peer_cfg
);
671 DBG1(DBG_CFG
, "added child to existing configuration '%s'",
672 peer_cfg
->get_name(peer_cfg
));
676 enumerator
->destroy(enumerator
);
678 child_cfg
= build_child_cfg(this, msg
);
681 peer_cfg
->destroy(peer_cfg
);
684 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
688 peer_cfg
->destroy(peer_cfg
);
692 /* add config to backend */
693 DBG1(DBG_CFG
, "added configuration '%s': %H[%D]...%H[%D]", msg
->add_conn
.name
,
694 ike_cfg
->get_my_host(ike_cfg
), peer_cfg
->get_my_id(peer_cfg
),
695 ike_cfg
->get_other_host(ike_cfg
), peer_cfg
->get_other_id(peer_cfg
));
696 this->mutex
->lock(this->mutex
);
697 this->list
->insert_last(this->list
, peer_cfg
);
698 this->mutex
->unlock(this->mutex
);
703 * Implementation of stroke_config_t.del.
705 static void del(private_stroke_config_t
*this, stroke_msg_t
*msg
)
707 enumerator_t
*enumerator
, *children
;
711 this->mutex
->lock(this->mutex
);
712 enumerator
= this->list
->create_enumerator(this->list
);
713 while (enumerator
->enumerate(enumerator
, (void**)&peer
))
715 /* remove peer config with such a name */
716 if (streq(peer
->get_name(peer
), msg
->del_conn
.name
))
718 this->list
->remove_at(this->list
, enumerator
);
722 /* remove any child with such a name */
723 children
= peer
->create_child_cfg_enumerator(peer
);
724 while (children
->enumerate(children
, &child
))
726 if (streq(child
->get_name(child
), msg
->del_conn
.name
))
728 peer
->remove_child_cfg(peer
, enumerator
);
729 child
->destroy(child
);
732 children
->destroy(children
);
734 enumerator
->destroy(enumerator
);
735 this->mutex
->unlock(this->mutex
);
737 DBG1(DBG_CFG
, "deleted connection '%s'", msg
->del_conn
.name
);
741 * Implementation of stroke_config_t.destroy
743 static void destroy(private_stroke_config_t
*this)
745 this->list
->destroy_offset(this->list
, offsetof(peer_cfg_t
, destroy
));
746 this->mutex
->destroy(this->mutex
);
753 stroke_config_t
*stroke_config_create(stroke_cred_t
*cred
)
755 private_stroke_config_t
*this = malloc_thing(private_stroke_config_t
);
757 this->public.backend
.create_peer_cfg_enumerator
= (enumerator_t
*(*)(backend_t
*, identification_t
*me
, identification_t
*other
))create_peer_cfg_enumerator
;
758 this->public.backend
.create_ike_cfg_enumerator
= (enumerator_t
*(*)(backend_t
*, host_t
*me
, host_t
*other
))create_ike_cfg_enumerator
;
759 this->public.backend
.get_peer_cfg_by_name
= (peer_cfg_t
* (*)(backend_t
*,char*))get_peer_cfg_by_name
;
760 this->public.add
= (void(*)(stroke_config_t
*, stroke_msg_t
*msg
))add
;
761 this->public.del
= (void(*)(stroke_config_t
*, stroke_msg_t
*msg
))del
;
762 this->public.destroy
= (void(*)(stroke_config_t
*))destroy
;
764 this->list
= linked_list_create();
765 this->mutex
= mutex_create(MUTEX_RECURSIVE
);
768 return &this->public;