2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
5 * Copyright (C) 2015-2019 Tobias Brunner
6 * Copyright (C) 2015-2018 Andreas Steffen
7 * HSR Hochschule fuer Technik Rapperswil
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * Copyright (C) 2014 Timo Teräs <timo.teras@iki.fi>
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 #include "vici_config.h"
45 #include "vici_builder.h"
48 #include <threading/rwlock.h>
49 #include <threading/rwlock_condvar.h>
50 #include <collections/array.h>
51 #include <collections/hashtable.h>
52 #include <collections/linked_list.h>
54 #include <pubkey_cert.h>
59 * Magic value for an undefined lifetime
61 #define LFT_UNDEFINED (~(uint64_t)0)
64 * Default IKE rekey time
66 #define LFT_DEFAULT_IKE_REKEY_TIME (4 * 60 * 60)
69 * Default CHILD rekey time
71 #define LFT_DEFAULT_CHILD_REKEY_TIME (1 * 60 * 60)
74 * Default CHILD rekey bytes
76 #define LFT_DEFAULT_CHILD_REKEY_BYTES 0
79 * Default CHILD rekey packets
81 #define LFT_DEFAULT_CHILD_REKEY_PACKETS 0
84 * Undefined replay window
86 #define REPLAY_UNDEFINED (~(uint32_t)0)
88 typedef struct private_vici_config_t private_vici_config_t
;
91 * Private data of an vici_config_t object.
93 struct private_vici_config_t
{
96 * Public vici_config_t interface.
103 vici_dispatcher_t
*dispatcher
;
106 * Hashtable of loaded connections, as peer_cfg_t
111 * Lock for conns table
116 * Condvar used to sync running actions
118 rwlock_condvar_t
*condvar
;
121 * True while we run or undo a start action
123 bool handling_actions
;
126 * Credential backend managed by VICI used for our certificates
131 * Auxiliary certification authority information
133 vici_authority_t
*authority
;
137 CALLBACK(peer_filter
, bool,
138 void *data
, enumerator_t
*orig
, va_list args
)
142 VA_ARGS_VGET(args
, out
);
144 if (orig
->enumerate(orig
, NULL
, out
))
151 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
152 private_vici_config_t
*this, identification_t
*me
, identification_t
*other
)
154 this->lock
->read_lock(this->lock
);
155 return enumerator_create_filter(this->conns
->create_enumerator(this->conns
),
156 peer_filter
, this->lock
,
157 (void*)this->lock
->unlock
);
160 CALLBACK(ike_filter
, bool,
161 void *data
, enumerator_t
*orig
, va_list args
)
166 VA_ARGS_VGET(args
, out
);
168 if (orig
->enumerate(orig
, NULL
, &cfg
))
170 *out
= cfg
->get_ike_cfg(cfg
);
176 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
177 private_vici_config_t
*this, host_t
*me
, host_t
*other
)
179 this->lock
->read_lock(this->lock
);
180 return enumerator_create_filter(this->conns
->create_enumerator(this->conns
),
181 ike_filter
, this->lock
,
182 (void*)this->lock
->unlock
);
185 METHOD(backend_t
, get_peer_cfg_by_name
, peer_cfg_t
*,
186 private_vici_config_t
*this, char *name
)
190 this->lock
->read_lock(this->lock
);
191 found
= this->conns
->get(this->conns
, name
);
194 found
->get_ref(found
);
196 this->lock
->unlock(this->lock
);
201 * Create a (error) reply message
203 static vici_message_t
* create_reply(char *fmt
, ...)
205 vici_builder_t
*builder
;
208 builder
= vici_builder_create();
209 builder
->add_kv(builder
, "success", fmt
? "no" : "yes");
213 builder
->vadd_kv(builder
, "errmsg", fmt
, args
);
216 return builder
->finalize(builder
);
220 * A rule to parse a key/value or list item
223 /** name of the key/value or list */
225 /** function to parse value */
226 bool (*parse
)(void *out
, chunk_t value
);
227 /** result, passed to parse() */
232 * Parse key/values using a rule-set
234 static bool parse_rules(parse_rule_t
*rules
, int count
, char *name
,
235 chunk_t value
, vici_message_t
**reply
)
239 for (i
= 0; i
< count
; i
++)
241 if (streq(name
, rules
[i
].name
))
243 if (rules
[i
].parse(rules
[i
].out
, value
))
247 *reply
= create_reply("invalid value for: %s, config discarded",
252 *reply
= create_reply("unknown option: %s, config discarded", name
);
257 * Parse callback data, passed to each callback
260 private_vici_config_t
*this;
261 vici_message_t
*reply
;
268 request_data_t
*request
;
276 * Clean up certificate data
278 static void free_cert_data(cert_data_t
*data
)
290 request_data_t
*request
;
296 * Clean up auth config data
298 static void free_auth_data(auth_data_t
*data
)
300 DESTROY_IF(data
->cfg
);
305 * Data associated to a peer config
308 request_data_t
*request
;
315 identification_t
*ppk_id
;
317 cert_policy_t send_cert
;
319 uint64_t dpd_timeout
;
320 fragmentation_t fragmentation
;
321 childless_t childless
;
322 unique_policy_t unique
;
323 uint32_t keyingtries
;
325 uint32_t remote_port
;
328 linked_list_t
*local
;
329 linked_list_t
*remote
;
330 linked_list_t
*proposals
;
331 linked_list_t
*children
;
334 uint64_t reauth_time
;
344 identification_t
*peer_id
;
349 * Log relevant auth config data
351 static void log_auth(auth_cfg_t
*auth
)
353 enumerator_t
*enumerator
;
357 identification_t
*id
;
362 enumerator
= auth
->create_enumerator(auth
);
363 while (enumerator
->enumerate(enumerator
, &rule
, &v
))
367 case AUTH_RULE_AUTH_CLASS
:
368 DBG2(DBG_CFG
, " class = %N", auth_class_names
, v
.u
);
370 case AUTH_RULE_EAP_TYPE
:
371 DBG2(DBG_CFG
, " eap-type = %N", eap_type_names
, v
.u
);
373 case AUTH_RULE_EAP_VENDOR
:
374 DBG2(DBG_CFG
, " eap-vendor = %u", v
.u
);
376 case AUTH_RULE_XAUTH_BACKEND
:
377 DBG2(DBG_CFG
, " xauth = %s", v
.str
);
379 case AUTH_RULE_CRL_VALIDATION
:
380 DBG2(DBG_CFG
, " revocation = %N", cert_validation_names
, v
.u
);
382 case AUTH_RULE_IDENTITY
:
383 DBG2(DBG_CFG
, " id = %Y", v
.id
);
385 case AUTH_RULE_CA_IDENTITY
:
386 DBG2(DBG_CFG
, " ca_id = %Y", v
.id
);
388 case AUTH_RULE_AAA_IDENTITY
:
389 DBG2(DBG_CFG
, " aaa_id = %Y", v
.id
);
391 case AUTH_RULE_EAP_IDENTITY
:
392 DBG2(DBG_CFG
, " eap_id = %Y", v
.id
);
394 case AUTH_RULE_XAUTH_IDENTITY
:
395 DBG2(DBG_CFG
, " xauth_id = %Y", v
.id
);
397 case AUTH_RULE_GROUP
:
398 DBG2(DBG_CFG
, " group = %Y", v
.id
);
400 case AUTH_RULE_SUBJECT_CERT
:
401 DBG2(DBG_CFG
, " cert = %Y", v
.cert
->get_subject(v
.cert
));
403 case AUTH_RULE_CA_CERT
:
404 DBG2(DBG_CFG
, " cacert = %Y", v
.cert
->get_subject(v
.cert
));
410 enumerator
->destroy(enumerator
);
414 * Log parsed peer data
416 static void log_peer_data(peer_data_t
*data
)
418 enumerator_t
*enumerator
;
422 DBG2(DBG_CFG
, " version = %u", data
->version
);
423 DBG2(DBG_CFG
, " local_addrs = %s", data
->local_addrs
);
424 DBG2(DBG_CFG
, " remote_addrs = %s", data
->remote_addrs
);
425 DBG2(DBG_CFG
, " local_port = %u", data
->local_port
);
426 DBG2(DBG_CFG
, " remote_port = %u", data
->remote_port
);
427 DBG2(DBG_CFG
, " send_certreq = %u", data
->send_certreq
);
428 DBG2(DBG_CFG
, " send_cert = %N", cert_policy_names
, data
->send_cert
);
429 DBG2(DBG_CFG
, " ppk_id = %Y", data
->ppk_id
);
430 DBG2(DBG_CFG
, " ppk_required = %u", data
->ppk_required
);
431 DBG2(DBG_CFG
, " mobike = %u", data
->mobike
);
432 DBG2(DBG_CFG
, " aggressive = %u", data
->aggressive
);
433 DBG2(DBG_CFG
, " dscp = 0x%.2x", data
->dscp
);
434 DBG2(DBG_CFG
, " encap = %u", data
->encap
);
435 DBG2(DBG_CFG
, " dpd_delay = %llu", data
->dpd_delay
);
436 DBG2(DBG_CFG
, " dpd_timeout = %llu", data
->dpd_timeout
);
437 DBG2(DBG_CFG
, " fragmentation = %u", data
->fragmentation
);
438 DBG2(DBG_CFG
, " childless = %u", data
->childless
);
439 DBG2(DBG_CFG
, " unique = %N", unique_policy_names
, data
->unique
);
440 DBG2(DBG_CFG
, " keyingtries = %u", data
->keyingtries
);
441 DBG2(DBG_CFG
, " reauth_time = %llu", data
->reauth_time
);
442 DBG2(DBG_CFG
, " rekey_time = %llu", data
->rekey_time
);
443 DBG2(DBG_CFG
, " over_time = %llu", data
->over_time
);
444 DBG2(DBG_CFG
, " rand_time = %llu", data
->rand_time
);
445 DBG2(DBG_CFG
, " proposals = %#P", data
->proposals
);
446 DBG2(DBG_CFG
, " if_id_in = %u", data
->if_id_in
);
447 DBG2(DBG_CFG
, " if_id_out = %u", data
->if_id_out
);
449 DBG2(DBG_CFG
, " mediation = %u", data
->mediation
);
450 if (data
->mediated_by
)
452 DBG2(DBG_CFG
, " mediated_by = %s", data
->mediated_by
);
453 DBG2(DBG_CFG
, " mediation_peer = %Y", data
->peer_id
);
457 if (data
->vips
->get_count(data
->vips
))
459 DBG2(DBG_CFG
, " vips:");
461 enumerator
= data
->vips
->create_enumerator(data
->vips
);
462 while (enumerator
->enumerate(enumerator
, &host
))
464 DBG2(DBG_CFG
, " %H", host
);
466 enumerator
->destroy(enumerator
);
468 enumerator
= data
->local
->create_enumerator(data
->local
);
469 while (enumerator
->enumerate(enumerator
, &auth
))
471 DBG2(DBG_CFG
, " local:");
474 enumerator
->destroy(enumerator
);
476 enumerator
= data
->remote
->create_enumerator(data
->remote
);
477 while (enumerator
->enumerate(enumerator
, &auth
))
479 DBG2(DBG_CFG
, " remote:");
482 enumerator
->destroy(enumerator
);
486 * Clean up peer config data
488 static void free_peer_data(peer_data_t
*data
)
490 data
->local
->destroy_function(data
->local
, (void*)free_auth_data
);
491 data
->remote
->destroy_function(data
->remote
, (void*)free_auth_data
);
492 data
->children
->destroy_offset(data
->children
,
493 offsetof(child_cfg_t
, destroy
));
494 data
->proposals
->destroy_offset(data
->proposals
,
495 offsetof(proposal_t
, destroy
));
496 data
->vips
->destroy_offset(data
->vips
, offsetof(host_t
, destroy
));
498 free(data
->local_addrs
);
499 free(data
->remote_addrs
);
500 DESTROY_IF(data
->ppk_id
);
502 free(data
->mediated_by
);
503 DESTROY_IF(data
->peer_id
);
511 request_data_t
*request
;
512 linked_list_t
*proposals
;
513 linked_list_t
*local_ts
;
514 linked_list_t
*remote_ts
;
515 uint32_t replay_window
;
516 child_cfg_create_t cfg
;
520 * Log parsed CHILD config data
522 static void log_child_data(child_data_t
*data
, char *name
)
524 child_cfg_create_t
*cfg
= &data
->cfg
;
526 #define has_opt(opt) ({ (cfg->options & (opt)) == (opt); })
527 DBG2(DBG_CFG
, " child %s:", name
);
528 DBG2(DBG_CFG
, " rekey_time = %llu", cfg
->lifetime
.time
.rekey
);
529 DBG2(DBG_CFG
, " life_time = %llu", cfg
->lifetime
.time
.life
);
530 DBG2(DBG_CFG
, " rand_time = %llu", cfg
->lifetime
.time
.jitter
);
531 DBG2(DBG_CFG
, " rekey_bytes = %llu", cfg
->lifetime
.bytes
.rekey
);
532 DBG2(DBG_CFG
, " life_bytes = %llu", cfg
->lifetime
.bytes
.life
);
533 DBG2(DBG_CFG
, " rand_bytes = %llu", cfg
->lifetime
.bytes
.jitter
);
534 DBG2(DBG_CFG
, " rekey_packets = %llu", cfg
->lifetime
.packets
.rekey
);
535 DBG2(DBG_CFG
, " life_packets = %llu", cfg
->lifetime
.packets
.life
);
536 DBG2(DBG_CFG
, " rand_packets = %llu", cfg
->lifetime
.packets
.jitter
);
537 DBG2(DBG_CFG
, " updown = %s", cfg
->updown
);
538 DBG2(DBG_CFG
, " hostaccess = %u", has_opt(OPT_HOSTACCESS
));
539 DBG2(DBG_CFG
, " ipcomp = %u", has_opt(OPT_IPCOMP
));
540 DBG2(DBG_CFG
, " mode = %N%s", ipsec_mode_names
, cfg
->mode
,
541 has_opt(OPT_PROXY_MODE
) ? "_PROXY" : "");
542 DBG2(DBG_CFG
, " policies = %u", !has_opt(OPT_NO_POLICIES
));
543 DBG2(DBG_CFG
, " policies_fwd_out = %u", has_opt(OPT_FWD_OUT_POLICIES
));
544 if (data
->replay_window
!= REPLAY_UNDEFINED
)
546 DBG2(DBG_CFG
, " replay_window = %u", data
->replay_window
);
548 DBG2(DBG_CFG
, " dpd_action = %N", action_names
, cfg
->dpd_action
);
549 DBG2(DBG_CFG
, " start_action = %N", action_names
, cfg
->start_action
);
550 DBG2(DBG_CFG
, " close_action = %N", action_names
, cfg
->close_action
);
551 DBG2(DBG_CFG
, " reqid = %u", cfg
->reqid
);
552 DBG2(DBG_CFG
, " tfc = %d", cfg
->tfc
);
553 DBG2(DBG_CFG
, " priority = %d", cfg
->priority
);
554 DBG2(DBG_CFG
, " interface = %s", cfg
->interface
);
555 DBG2(DBG_CFG
, " if_id_in = %u", cfg
->if_id_in
);
556 DBG2(DBG_CFG
, " if_id_out = %u", cfg
->if_id_out
);
557 DBG2(DBG_CFG
, " mark_in = %u/%u",
558 cfg
->mark_in
.value
, cfg
->mark_in
.mask
);
559 DBG2(DBG_CFG
, " mark_in_sa = %u", has_opt(OPT_MARK_IN_SA
));
560 DBG2(DBG_CFG
, " mark_out = %u/%u",
561 cfg
->mark_out
.value
, cfg
->mark_out
.mask
);
562 DBG2(DBG_CFG
, " set_mark_in = %u/%u",
563 cfg
->set_mark_in
.value
, cfg
->set_mark_in
.mask
);
564 DBG2(DBG_CFG
, " set_mark_out = %u/%u",
565 cfg
->set_mark_out
.value
, cfg
->set_mark_out
.mask
);
566 DBG2(DBG_CFG
, " inactivity = %llu", cfg
->inactivity
);
567 DBG2(DBG_CFG
, " proposals = %#P", data
->proposals
);
568 DBG2(DBG_CFG
, " local_ts = %#R", data
->local_ts
);
569 DBG2(DBG_CFG
, " remote_ts = %#R", data
->remote_ts
);
570 DBG2(DBG_CFG
, " hw_offload = %N", hw_offload_names
, cfg
->hw_offload
);
571 DBG2(DBG_CFG
, " sha256_96 = %u", has_opt(OPT_SHA256_96
));
572 DBG2(DBG_CFG
, " copy_df = %u", !has_opt(OPT_NO_COPY_DF
));
573 DBG2(DBG_CFG
, " copy_ecn = %u", !has_opt(OPT_NO_COPY_ECN
));
574 DBG2(DBG_CFG
, " copy_dscp = %N", dscp_copy_names
, cfg
->copy_dscp
);
578 * Clean up CHILD config data
580 static void free_child_data(child_data_t
*data
)
582 data
->proposals
->destroy_offset(data
->proposals
,
583 offsetof(proposal_t
, destroy
));
584 data
->local_ts
->destroy_offset(data
->local_ts
,
585 offsetof(traffic_selector_t
, destroy
));
586 data
->remote_ts
->destroy_offset(data
->remote_ts
,
587 offsetof(traffic_selector_t
, destroy
));
588 free(data
->cfg
.updown
);
589 free(data
->cfg
.interface
);
593 * Common proposal parsing
595 static bool parse_proposal(linked_list_t
*list
, protocol_id_t proto
, chunk_t v
)
598 proposal_t
*proposal
;
600 if (!vici_stringify(v
, buf
, sizeof(buf
)))
604 if (strcaseeq("default", buf
))
606 proposal
= proposal_create_default(proto
);
609 list
->insert_last(list
, proposal
);
611 proposal
= proposal_create_default_aead(proto
);
614 list
->insert_last(list
, proposal
);
618 proposal
= proposal_create_from_string(proto
, buf
);
621 list
->insert_last(list
, proposal
);
630 CALLBACK(parse_ike_proposal
, bool,
631 linked_list_t
*out
, chunk_t v
)
633 return parse_proposal(out
, PROTO_IKE
, v
);
639 CALLBACK(parse_esp_proposal
, bool,
640 linked_list_t
*out
, chunk_t v
)
642 return parse_proposal(out
, PROTO_ESP
, v
);
648 CALLBACK(parse_ah_proposal
, bool,
649 linked_list_t
*out
, chunk_t v
)
651 return parse_proposal(out
, PROTO_AH
, v
);
655 * Parse a traffic selector
657 CALLBACK(parse_ts
, bool,
658 linked_list_t
*out
, chunk_t v
)
660 char buf
[BUF_LEN
], *protoport
, *sep
, *port
= "", *end
;
661 traffic_selector_t
*ts
= NULL
;
662 struct protoent
*protoent
;
665 uint16_t from
= 0, to
= 0xffff;
668 if (!vici_stringify(v
, buf
, sizeof(buf
)))
673 protoport
= strchr(buf
, '[');
676 *(protoport
++) = '\0';
678 sep
= strrchr(protoport
, ']');
685 sep
= strchr(protoport
, '/');
687 { /* protocol/port */
692 if (streq(protoport
, "any"))
698 protoent
= getprotobyname(protoport
);
701 proto
= protoent
->p_proto
;
705 p
= strtol(protoport
, &end
, 0);
706 if ((*protoport
&& *end
) || p
< 0 || p
> 0xff)
713 if (streq(port
, "opaque"))
718 else if (*port
&& !streq(port
, "any"))
720 svc
= getservbyname(port
, NULL
);
723 from
= to
= ntohs(svc
->s_port
);
727 p
= strtol(port
, &end
, 0);
728 if (p
< 0 || p
> 0xffff)
736 p
= strtol(port
, &end
, 0);
737 if (p
< 0 || p
> 0xffff)
750 if (streq(buf
, "dynamic"))
752 ts
= traffic_selector_create_dynamic(proto
, from
, to
);
754 else if (strchr(buf
, '-'))
756 host_t
*lower
, *upper
;
759 if (host_create_from_range(buf
, &lower
, &upper
))
761 type
= (lower
->get_family(lower
) == AF_INET
) ?
762 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
763 ts
= traffic_selector_create_from_bytes(proto
, type
,
764 lower
->get_address(lower
), from
,
765 upper
->get_address(upper
), to
);
766 lower
->destroy(lower
);
767 upper
->destroy(upper
);
772 ts
= traffic_selector_create_from_cidr(buf
, proto
, from
, to
);
778 out
->insert_last(out
, ts
);
785 CALLBACK(parse_string
, bool,
786 char **out
, chunk_t v
)
788 if (!chunk_printable(v
, NULL
, ' '))
794 if (asprintf(out
, "%.*s", (int)v
.len
, v
.ptr
) == -1)
802 * Map a string to an integer
810 * Parse a string to an integer mapping
812 static bool parse_map(enum_map_t
*map
, int count
, int *out
, chunk_t v
)
817 if (!vici_stringify(v
, buf
, sizeof(buf
)))
821 for (i
= 0; i
< count
; i
++)
823 if (strcaseeq(map
[i
].str
, buf
))
835 CALLBACK(parse_bool
, bool,
836 bool *out
, chunk_t v
)
845 { "disabled", FALSE
},
850 if (parse_map(map
, countof(map
), &d
, v
))
859 * Parse a ipsec_mode_t
861 CALLBACK(parse_mode
, bool,
862 child_cfg_create_t
*cfg
, chunk_t v
)
865 { "tunnel", MODE_TUNNEL
},
866 { "transport", MODE_TRANSPORT
},
867 { "transport_proxy", MODE_TRANSPORT
},
868 { "beet", MODE_BEET
},
869 { "drop", MODE_DROP
},
870 { "pass", MODE_PASS
},
874 if (parse_map(map
, countof(map
), &d
, v
))
877 if ((d
== MODE_TRANSPORT
) && (v
.len
> 9))
879 cfg
->options
|= OPT_PROXY_MODE
;
887 * Enable a child_cfg_option_t, the flag controls whether the option is enabled
888 * if the parsed value is TRUE or FALSE.
890 static bool parse_option(child_cfg_option_t
*out
, child_cfg_option_t opt
,
891 chunk_t v
, bool add_if_true
)
895 if (parse_bool(&val
, v
))
897 if (val
== add_if_true
)
907 * Parse OPT_HOSTACCESS option
909 CALLBACK(parse_opt_haccess
, bool,
910 child_cfg_option_t
*out
, chunk_t v
)
912 return parse_option(out
, OPT_HOSTACCESS
, v
, TRUE
);
916 * Parse OPT_NO_POLICIES option
918 CALLBACK(parse_opt_policies
, bool,
919 child_cfg_option_t
*out
, chunk_t v
)
921 return parse_option(out
, OPT_NO_POLICIES
, v
, FALSE
);
925 * Parse OPT_FWD_OUT_POLICIES option
927 CALLBACK(parse_opt_fwd_out
, bool,
928 child_cfg_option_t
*out
, chunk_t v
)
930 return parse_option(out
, OPT_FWD_OUT_POLICIES
, v
, TRUE
);
934 * Parse OPT_IPCOMP option
936 CALLBACK(parse_opt_ipcomp
, bool,
937 child_cfg_option_t
*out
, chunk_t v
)
939 return parse_option(out
, OPT_IPCOMP
, v
, TRUE
);
943 * Parse OPT_SHA256_96 option
945 CALLBACK(parse_opt_sha256_96
, bool,
946 child_cfg_option_t
*out
, chunk_t v
)
948 return parse_option(out
, OPT_SHA256_96
, v
, TRUE
);
952 * Parse OPT_MARK_IN_SA option
954 CALLBACK(parse_opt_mark_in
, bool,
955 child_cfg_option_t
*out
, chunk_t v
)
957 return parse_option(out
, OPT_MARK_IN_SA
, v
, TRUE
);
961 * Parse OPT_NO_COPY_DF option
963 CALLBACK(parse_opt_copy_df
, bool,
964 child_cfg_option_t
*out
, chunk_t v
)
966 return parse_option(out
, OPT_NO_COPY_DF
, v
, FALSE
);
970 * Parse OPT_NO_COPY_ECN option
972 CALLBACK(parse_opt_copy_ecn
, bool,
973 child_cfg_option_t
*out
, chunk_t v
)
975 return parse_option(out
, OPT_NO_COPY_ECN
, v
, FALSE
);
979 * Parse a dscp_copy_t
981 CALLBACK(parse_copy_dscp
, bool,
982 dscp_copy_t
*out
, chunk_t v
)
985 { "no", DSCP_COPY_NO
},
986 { "in", DSCP_COPY_IN_ONLY
},
987 { "out", DSCP_COPY_OUT_ONLY
},
988 { "yes", DSCP_COPY_YES
},
992 if (parse_map(map
, countof(map
), &d
, v
))
1003 CALLBACK(parse_action
, bool,
1004 action_t
*out
, chunk_t v
)
1006 enum_map_t map
[] = {
1007 { "start", ACTION_RESTART
},
1008 { "restart", ACTION_RESTART
},
1009 { "route", ACTION_ROUTE
},
1010 { "trap", ACTION_ROUTE
},
1011 { "none", ACTION_NONE
},
1012 { "clear", ACTION_NONE
},
1016 if (parse_map(map
, countof(map
), &d
, v
))
1025 * Parse an hw_offload_t
1027 CALLBACK(parse_hw_offload
, bool,
1028 action_t
*out
, chunk_t v
)
1030 enum_map_t map
[] = {
1031 { "no", HW_OFFLOAD_NO
},
1032 { "yes", HW_OFFLOAD_YES
},
1033 { "auto", HW_OFFLOAD_AUTO
},
1037 if (parse_map(map
, countof(map
), &d
, v
))
1046 * Parse a uint32_t with the given base
1048 static bool parse_uint32_base(uint32_t *out
, chunk_t v
, int base
)
1053 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1057 l
= strtoul(buf
, &end
, base
);
1069 CALLBACK(parse_uint32
, bool,
1070 uint32_t *out
, chunk_t v
)
1072 return parse_uint32_base(out
, v
, 0);
1076 * Parse a uint32_t in binary encoding
1078 CALLBACK(parse_uint32_bin
, bool,
1079 uint32_t *out
, chunk_t v
)
1081 return parse_uint32_base(out
, v
, 2);
1087 CALLBACK(parse_uint64
, bool,
1088 uint64_t *out
, chunk_t v
)
1091 unsigned long long l
;
1093 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1097 l
= strtoull(buf
, &end
, 0);
1107 * Parse a relative time
1109 CALLBACK(parse_time
, bool,
1110 uint64_t *out
, chunk_t v
)
1115 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1120 l
= strtoul(buf
, &end
, 0);
1157 * Parse a relative time (32-bit)
1159 CALLBACK(parse_time32
, bool,
1160 uint32_t *out
, chunk_t v
)
1164 if (parse_time(&time
, v
))
1175 CALLBACK(parse_bytes
, bool,
1176 uint64_t *out
, chunk_t v
)
1179 unsigned long long l
;
1181 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1186 l
= strtoull(buf
, &end
, 0);
1222 CALLBACK(parse_mark
, bool,
1223 mark_t
*out
, chunk_t v
)
1227 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1231 return mark_from_string(buf
, MARK_OP_UNIQUE
, out
);
1235 * Parse a mark_t when using it as set_mark.
1237 CALLBACK(parse_set_mark
, bool,
1238 mark_t
*out
, chunk_t v
)
1242 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1246 return mark_from_string(buf
, MARK_OP_SAME
, out
);
1250 * Parse interface ID
1252 CALLBACK(parse_if_id
, bool,
1253 uint32_t *out
, chunk_t v
)
1257 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1261 return if_id_from_string(buf
, out
);
1265 * Parse TFC padding option
1267 CALLBACK(parse_tfc
, bool,
1268 uint32_t *out
, chunk_t v
)
1270 if (chunk_equals(v
, chunk_from_str("mtu")))
1275 return parse_uint32(out
, v
);
1279 * Parse 6-bit DSCP value
1281 CALLBACK(parse_dscp
, bool,
1282 uint8_t *out
, chunk_t v
)
1284 if (parse_uint32_bin(out
, v
))
1293 * Parse authentication config
1295 CALLBACK(parse_auth
, bool,
1296 auth_cfg_t
*cfg
, chunk_t v
)
1299 eap_vendor_type_t
*type
;
1301 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1305 if (strpfx(buf
, "ike:") ||
1306 strpfx(buf
, "pubkey") ||
1307 strpfx(buf
, "rsa") ||
1308 strpfx(buf
, "ecdsa") ||
1309 strpfx(buf
, "bliss"))
1311 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
1312 cfg
->add_pubkey_constraints(cfg
, buf
, TRUE
);
1315 if (strcaseeq(buf
, "psk"))
1317 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
1320 if (strcasepfx(buf
, "xauth"))
1322 pos
= strchr(buf
, '-');
1325 cfg
->add(cfg
, AUTH_RULE_XAUTH_BACKEND
, strdup(++pos
));
1327 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_XAUTH
);
1330 if (strcasepfx(buf
, "eap"))
1334 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
1336 pos
= strchr(buf
, ':');
1340 cfg
->add_pubkey_constraints(cfg
, pos
+ 1, FALSE
);
1342 type
= eap_vendor_type_from_string(buf
);
1345 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
->type
);
1348 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, type
->vendor
);
1358 * Parse identity; add as auth rule to config
1360 static bool parse_id(auth_cfg_t
*cfg
, auth_rule_t rule
, chunk_t v
)
1364 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1368 cfg
->add(cfg
, rule
, identification_create_from_string(buf
));
1373 * Parse IKE identity
1375 CALLBACK(parse_ike_id
, bool,
1376 auth_cfg_t
*cfg
, chunk_t v
)
1378 return parse_id(cfg
, AUTH_RULE_IDENTITY
, v
);
1382 * Parse CA identity constraint
1384 CALLBACK(parse_ca_id
, bool,
1385 auth_cfg_t
*cfg
, chunk_t v
)
1387 return parse_id(cfg
, AUTH_RULE_CA_IDENTITY
, v
);
1391 * Parse AAA identity
1393 CALLBACK(parse_aaa_id
, bool,
1394 auth_cfg_t
*cfg
, chunk_t v
)
1396 return parse_id(cfg
, AUTH_RULE_AAA_IDENTITY
, v
);
1400 * Parse EAP identity
1402 CALLBACK(parse_eap_id
, bool,
1403 auth_cfg_t
*cfg
, chunk_t v
)
1405 return parse_id(cfg
, AUTH_RULE_EAP_IDENTITY
, v
);
1409 * Parse XAuth identity
1411 CALLBACK(parse_xauth_id
, bool,
1412 auth_cfg_t
*cfg
, chunk_t v
)
1414 return parse_id(cfg
, AUTH_RULE_XAUTH_IDENTITY
, v
);
1418 * Parse group membership
1420 CALLBACK(parse_group
, bool,
1421 auth_cfg_t
*cfg
, chunk_t v
)
1423 return parse_id(cfg
, AUTH_RULE_GROUP
, v
);
1427 * Parse certificate policy
1429 CALLBACK(parse_cert_policy
, bool,
1430 auth_cfg_t
*cfg
, chunk_t v
)
1434 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1438 cfg
->add(cfg
, AUTH_RULE_CERT_POLICY
, strdup(buf
));
1443 * Add a certificate as auth rule to config
1445 static bool add_cert(auth_data_t
*auth
, auth_rule_t rule
, certificate_t
*cert
)
1447 vici_authority_t
*authority
;
1450 if (rule
== AUTH_RULE_CA_CERT
)
1452 authority
= auth
->request
->this->authority
;
1453 cert
= authority
->add_ca_cert(authority
, cert
);
1457 cred
= auth
->request
->this->cred
;
1458 cert
= cred
->add_cert(cred
, cert
);
1460 auth
->cfg
->add(auth
->cfg
, rule
, cert
);
1465 * Parse a certificate; add as auth rule to config
1467 static bool parse_cert(auth_data_t
*auth
, auth_rule_t rule
, chunk_t v
)
1469 certificate_t
*cert
;
1471 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
1472 BUILD_BLOB
, v
, BUILD_END
);
1475 return add_cert(auth
, rule
, cert
);
1481 * Parse subject certificates
1483 CALLBACK(parse_certs
, bool,
1484 auth_data_t
*auth
, chunk_t v
)
1486 return parse_cert(auth
, AUTH_RULE_SUBJECT_CERT
, v
);
1490 * Parse CA certificates
1492 CALLBACK(parse_cacerts
, bool,
1493 auth_data_t
*auth
, chunk_t v
)
1495 return parse_cert(auth
, AUTH_RULE_CA_CERT
, v
);
1499 * Parse raw public keys
1501 CALLBACK(parse_pubkeys
, bool,
1502 auth_data_t
*auth
, chunk_t v
)
1504 certificate_t
*cert
;
1506 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_TRUSTED_PUBKEY
,
1507 BUILD_BLOB
, v
, BUILD_END
);
1510 return add_cert(auth
, AUTH_RULE_SUBJECT_CERT
, cert
);
1516 * Parse revocation status
1518 CALLBACK(parse_revocation
, bool,
1519 auth_cfg_t
*cfg
, chunk_t v
)
1521 enum_map_t map
[] = {
1522 { "strict", VALIDATION_GOOD
},
1523 { "ifuri", VALIDATION_SKIPPED
},
1524 { "relaxed", VALIDATION_FAILED
},
1528 if (parse_map(map
, countof(map
), &d
, v
))
1530 if (d
!= VALIDATION_FAILED
)
1532 cfg
->add(cfg
, AUTH_RULE_CRL_VALIDATION
, d
);
1540 * Parse list items to comma separated strings
1542 CALLBACK(parse_stringlist
, bool,
1543 char **out
, chunk_t v
)
1547 if (!chunk_printable(v
, NULL
, ' '))
1554 if (asprintf(out
, "%s, %.*s", current
, (int)v
.len
, v
.ptr
) == -1)
1562 if (asprintf(out
, "%.*s", (int)v
.len
, v
.ptr
) == -1)
1571 * Parse an fragmentation_t
1573 CALLBACK(parse_frag
, bool,
1574 fragmentation_t
*out
, chunk_t v
)
1576 enum_map_t map
[] = {
1577 { "yes", FRAGMENTATION_YES
},
1578 { "accept", FRAGMENTATION_ACCEPT
},
1579 { "no", FRAGMENTATION_NO
},
1580 { "force", FRAGMENTATION_FORCE
},
1584 if (parse_map(map
, countof(map
), &d
, v
))
1593 * Parse a childless_t
1595 CALLBACK(parse_childless
, bool,
1596 childless_t
*out
, chunk_t v
)
1598 enum_map_t map
[] = {
1599 { "allow", CHILDLESS_ALLOW
},
1600 { "never", CHILDLESS_NEVER
},
1601 { "force", CHILDLESS_FORCE
},
1605 if (parse_map(map
, countof(map
), &d
, v
))
1614 * Parse a cert_policy_t
1616 CALLBACK(parse_send_cert
, bool,
1617 cert_policy_t
*out
, chunk_t v
)
1619 enum_map_t map
[] = {
1620 { "ifasked", CERT_SEND_IF_ASKED
},
1621 { "always", CERT_ALWAYS_SEND
},
1622 { "never", CERT_NEVER_SEND
},
1626 if (parse_map(map
, countof(map
), &d
, v
))
1635 * Parse a unique_policy_t
1637 CALLBACK(parse_unique
, bool,
1638 unique_policy_t
*out
, chunk_t v
)
1640 enum_map_t map
[] = {
1641 { "never", UNIQUE_NEVER
},
1642 { "no", UNIQUE_NO
},
1643 { "replace", UNIQUE_REPLACE
},
1644 { "keep", UNIQUE_KEEP
},
1648 if (parse_map(map
, countof(map
), &d
, v
))
1657 * Parse host_t into a list
1659 CALLBACK(parse_hosts
, bool,
1660 linked_list_t
*list
, chunk_t v
)
1665 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1669 host
= host_create_from_string(buf
, 0);
1674 list
->insert_last(list
, host
);
1681 CALLBACK(parse_peer_id
, bool,
1682 identification_t
**out
, chunk_t v
)
1686 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1690 *out
= identification_create_from_string(buf
);
1695 CALLBACK(cert_kv
, bool,
1696 cert_data_t
*cert
, vici_message_t
*message
, char *name
, chunk_t value
)
1698 parse_rule_t rules
[] = {
1699 { "handle", parse_string
, &cert
->handle
},
1700 { "slot", parse_uint32
, &cert
->slot
},
1701 { "module", parse_string
, &cert
->module
},
1702 { "file", parse_string
, &cert
->file
},
1705 return parse_rules(rules
, countof(rules
), name
, value
,
1706 &cert
->request
->reply
);
1709 CALLBACK(child_li
, bool,
1710 child_data_t
*child
, vici_message_t
*message
, char *name
, chunk_t value
)
1712 parse_rule_t rules
[] = {
1713 { "ah_proposals", parse_ah_proposal
, child
->proposals
},
1714 { "esp_proposals", parse_esp_proposal
, child
->proposals
},
1715 { "local_ts", parse_ts
, child
->local_ts
},
1716 { "remote_ts", parse_ts
, child
->remote_ts
},
1719 return parse_rules(rules
, countof(rules
), name
, value
,
1720 &child
->request
->reply
);
1723 CALLBACK(child_kv
, bool,
1724 child_data_t
*child
, vici_message_t
*message
, char *name
, chunk_t value
)
1726 parse_rule_t rules
[] = {
1727 { "updown", parse_string
, &child
->cfg
.updown
},
1728 { "hostaccess", parse_opt_haccess
, &child
->cfg
.options
},
1729 { "mode", parse_mode
, &child
->cfg
},
1730 { "policies", parse_opt_policies
, &child
->cfg
.options
},
1731 { "policies_fwd_out", parse_opt_fwd_out
, &child
->cfg
.options
},
1732 { "replay_window", parse_uint32
, &child
->replay_window
},
1733 { "rekey_time", parse_time
, &child
->cfg
.lifetime
.time
.rekey
},
1734 { "life_time", parse_time
, &child
->cfg
.lifetime
.time
.life
},
1735 { "rand_time", parse_time
, &child
->cfg
.lifetime
.time
.jitter
},
1736 { "rekey_bytes", parse_bytes
, &child
->cfg
.lifetime
.bytes
.rekey
},
1737 { "life_bytes", parse_bytes
, &child
->cfg
.lifetime
.bytes
.life
},
1738 { "rand_bytes", parse_bytes
, &child
->cfg
.lifetime
.bytes
.jitter
},
1739 { "rekey_packets", parse_uint64
, &child
->cfg
.lifetime
.packets
.rekey
},
1740 { "life_packets", parse_uint64
, &child
->cfg
.lifetime
.packets
.life
},
1741 { "rand_packets", parse_uint64
, &child
->cfg
.lifetime
.packets
.jitter
},
1742 { "dpd_action", parse_action
, &child
->cfg
.dpd_action
},
1743 { "start_action", parse_action
, &child
->cfg
.start_action
},
1744 { "close_action", parse_action
, &child
->cfg
.close_action
},
1745 { "ipcomp", parse_opt_ipcomp
, &child
->cfg
.options
},
1746 { "inactivity", parse_time32
, &child
->cfg
.inactivity
},
1747 { "reqid", parse_uint32
, &child
->cfg
.reqid
},
1748 { "mark_in", parse_mark
, &child
->cfg
.mark_in
},
1749 { "mark_in_sa", parse_opt_mark_in
, &child
->cfg
.options
},
1750 { "mark_out", parse_mark
, &child
->cfg
.mark_out
},
1751 { "set_mark_in", parse_set_mark
, &child
->cfg
.set_mark_in
},
1752 { "set_mark_out", parse_set_mark
, &child
->cfg
.set_mark_out
},
1753 { "tfc_padding", parse_tfc
, &child
->cfg
.tfc
},
1754 { "priority", parse_uint32
, &child
->cfg
.priority
},
1755 { "interface", parse_string
, &child
->cfg
.interface
},
1756 { "hw_offload", parse_hw_offload
, &child
->cfg
.hw_offload
},
1757 { "sha256_96", parse_opt_sha256_96
,&child
->cfg
.options
},
1758 { "copy_df", parse_opt_copy_df
, &child
->cfg
.options
},
1759 { "copy_ecn", parse_opt_copy_ecn
, &child
->cfg
.options
},
1760 { "copy_dscp", parse_copy_dscp
, &child
->cfg
.copy_dscp
},
1761 { "if_id_in", parse_if_id
, &child
->cfg
.if_id_in
},
1762 { "if_id_out", parse_if_id
, &child
->cfg
.if_id_out
},
1765 return parse_rules(rules
, countof(rules
), name
, value
,
1766 &child
->request
->reply
);
1769 CALLBACK(auth_li
, bool,
1770 auth_data_t
*auth
, vici_message_t
*message
, char *name
, chunk_t value
)
1772 parse_rule_t rules
[] = {
1773 { "groups", parse_group
, auth
->cfg
},
1774 { "cert_policy", parse_cert_policy
, auth
->cfg
},
1775 { "certs", parse_certs
, auth
},
1776 { "cacerts", parse_cacerts
, auth
},
1777 { "pubkeys", parse_pubkeys
, auth
},
1780 return parse_rules(rules
, countof(rules
), name
, value
,
1781 &auth
->request
->reply
);
1784 CALLBACK(auth_kv
, bool,
1785 auth_data_t
*auth
, vici_message_t
*message
, char *name
, chunk_t value
)
1787 parse_rule_t rules
[] = {
1788 { "auth", parse_auth
, auth
->cfg
},
1789 { "id", parse_ike_id
, auth
->cfg
},
1790 { "ca_id", parse_ca_id
, auth
->cfg
},
1791 { "aaa_id", parse_aaa_id
, auth
->cfg
},
1792 { "eap_id", parse_eap_id
, auth
->cfg
},
1793 { "xauth_id", parse_xauth_id
, auth
->cfg
},
1794 { "revocation", parse_revocation
, auth
->cfg
},
1795 { "round", parse_uint32
, &auth
->round
},
1798 return parse_rules(rules
, countof(rules
), name
, value
,
1799 &auth
->request
->reply
);
1802 CALLBACK(peer_li
, bool,
1803 peer_data_t
*peer
, vici_message_t
*message
, char *name
, chunk_t value
)
1805 parse_rule_t rules
[] = {
1806 { "local_addrs", parse_stringlist
, &peer
->local_addrs
},
1807 { "remote_addrs", parse_stringlist
, &peer
->remote_addrs
},
1808 { "proposals", parse_ike_proposal
, peer
->proposals
},
1809 { "vips", parse_hosts
, peer
->vips
},
1810 { "pools", parse_stringlist
, &peer
->pools
},
1813 return parse_rules(rules
, countof(rules
), name
, value
,
1814 &peer
->request
->reply
);
1817 CALLBACK(peer_kv
, bool,
1818 peer_data_t
*peer
, vici_message_t
*message
, char *name
, chunk_t value
)
1820 parse_rule_t rules
[] = {
1821 { "version", parse_uint32
, &peer
->version
},
1822 { "aggressive", parse_bool
, &peer
->aggressive
},
1823 { "pull", parse_bool
, &peer
->pull
},
1824 { "dscp", parse_dscp
, &peer
->dscp
},
1825 { "encap", parse_bool
, &peer
->encap
},
1826 { "mobike", parse_bool
, &peer
->mobike
},
1827 { "dpd_delay", parse_time
, &peer
->dpd_delay
},
1828 { "dpd_timeout", parse_time
, &peer
->dpd_timeout
},
1829 { "fragmentation", parse_frag
, &peer
->fragmentation
},
1830 { "childless", parse_childless
, &peer
->childless
},
1831 { "send_certreq", parse_bool
, &peer
->send_certreq
},
1832 { "send_cert", parse_send_cert
, &peer
->send_cert
},
1833 { "keyingtries", parse_uint32
, &peer
->keyingtries
},
1834 { "unique", parse_unique
, &peer
->unique
},
1835 { "local_port", parse_uint32
, &peer
->local_port
},
1836 { "remote_port", parse_uint32
, &peer
->remote_port
},
1837 { "reauth_time", parse_time
, &peer
->reauth_time
},
1838 { "rekey_time", parse_time
, &peer
->rekey_time
},
1839 { "over_time", parse_time
, &peer
->over_time
},
1840 { "rand_time", parse_time
, &peer
->rand_time
},
1841 { "ppk_id", parse_peer_id
, &peer
->ppk_id
},
1842 { "ppk_required", parse_bool
, &peer
->ppk_required
},
1843 { "if_id_in", parse_if_id
, &peer
->if_id_in
},
1844 { "if_id_out", parse_if_id
, &peer
->if_id_out
},
1846 { "mediation", parse_bool
, &peer
->mediation
},
1847 { "mediated_by", parse_string
, &peer
->mediated_by
},
1848 { "mediation_peer", parse_peer_id
, &peer
->peer_id
},
1852 return parse_rules(rules
, countof(rules
), name
, value
,
1853 &peer
->request
->reply
);
1856 CALLBACK(auth_sn
, bool,
1857 auth_data_t
*auth
, vici_message_t
*message
, vici_parse_context_t
*ctx
,
1860 if (strcasepfx(name
, "cert") ||
1861 strcasepfx(name
, "cacert"))
1865 certificate_t
*cert
;
1869 .request
= auth
->request
,
1873 if (!message
->parse(message
, ctx
, NULL
, cert_kv
, NULL
, data
))
1875 free_cert_data(data
);
1878 if (!data
->handle
&& !data
->file
)
1880 auth
->request
->reply
= create_reply("handle or file path missing: "
1882 free_cert_data(data
);
1885 else if (data
->handle
&& data
->file
)
1887 auth
->request
->reply
= create_reply("handle and file path given: "
1889 free_cert_data(data
);
1895 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
1896 BUILD_FROM_FILE
, data
->file
, BUILD_END
);
1900 handle
= chunk_from_hex(chunk_from_str(data
->handle
), NULL
);
1901 if (data
->slot
!= -1)
1903 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
,
1904 CERT_X509
, BUILD_PKCS11_KEYID
, handle
,
1905 BUILD_PKCS11_SLOT
, data
->slot
,
1906 data
->module
? BUILD_PKCS11_MODULE
: BUILD_END
,
1907 data
->module
, BUILD_END
);
1911 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
,
1912 CERT_X509
, BUILD_PKCS11_KEYID
, handle
,
1913 data
->module
? BUILD_PKCS11_MODULE
: BUILD_END
,
1914 data
->module
, BUILD_END
);
1916 chunk_free(&handle
);
1918 free_cert_data(data
);
1921 auth
->request
->reply
= create_reply("unable to load certificate: "
1925 rule
= strcasepfx(name
, "cert") ? AUTH_RULE_SUBJECT_CERT
1926 : AUTH_RULE_CA_CERT
;
1927 return add_cert(auth
, rule
, cert
);
1929 auth
->request
->reply
= create_reply("invalid section: %s", name
);
1934 * Check and update lifetimes
1936 static void check_lifetimes(lifetime_cfg_t
*lft
)
1938 /* if no hard lifetime specified, add one at soft lifetime + 10% */
1939 if (lft
->time
.life
== LFT_UNDEFINED
)
1941 lft
->time
.life
= lft
->time
.rekey
* 110 / 100;
1943 if (lft
->bytes
.life
== LFT_UNDEFINED
)
1945 lft
->bytes
.life
= lft
->bytes
.rekey
* 110 / 100;
1947 if (lft
->packets
.life
== LFT_UNDEFINED
)
1949 lft
->packets
.life
= lft
->packets
.rekey
* 110 / 100;
1951 /* if no rand time defined, use difference of hard and soft */
1952 if (lft
->time
.jitter
== LFT_UNDEFINED
)
1954 lft
->time
.jitter
= lft
->time
.life
-
1955 min(lft
->time
.life
, lft
->time
.rekey
);
1957 if (lft
->bytes
.jitter
== LFT_UNDEFINED
)
1959 lft
->bytes
.jitter
= lft
->bytes
.life
-
1960 min(lft
->bytes
.life
, lft
->bytes
.rekey
);
1962 if (lft
->packets
.jitter
== LFT_UNDEFINED
)
1964 lft
->packets
.jitter
= lft
->packets
.life
-
1965 min(lft
->packets
.life
, lft
->packets
.rekey
);
1969 CALLBACK(children_sn
, bool,
1970 peer_data_t
*peer
, vici_message_t
*message
, vici_parse_context_t
*ctx
,
1973 child_data_t child
= {
1974 .request
= peer
->request
,
1975 .proposals
= linked_list_create(),
1976 .local_ts
= linked_list_create(),
1977 .remote_ts
= linked_list_create(),
1978 .replay_window
= REPLAY_UNDEFINED
,
1980 .mode
= MODE_TUNNEL
,
1983 .rekey
= LFT_DEFAULT_CHILD_REKEY_TIME
,
1984 .life
= LFT_UNDEFINED
,
1985 .jitter
= LFT_UNDEFINED
,
1988 .rekey
= LFT_DEFAULT_CHILD_REKEY_BYTES
,
1989 .life
= LFT_UNDEFINED
,
1990 .jitter
= LFT_UNDEFINED
,
1993 .rekey
= LFT_DEFAULT_CHILD_REKEY_PACKETS
,
1994 .life
= LFT_UNDEFINED
,
1995 .jitter
= LFT_UNDEFINED
,
2001 proposal_t
*proposal
;
2002 traffic_selector_t
*ts
;
2004 if (!message
->parse(message
, ctx
, NULL
, child_kv
, child_li
, &child
))
2006 free_child_data(&child
);
2010 if (child
.local_ts
->get_count(child
.local_ts
) == 0)
2012 child
.local_ts
->insert_last(child
.local_ts
,
2013 traffic_selector_create_dynamic(0, 0, 65535));
2015 if (child
.remote_ts
->get_count(child
.remote_ts
) == 0)
2017 child
.remote_ts
->insert_last(child
.remote_ts
,
2018 traffic_selector_create_dynamic(0, 0, 65535));
2020 if (child
.proposals
->get_count(child
.proposals
) == 0)
2022 proposal
= proposal_create_default_aead(PROTO_ESP
);
2025 child
.proposals
->insert_last(child
.proposals
, proposal
);
2027 proposal
= proposal_create_default(PROTO_ESP
);
2030 child
.proposals
->insert_last(child
.proposals
, proposal
);
2034 check_lifetimes(&child
.cfg
.lifetime
);
2036 log_child_data(&child
, name
);
2038 cfg
= child_cfg_create(name
, &child
.cfg
);
2040 if (child
.replay_window
!= REPLAY_UNDEFINED
)
2042 cfg
->set_replay_window(cfg
, child
.replay_window
);
2044 while (child
.local_ts
->remove_first(child
.local_ts
,
2045 (void**)&ts
) == SUCCESS
)
2047 cfg
->add_traffic_selector(cfg
, TRUE
, ts
);
2049 while (child
.remote_ts
->remove_first(child
.remote_ts
,
2050 (void**)&ts
) == SUCCESS
)
2052 cfg
->add_traffic_selector(cfg
, FALSE
, ts
);
2054 while (child
.proposals
->remove_first(child
.proposals
,
2055 (void**)&proposal
) == SUCCESS
)
2057 cfg
->add_proposal(cfg
, proposal
);
2060 peer
->children
->insert_last(peer
->children
, cfg
);
2062 free_child_data(&child
);
2067 CALLBACK(peer_sn
, bool,
2068 peer_data_t
*peer
, vici_message_t
*message
, vici_parse_context_t
*ctx
,
2071 if (strcaseeq(name
, "children"))
2073 return message
->parse(message
, ctx
, children_sn
, NULL
, NULL
, peer
);
2075 if (strcasepfx(name
, "local") ||
2076 strcasepfx(name
, "remote"))
2078 enumerator_t
*enumerator
;
2079 linked_list_t
*auths
;
2080 auth_data_t
*auth
, *current
;
2082 certificate_t
*cert
;
2083 pubkey_cert_t
*pubkey_cert
;
2084 identification_t
*id
;
2085 bool default_id
= FALSE
;
2088 .request
= peer
->request
,
2089 .cfg
= auth_cfg_create(),
2092 if (!message
->parse(message
, ctx
, auth_sn
, auth_kv
, auth_li
, auth
))
2094 free_auth_data(auth
);
2097 id
= auth
->cfg
->get(auth
->cfg
, AUTH_RULE_IDENTITY
);
2099 enumerator
= auth
->cfg
->create_enumerator(auth
->cfg
);
2100 while (enumerator
->enumerate(enumerator
, &rule
, &cert
))
2102 if (rule
== AUTH_RULE_SUBJECT_CERT
&& !default_id
)
2106 id
= cert
->get_subject(cert
);
2107 DBG1(DBG_CFG
, " id not specified, defaulting to"
2108 " cert subject '%Y'", id
);
2109 auth
->cfg
->add(auth
->cfg
, AUTH_RULE_IDENTITY
, id
->clone(id
));
2112 else if (cert
->get_type(cert
) == CERT_TRUSTED_PUBKEY
&&
2113 id
->get_type
!= ID_ANY
)
2115 /* set the subject of all raw public keys to the id */
2116 pubkey_cert
= (pubkey_cert_t
*)cert
;
2117 pubkey_cert
->set_subject(pubkey_cert
, id
);
2121 enumerator
->destroy(enumerator
);
2123 auths
= strcasepfx(name
, "local") ? peer
->local
: peer
->remote
;
2124 enumerator
= auths
->create_enumerator(auths
);
2125 while (enumerator
->enumerate(enumerator
, ¤t
))
2127 if (auth
->round
< current
->round
)
2132 auths
->insert_before(auths
, enumerator
, auth
);
2133 enumerator
->destroy(enumerator
);
2136 peer
->request
->reply
= create_reply("invalid section: %s", name
);
2141 * Perform start actions associated with a child config
2143 static void run_start_action(private_vici_config_t
*this, peer_cfg_t
*peer_cfg
,
2144 child_cfg_t
*child_cfg
)
2146 switch (child_cfg
->get_start_action(child_cfg
))
2148 case ACTION_RESTART
:
2149 DBG1(DBG_CFG
, "initiating '%s'", child_cfg
->get_name(child_cfg
));
2150 charon
->controller
->initiate(charon
->controller
,
2151 peer_cfg
->get_ref(peer_cfg
), child_cfg
->get_ref(child_cfg
),
2152 NULL
, NULL
, 0, FALSE
);
2155 DBG1(DBG_CFG
, "installing '%s'", child_cfg
->get_name(child_cfg
));
2156 switch (child_cfg
->get_mode(child_cfg
))
2160 charon
->shunts
->install(charon
->shunts
,
2161 peer_cfg
->get_name(peer_cfg
), child_cfg
);
2164 charon
->traps
->install(charon
->traps
, peer_cfg
, child_cfg
);
2174 * Undo start actions associated with a child config
2176 static void clear_start_action(private_vici_config_t
*this, char *peer_name
,
2177 child_cfg_t
*child_cfg
)
2179 enumerator_t
*enumerator
, *children
;
2180 child_sa_t
*child_sa
;
2182 uint32_t id
= 0, others
;
2183 array_t
*ids
= NULL
, *ikeids
= NULL
;
2186 name
= child_cfg
->get_name(child_cfg
);
2188 switch (child_cfg
->get_start_action(child_cfg
))
2190 case ACTION_RESTART
:
2191 enumerator
= charon
->controller
->create_ike_sa_enumerator(
2192 charon
->controller
, TRUE
);
2193 while (enumerator
->enumerate(enumerator
, &ike_sa
))
2195 if (!streq(ike_sa
->get_name(ike_sa
), peer_name
))
2200 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
2201 while (children
->enumerate(children
, &child_sa
))
2203 if (child_sa
->get_state(child_sa
) != CHILD_DELETING
&&
2204 child_sa
->get_state(child_sa
) != CHILD_DELETED
)
2206 if (streq(name
, child_sa
->get_name(child_sa
)))
2208 id
= child_sa
->get_unique_id(child_sa
);
2216 children
->destroy(children
);
2218 if (!ike_sa
->get_child_count(ike_sa
) || (id
&& !others
))
2220 /* found no children or only matching, delete IKE_SA */
2221 id
= ike_sa
->get_unique_id(ike_sa
);
2222 array_insert_create_value(&ikeids
, sizeof(id
),
2227 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
2228 while (children
->enumerate(children
, &child_sa
))
2230 if (streq(name
, child_sa
->get_name(child_sa
)))
2232 id
= child_sa
->get_unique_id(child_sa
);
2233 array_insert_create_value(&ids
, sizeof(id
),
2237 children
->destroy(children
);
2240 enumerator
->destroy(enumerator
);
2242 if (array_count(ids
))
2244 while (array_remove(ids
, ARRAY_HEAD
, &id
))
2246 DBG1(DBG_CFG
, "closing '%s' #%u", name
, id
);
2247 charon
->controller
->terminate_child(charon
->controller
,
2252 if (array_count(ikeids
))
2254 while (array_remove(ikeids
, ARRAY_HEAD
, &id
))
2256 DBG1(DBG_CFG
, "closing IKE_SA #%u", id
);
2257 charon
->controller
->terminate_ike(charon
->controller
, id
,
2258 FALSE
, NULL
, NULL
, 0);
2260 array_destroy(ikeids
);
2264 DBG1(DBG_CFG
, "uninstalling '%s'", name
);
2265 switch (child_cfg
->get_mode(child_cfg
))
2269 charon
->shunts
->uninstall(charon
->shunts
, peer_name
, name
);
2272 charon
->traps
->uninstall(charon
->traps
, peer_name
, name
);
2282 * Run or undo a start actions associated with a child config
2284 static void handle_start_action(private_vici_config_t
*this,
2285 peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
2288 this->handling_actions
= TRUE
;
2289 this->lock
->unlock(this->lock
);
2293 clear_start_action(this, peer_cfg
->get_name(peer_cfg
), child_cfg
);
2297 run_start_action(this, peer_cfg
, child_cfg
);
2300 this->lock
->write_lock(this->lock
);
2301 this->handling_actions
= FALSE
;
2305 * Run or undo start actions associated with all child configs of a peer config
2307 static void handle_start_actions(private_vici_config_t
*this,
2308 peer_cfg_t
*peer_cfg
, bool undo
)
2310 enumerator_t
*enumerator
;
2311 child_cfg_t
*child_cfg
;
2313 this->handling_actions
= TRUE
;
2314 this->lock
->unlock(this->lock
);
2316 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
2317 while (enumerator
->enumerate(enumerator
, &child_cfg
))
2321 clear_start_action(this, peer_cfg
->get_name(peer_cfg
), child_cfg
);
2325 run_start_action(this, peer_cfg
, child_cfg
);
2328 enumerator
->destroy(enumerator
);
2330 this->lock
->write_lock(this->lock
);
2331 this->handling_actions
= FALSE
;
2335 * Replace children of a peer config by a new config
2337 static void replace_children(private_vici_config_t
*this,
2338 peer_cfg_t
*from
, peer_cfg_t
*to
)
2340 enumerator_t
*enumerator
;
2344 enumerator
= to
->replace_child_cfgs(to
, from
);
2345 while (enumerator
->enumerate(enumerator
, &child
, &added
))
2347 handle_start_action(this, to
, child
, !added
);
2349 enumerator
->destroy(enumerator
);
2353 * Merge/replace a peer config with existing configs
2355 static void merge_config(private_vici_config_t
*this, peer_cfg_t
*peer_cfg
)
2360 this->lock
->write_lock(this->lock
);
2361 while (this->handling_actions
)
2363 this->condvar
->wait(this->condvar
, this->lock
);
2366 found
= this->conns
->get(this->conns
, peer_cfg
->get_name(peer_cfg
));
2369 ike_cfg
= found
->get_ike_cfg(found
);
2370 if (peer_cfg
->equals(peer_cfg
, found
) &&
2371 ike_cfg
->equals(ike_cfg
, peer_cfg
->get_ike_cfg(peer_cfg
)))
2373 DBG1(DBG_CFG
, "updated vici connection: %s",
2374 peer_cfg
->get_name(peer_cfg
));
2375 replace_children(this, peer_cfg
, found
);
2376 peer_cfg
->destroy(peer_cfg
);
2380 DBG1(DBG_CFG
, "replaced vici connection: %s",
2381 peer_cfg
->get_name(peer_cfg
));
2382 this->conns
->put(this->conns
, peer_cfg
->get_name(peer_cfg
),
2384 handle_start_actions(this, found
, TRUE
);
2385 handle_start_actions(this, peer_cfg
, FALSE
);
2386 found
->destroy(found
);
2391 DBG1(DBG_CFG
, "added vici connection: %s", peer_cfg
->get_name(peer_cfg
));
2392 this->conns
->put(this->conns
, peer_cfg
->get_name(peer_cfg
), peer_cfg
);
2393 handle_start_actions(this, peer_cfg
, FALSE
);
2395 this->condvar
->signal(this->condvar
);
2396 this->lock
->unlock(this->lock
);
2399 CALLBACK(config_sn
, bool,
2400 request_data_t
*request
, vici_message_t
*message
,
2401 vici_parse_context_t
*ctx
, char *name
)
2403 peer_data_t peer
= {
2405 .local
= linked_list_create(),
2406 .remote
= linked_list_create(),
2407 .vips
= linked_list_create(),
2408 .children
= linked_list_create(),
2409 .proposals
= linked_list_create(),
2411 .send_certreq
= TRUE
,
2413 .send_cert
= CERT_SEND_IF_ASKED
,
2415 .remote_port
= IKEV2_UDP_PORT
,
2416 .fragmentation
= FRAGMENTATION_YES
,
2417 .unique
= UNIQUE_NO
,
2419 .rekey_time
= LFT_UNDEFINED
,
2420 .reauth_time
= LFT_UNDEFINED
,
2421 .over_time
= LFT_UNDEFINED
,
2422 .rand_time
= LFT_UNDEFINED
,
2424 enumerator_t
*enumerator
;
2425 peer_cfg_create_t cfg
;
2426 peer_cfg_t
*peer_cfg
;
2427 ike_cfg_create_t ike
;
2429 child_cfg_t
*child_cfg
;
2431 proposal_t
*proposal
;
2435 DBG2(DBG_CFG
, " conn %s:", name
);
2437 if (!message
->parse(message
, ctx
, peer_sn
, peer_kv
, peer_li
, &peer
))
2439 free_peer_data(&peer
);
2443 if (peer
.local
->get_count(peer
.local
) == 0)
2446 .cfg
= auth_cfg_create(),
2448 peer
.local
->insert_last(peer
.local
, auth
);
2450 if (peer
.remote
->get_count(peer
.remote
) == 0)
2453 .cfg
= auth_cfg_create(),
2455 peer
.remote
->insert_last(peer
.remote
, auth
);
2457 if (peer
.proposals
->get_count(peer
.proposals
) == 0)
2459 proposal
= proposal_create_default(PROTO_IKE
);
2462 peer
.proposals
->insert_last(peer
.proposals
, proposal
);
2464 proposal
= proposal_create_default_aead(PROTO_IKE
);
2467 peer
.proposals
->insert_last(peer
.proposals
, proposal
);
2470 if (!peer
.local_addrs
)
2472 peer
.local_addrs
= strdup("%any");
2474 if (!peer
.remote_addrs
)
2476 peer
.remote_addrs
= strdup("%any");
2478 if (!peer
.local_port
)
2480 peer
.local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
);
2483 if (peer
.rekey_time
== LFT_UNDEFINED
&& peer
.reauth_time
== LFT_UNDEFINED
)
2485 /* apply a default rekey time if no rekey/reauth time set */
2486 peer
.rekey_time
= LFT_DEFAULT_IKE_REKEY_TIME
;
2487 peer
.reauth_time
= 0;
2489 if (peer
.rekey_time
== LFT_UNDEFINED
)
2491 peer
.rekey_time
= 0;
2493 if (peer
.reauth_time
== LFT_UNDEFINED
)
2495 peer
.reauth_time
= 0;
2497 if (peer
.over_time
== LFT_UNDEFINED
)
2499 /* default over_time to 10% of rekey/reauth time if not given */
2500 peer
.over_time
= max(peer
.rekey_time
, peer
.reauth_time
) / 10;
2502 if (peer
.rand_time
== LFT_UNDEFINED
)
2504 /* default rand_time to over_time if not given, but don't make it
2505 * longer than half of rekey/rauth time */
2506 if (peer
.rekey_time
&& peer
.reauth_time
)
2508 peer
.rand_time
= min(peer
.rekey_time
, peer
.reauth_time
);
2512 peer
.rand_time
= max(peer
.rekey_time
, peer
.reauth_time
);
2514 peer
.rand_time
= min(peer
.over_time
, peer
.rand_time
/ 2);
2518 if (peer
.mediation
&& peer
.mediated_by
)
2520 DBG1(DBG_CFG
, "a mediation connection cannot be a mediated connection "
2521 "at the same time, config discarded");
2522 free_peer_data(&peer
);
2526 { /* force unique connections for mediation connections */
2527 peer
.unique
= UNIQUE_REPLACE
;
2529 else if (peer
.mediated_by
)
2530 { /* fallback to remote identity of first auth round if peer_id is not
2531 * given explicitly */
2534 if (!peer
.peer_id
&&
2535 peer
.remote
->get_first(peer
.remote
, (void**)&cfg
) == SUCCESS
)
2537 peer
.peer_id
= cfg
->get(cfg
, AUTH_RULE_IDENTITY
);
2540 peer
.peer_id
= peer
.peer_id
->clone(peer
.peer_id
);
2544 DBG1(DBG_CFG
, "mediation peer missing for mediated connection, "
2545 "config discarded");
2546 free_peer_data(&peer
);
2553 log_peer_data(&peer
);
2555 ike
= (ike_cfg_create_t
){
2556 .version
= peer
.version
,
2557 .local
= peer
.local_addrs
,
2558 .local_port
= peer
.local_port
,
2559 .remote
= peer
.remote_addrs
,
2560 .remote_port
= peer
.remote_port
,
2561 .no_certreq
= !peer
.send_certreq
,
2562 .force_encap
= peer
.encap
,
2563 .fragmentation
= peer
.fragmentation
,
2564 .childless
= peer
.childless
,
2567 ike_cfg
= ike_cfg_create(&ike
);
2569 cfg
= (peer_cfg_create_t
){
2570 .cert_policy
= peer
.send_cert
,
2571 .unique
= peer
.unique
,
2572 .keyingtries
= peer
.keyingtries
,
2573 .rekey_time
= peer
.rekey_time
,
2574 .reauth_time
= peer
.reauth_time
,
2575 .jitter_time
= peer
.rand_time
,
2576 .over_time
= peer
.over_time
,
2577 .no_mobike
= !peer
.mobike
,
2578 .aggressive
= peer
.aggressive
,
2579 .push_mode
= !peer
.pull
,
2580 .dpd
= peer
.dpd_delay
,
2581 .dpd_timeout
= peer
.dpd_timeout
,
2582 .ppk_id
= peer
.ppk_id
? peer
.ppk_id
->clone(peer
.ppk_id
) : NULL
,
2583 .ppk_required
= peer
.ppk_required
,
2584 .if_id_in
= peer
.if_id_in
,
2585 .if_id_out
= peer
.if_id_out
,
2588 cfg
.mediation
= peer
.mediation
;
2589 if (peer
.mediated_by
)
2591 cfg
.mediated_by
= peer
.mediated_by
;
2594 cfg
.peer_id
= peer
.peer_id
->clone(peer
.peer_id
);
2598 peer_cfg
= peer_cfg_create(name
, ike_cfg
, &cfg
);
2600 while (peer
.local
->remove_first(peer
.local
,
2601 (void**)&auth
) == SUCCESS
)
2603 peer_cfg
->add_auth_cfg(peer_cfg
, auth
->cfg
, TRUE
);
2605 free_auth_data(auth
);
2607 while (peer
.remote
->remove_first(peer
.remote
,
2608 (void**)&auth
) == SUCCESS
)
2610 peer_cfg
->add_auth_cfg(peer_cfg
, auth
->cfg
, FALSE
);
2612 free_auth_data(auth
);
2614 while (peer
.children
->remove_first(peer
.children
,
2615 (void**)&child_cfg
) == SUCCESS
)
2617 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
2619 while (peer
.proposals
->remove_first(peer
.proposals
,
2620 (void**)&proposal
) == SUCCESS
)
2622 ike_cfg
->add_proposal(ike_cfg
, proposal
);
2624 while (peer
.vips
->remove_first(peer
.vips
, (void**)&host
) == SUCCESS
)
2626 peer_cfg
->add_virtual_ip(peer_cfg
, host
);
2630 enumerator
= enumerator_create_token(peer
.pools
, ",", " ");
2631 while (enumerator
->enumerate(enumerator
, &str
))
2633 peer_cfg
->add_pool(peer_cfg
, str
);
2635 enumerator
->destroy(enumerator
);
2638 free_peer_data(&peer
);
2640 merge_config(request
->this, peer_cfg
);
2645 CALLBACK(load_conn
, vici_message_t
*,
2646 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
2648 request_data_t request
= {
2652 if (!message
->parse(message
, NULL
, config_sn
, NULL
, NULL
, &request
))
2656 return request
.reply
;
2658 return create_reply("parsing request failed");
2660 return create_reply(NULL
);
2663 CALLBACK(unload_conn
, vici_message_t
*,
2664 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
2669 conn_name
= message
->get_str(message
, NULL
, "name");
2672 return create_reply("unload: missing connection name");
2675 this->lock
->write_lock(this->lock
);
2676 while (this->handling_actions
)
2678 this->condvar
->wait(this->condvar
, this->lock
);
2680 cfg
= this->conns
->remove(this->conns
, conn_name
);
2683 handle_start_actions(this, cfg
, TRUE
);
2686 this->condvar
->signal(this->condvar
);
2687 this->lock
->unlock(this->lock
);
2691 return create_reply("unload: connection '%s' not found", conn_name
);
2693 return create_reply(NULL
);
2696 CALLBACK(get_conns
, vici_message_t
*,
2697 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
2699 vici_builder_t
*builder
;
2700 enumerator_t
*enumerator
;
2703 builder
= vici_builder_create();
2704 builder
->begin_list(builder
, "conns");
2706 this->lock
->read_lock(this->lock
);
2707 enumerator
= this->conns
->create_enumerator(this->conns
);
2708 while (enumerator
->enumerate(enumerator
, NULL
, &cfg
))
2710 builder
->add_li(builder
, "%s", cfg
->get_name(cfg
));
2712 enumerator
->destroy(enumerator
);
2713 this->lock
->unlock(this->lock
);
2715 builder
->end_list(builder
);
2717 return builder
->finalize(builder
);
2720 static void manage_command(private_vici_config_t
*this,
2721 char *name
, vici_command_cb_t cb
, bool reg
)
2723 this->dispatcher
->manage_command(this->dispatcher
, name
,
2724 reg
? cb
: NULL
, this);
2728 * (Un-)register dispatcher functions
2730 static void manage_commands(private_vici_config_t
*this, bool reg
)
2732 manage_command(this, "load-conn", load_conn
, reg
);
2733 manage_command(this, "unload-conn", unload_conn
, reg
);
2734 manage_command(this, "get-conns", get_conns
, reg
);
2737 CALLBACK(destroy_conn
, void,
2738 peer_cfg_t
*cfg
, const void *key
)
2743 METHOD(vici_config_t
, destroy
, void,
2744 private_vici_config_t
*this)
2746 manage_commands(this, FALSE
);
2747 this->conns
->destroy_function(this->conns
, destroy_conn
);
2748 this->condvar
->destroy(this->condvar
);
2749 this->lock
->destroy(this->lock
);
2756 vici_config_t
*vici_config_create(vici_dispatcher_t
*dispatcher
,
2757 vici_authority_t
*authority
,
2760 private_vici_config_t
*this;
2765 .create_peer_cfg_enumerator
= _create_peer_cfg_enumerator
,
2766 .create_ike_cfg_enumerator
= _create_ike_cfg_enumerator
,
2767 .get_peer_cfg_by_name
= _get_peer_cfg_by_name
,
2769 .destroy
= _destroy
,
2771 .dispatcher
= dispatcher
,
2772 .conns
= hashtable_create(hashtable_hash_str
, hashtable_equals_str
, 32),
2773 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
2774 .condvar
= rwlock_condvar_create(),
2775 .authority
= authority
,
2779 manage_commands(this, TRUE
);
2781 return &this->public;