2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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 "vici_config.h"
19 #include "vici_builder.h"
22 #include <threading/rwlock.h>
23 #include <collections/array.h>
24 #include <collections/linked_list.h>
29 * Magic value for an undefined lifetime
31 #define LFT_UNDEFINED (~(u_int64_t)0)
34 * Default IKE rekey time
36 #define LFT_DEFAULT_IKE_REKEY (4 * 60 * 60)
39 * Default CHILD rekey time
41 #define LFT_DEFAULT_CHILD_REKEY (1 * 60 * 60)
44 * Undefined replay window
46 #define REPLAY_UNDEFINED (~(u_int32_t)0)
48 typedef struct private_vici_config_t private_vici_config_t
;
51 * Private data of an vici_config_t object.
53 struct private_vici_config_t
{
56 * Public vici_config_t interface.
63 vici_dispatcher_t
*dispatcher
;
66 * List of loaded connections, as peer_cfg_t
76 METHOD(backend_t
, create_peer_cfg_enumerator
, enumerator_t
*,
77 private_vici_config_t
*this, identification_t
*me
, identification_t
*other
)
79 this->lock
->read_lock(this->lock
);
80 return enumerator_create_cleaner(this->conns
->create_enumerator(this->conns
),
81 (void*)this->lock
->unlock
, this->lock
);
85 * Enumerator filter function for ike configs
87 static bool ike_filter(void *data
, peer_cfg_t
**in
, ike_cfg_t
**out
)
89 *out
= (*in
)->get_ike_cfg(*in
);
93 METHOD(backend_t
, create_ike_cfg_enumerator
, enumerator_t
*,
94 private_vici_config_t
*this, host_t
*me
, host_t
*other
)
96 this->lock
->read_lock(this->lock
);
97 return enumerator_create_filter(this->conns
->create_enumerator(this->conns
),
98 (void*)ike_filter
, this->lock
,
99 (void*)this->lock
->unlock
);
102 METHOD(backend_t
, get_peer_cfg_by_name
, peer_cfg_t
*,
103 private_vici_config_t
*this, char *name
)
105 peer_cfg_t
*current
, *found
= NULL
;
106 enumerator_t
*enumerator
;
108 this->lock
->read_lock(this->lock
);
109 enumerator
= this->conns
->create_enumerator(this->conns
);
110 while (enumerator
->enumerate(enumerator
, ¤t
))
112 if (streq(current
->get_name(current
), name
))
115 found
->get_ref(found
);
119 enumerator
->destroy(enumerator
);
120 this->lock
->unlock(this->lock
);
126 * Create a (error) reply message
128 static vici_message_t
* create_reply(char *fmt
, ...)
130 vici_builder_t
*builder
;
133 builder
= vici_builder_create();
134 builder
->add_kv(builder
, "success", fmt ?
"no" : "yes");
138 builder
->vadd_kv(builder
, "errmsg", fmt
, args
);
141 return builder
->finalize(builder
);
145 * A rule to parse a key/value or list item
148 /** name of the key/value or list */
150 /** function to parse value */
151 bool (*parse
)(void *out
, chunk_t value
);
152 /** result, passed to parse() */
157 * Parse key/values using a rule-set
159 static bool parse_rules(parse_rule_t
*rules
, int count
, char *name
,
160 chunk_t value
, vici_message_t
**reply
)
164 for (i
= 0; i
< count
; i
++)
166 if (streq(name
, rules
[i
].name
))
168 if (rules
[i
].parse(rules
[i
].out
, value
))
172 *reply
= create_reply("invalid value for: %s, config discarded",
177 *reply
= create_reply("unknown option: %s, config discarded", name
);
182 * Parse callback data, passed to each callback
185 private_vici_config_t
*this;
186 vici_message_t
*reply
;
190 * Data associated to a peer config
193 request_data_t
*request
;
200 cert_policy_t send_cert
;
202 u_int64_t dpd_timeout
;
203 fragmentation_t fragmentation
;
204 unique_policy_t unique
;
205 u_int32_t keyingtries
;
206 u_int32_t local_port
;
207 u_int32_t remote_port
;
210 linked_list_t
*local
;
211 linked_list_t
*remote
;
212 linked_list_t
*proposals
;
213 linked_list_t
*children
;
216 u_int64_t reauth_time
;
217 u_int64_t rekey_time
;
223 * Log relevant auth config data
225 static void log_auth(auth_cfg_t
*auth
)
227 enumerator_t
*enumerator
;
231 identification_t
*id
;
235 enumerator
= auth
->create_enumerator(auth
);
236 while (enumerator
->enumerate(enumerator
, &rule
, &v
))
240 case AUTH_RULE_AUTH_CLASS
:
241 DBG2(DBG_CFG
, " class = %N", auth_class_names
, v
.u
);
243 case AUTH_RULE_EAP_TYPE
:
244 DBG2(DBG_CFG
, " eap-type = %N", eap_type_names
, v
.u
);
246 case AUTH_RULE_EAP_VENDOR
:
247 DBG2(DBG_CFG
, " eap-vendor = %u", v
.u
);
249 case AUTH_RULE_XAUTH_BACKEND
:
250 DBG2(DBG_CFG
, " xauth = %s", v
.str
);
252 case AUTH_RULE_CRL_VALIDATION
:
253 DBG2(DBG_CFG
, " revocation = %N", cert_validation_names
, v
.u
);
255 case AUTH_RULE_IDENTITY
:
256 DBG2(DBG_CFG
, " id = %Y", v
.id
);
258 case AUTH_RULE_AAA_IDENTITY
:
259 DBG2(DBG_CFG
, " aaa_id = %Y", v
.id
);
261 case AUTH_RULE_EAP_IDENTITY
:
262 DBG2(DBG_CFG
, " eap_id = %Y", v
.id
);
264 case AUTH_RULE_XAUTH_IDENTITY
:
265 DBG2(DBG_CFG
, " xauth_id = %Y", v
.id
);
267 case AUTH_RULE_GROUP
:
268 DBG2(DBG_CFG
, " group = %Y", v
.id
);
274 enumerator
->destroy(enumerator
);
278 * Log parsed peer data
280 static void log_peer_data(peer_data_t
*data
)
282 enumerator_t
*enumerator
;
286 DBG2(DBG_CFG
, " version = %u", data
->version
);
287 DBG2(DBG_CFG
, " local_addrs = %s", data
->local_addrs
);
288 DBG2(DBG_CFG
, " remote_addrs = %s", data
->remote_addrs
);
289 DBG2(DBG_CFG
, " local_port = %u", data
->local_port
);
290 DBG2(DBG_CFG
, " remote_port = %u", data
->remote_port
);
291 DBG2(DBG_CFG
, " send_certreq = %u", data
->send_certreq
);
292 DBG2(DBG_CFG
, " send_cert = %N", cert_policy_names
, data
->send_cert
);
293 DBG2(DBG_CFG
, " mobike = %u", data
->mobike
);
294 DBG2(DBG_CFG
, " aggressive = %u", data
->aggressive
);
295 DBG2(DBG_CFG
, " encap = %u", data
->encap
);
296 DBG2(DBG_CFG
, " dpd_delay = %llu", data
->dpd_delay
);
297 DBG2(DBG_CFG
, " dpd_timeout = %llu", data
->dpd_timeout
);
298 DBG2(DBG_CFG
, " fragmentation = %u", data
->fragmentation
);
299 DBG2(DBG_CFG
, " unique = %N", unique_policy_names
, data
->unique
);
300 DBG2(DBG_CFG
, " keyingtries = %u", data
->keyingtries
);
301 DBG2(DBG_CFG
, " reauth_time = %llu", data
->reauth_time
);
302 DBG2(DBG_CFG
, " rekey_time = %llu", data
->rekey_time
);
303 DBG2(DBG_CFG
, " over_time = %llu", data
->over_time
);
304 DBG2(DBG_CFG
, " rand_time = %llu", data
->rand_time
);
305 DBG2(DBG_CFG
, " proposals = %#P", data
->proposals
);
307 if (data
->vips
->get_count(data
->vips
))
309 DBG2(DBG_CFG
, " vips:");
311 enumerator
= data
->vips
->create_enumerator(data
->vips
);
312 while (enumerator
->enumerate(enumerator
, &host
))
314 DBG2(DBG_CFG
, " %H", host
);
316 enumerator
->destroy(enumerator
);
318 enumerator
= data
->local
->create_enumerator(data
->local
);
319 while (enumerator
->enumerate(enumerator
, &auth
))
321 DBG2(DBG_CFG
, " local:");
324 enumerator
->destroy(enumerator
);
326 enumerator
= data
->remote
->create_enumerator(data
->remote
);
327 while (enumerator
->enumerate(enumerator
, &auth
))
329 DBG2(DBG_CFG
, " remote:");
332 enumerator
->destroy(enumerator
);
336 * Clean up peer config data
338 static void free_peer_data(peer_data_t
*data
)
340 data
->local
->destroy_offset(data
->local
,
341 offsetof(auth_cfg_t
, destroy
));
342 data
->remote
->destroy_offset(data
->remote
,
343 offsetof(auth_cfg_t
, destroy
));
344 data
->children
->destroy_offset(data
->children
,
345 offsetof(child_cfg_t
, destroy
));
346 data
->proposals
->destroy_offset(data
->proposals
,
347 offsetof(proposal_t
, destroy
));
348 data
->vips
->destroy_offset(data
->vips
, offsetof(host_t
, destroy
));
350 free(data
->local_addrs
);
351 free(data
->remote_addrs
);
358 request_data_t
*request
;
365 u_int32_t replay_window
;
367 action_t start_action
;
368 action_t close_action
;
373 u_int64_t inactivity
;
374 linked_list_t
*proposals
;
375 linked_list_t
*local_ts
;
376 linked_list_t
*remote_ts
;
380 * Log parsed CHILD config data
382 static void log_child_data(child_data_t
*data
, char *name
)
384 DBG2(DBG_CFG
, " child %s:", name
);
385 DBG2(DBG_CFG
, " rekey_time = %llu", data
->lft
.time
.rekey
);
386 DBG2(DBG_CFG
, " life_time = %llu", data
->lft
.time
.life
);
387 DBG2(DBG_CFG
, " rand_time = %llu", data
->lft
.time
.jitter
);
388 DBG2(DBG_CFG
, " rekey_bytes = %llu", data
->lft
.bytes
.rekey
);
389 DBG2(DBG_CFG
, " life_bytes = %llu", data
->lft
.bytes
.life
);
390 DBG2(DBG_CFG
, " rand_bytes = %llu", data
->lft
.bytes
.jitter
);
391 DBG2(DBG_CFG
, " rekey_packets = %llu", data
->lft
.packets
.rekey
);
392 DBG2(DBG_CFG
, " life_packets = %llu", data
->lft
.packets
.life
);
393 DBG2(DBG_CFG
, " rand_packets = %llu", data
->lft
.packets
.jitter
);
394 DBG2(DBG_CFG
, " updown = %s", data
->updown
);
395 DBG2(DBG_CFG
, " hostaccess = %u", data
->hostaccess
);
396 DBG2(DBG_CFG
, " ipcomp = %u", data
->ipcomp
);
397 DBG2(DBG_CFG
, " mode = %N", ipsec_mode_names
, data
->mode
);
398 if (data
->replay_window
!= REPLAY_UNDEFINED
)
400 DBG2(DBG_CFG
, " replay_window = %u", data
->replay_window
);
402 DBG2(DBG_CFG
, " dpd_action = %N", action_names
, data
->dpd_action
);
403 DBG2(DBG_CFG
, " start_action = %N", action_names
, data
->start_action
);
404 DBG2(DBG_CFG
, " close_action = %N", action_names
, data
->close_action
);
405 DBG2(DBG_CFG
, " reqid = %u", data
->reqid
);
406 DBG2(DBG_CFG
, " tfc = %d", data
->tfc
);
407 DBG2(DBG_CFG
, " mark_in = %u/%u",
408 data
->mark_in
.value
, data
->mark_in
.mask
);
409 DBG2(DBG_CFG
, " mark_out = %u/%u",
410 data
->mark_out
.value
, data
->mark_out
.mask
);
411 DBG2(DBG_CFG
, " inactivity = %llu", data
->inactivity
);
412 DBG2(DBG_CFG
, " proposals = %#P", data
->proposals
);
413 DBG2(DBG_CFG
, " local_ts = %#R", data
->local_ts
);
414 DBG2(DBG_CFG
, " remote_ts = %#R", data
->remote_ts
);
418 * Clean up CHILD config data
420 static void free_child_data(child_data_t
*data
)
422 data
->proposals
->destroy_offset(data
->proposals
,
423 offsetof(proposal_t
, destroy
));
424 data
->local_ts
->destroy_offset(data
->local_ts
,
425 offsetof(traffic_selector_t
, destroy
));
426 data
->remote_ts
->destroy_offset(data
->remote_ts
,
427 offsetof(traffic_selector_t
, destroy
));
435 request_data_t
*request
;
440 * Common proposal parsing
442 static bool parse_proposal(linked_list_t
*list
, protocol_id_t proto
, chunk_t v
)
445 proposal_t
*proposal
;
447 if (!vici_stringify(v
, buf
, sizeof(buf
)))
451 if (strcaseeq("default", buf
))
453 proposal
= proposal_create_default(proto
);
456 list
->insert_last(list
, proposal
);
458 proposal
= proposal_create_default_aead(proto
);
461 list
->insert_last(list
, proposal
);
465 proposal
= proposal_create_from_string(proto
, buf
);
468 list
->insert_last(list
, proposal
);
477 CALLBACK(parse_ike_proposal
, bool,
478 linked_list_t
*out
, chunk_t v
)
480 return parse_proposal(out
, PROTO_IKE
, v
);
486 CALLBACK(parse_esp_proposal
, bool,
487 linked_list_t
*out
, chunk_t v
)
489 return parse_proposal(out
, PROTO_ESP
, v
);
495 CALLBACK(parse_ah_proposal
, bool,
496 linked_list_t
*out
, chunk_t v
)
498 return parse_proposal(out
, PROTO_AH
, v
);
502 * Parse a traffic selector
504 CALLBACK(parse_ts
, bool,
505 linked_list_t
*out
, chunk_t v
)
507 char buf
[128], *protoport
, *sep
, *port
= "", *end
;
508 traffic_selector_t
*ts
;
509 struct protoent
*protoent
;
512 u_int16_t from
= 0, to
= 0xffff;
515 if (!vici_stringify(v
, buf
, sizeof(buf
)))
520 protoport
= strchr(buf
, '[');
523 *(protoport
++) = '\0';
525 sep
= strrchr(protoport
, ']');
532 sep
= strchr(protoport
, '/');
534 { /* protocol/port */
539 if (streq(protoport
, "any"))
545 protoent
= getprotobyname(protoport
);
548 proto
= protoent
->p_proto
;
552 p
= strtol(protoport
, &end
, 0);
553 if ((*protoport
&& *end
) || p
< 0 || p
> 0xff)
560 if (streq(port
, "opaque"))
565 else if (*port
&& !streq(port
, "any"))
567 svc
= getservbyname(port
, NULL
);
570 from
= to
= ntohs(svc
->s_port
);
574 p
= strtol(port
, &end
, 0);
575 if (p
< 0 || p
> 0xffff)
583 p
= strtol(port
, &end
, 0);
584 if (p
< 0 || p
> 0xffff)
597 if (streq(buf
, "dynamic"))
599 ts
= traffic_selector_create_dynamic(proto
, from
, to
);
603 ts
= traffic_selector_create_from_cidr(buf
, proto
, from
, to
);
609 out
->insert_last(out
, ts
);
616 CALLBACK(parse_string
, bool,
617 char **out
, chunk_t v
)
619 if (!chunk_printable(v
, NULL
, ' '))
625 if (asprintf(out
, "%.*s", (int)v
.len
, v
.ptr
) == -1)
633 * Map a string to an integer
641 * Parse a string to an integer mapping
643 static bool parse_map(enum_map_t
*map
, int count
, int *out
, chunk_t v
)
648 if (!vici_stringify(v
, buf
, sizeof(buf
)))
652 for (i
= 0; i
< count
; i
++)
654 if (strcaseeq(map
[i
].str
, buf
))
666 CALLBACK(parse_bool
, bool,
667 bool *out
, chunk_t v
)
676 { "disabled", FALSE
},
681 if (parse_map(map
, countof(map
), &d
, v
))
690 * Parse a ipsec_mode_t
692 CALLBACK(parse_mode
, bool,
693 ipsec_mode_t
*out
, chunk_t v
)
696 { "tunnel", MODE_TUNNEL
},
697 { "transport", MODE_TRANSPORT
},
698 { "beet", MODE_BEET
},
699 { "drop", MODE_DROP
},
700 { "pass", MODE_PASS
},
704 if (parse_map(map
, countof(map
), &d
, v
))
715 CALLBACK(parse_action
, bool,
716 action_t
*out
, chunk_t v
)
719 { "start", ACTION_RESTART
},
720 { "restart", ACTION_RESTART
},
721 { "route", ACTION_ROUTE
},
722 { "trap", ACTION_ROUTE
},
723 { "none", ACTION_NONE
},
724 { "clear", ACTION_NONE
},
728 if (parse_map(map
, countof(map
), &d
, v
))
739 CALLBACK(parse_uint32
, bool,
740 u_int32_t
*out
, chunk_t v
)
745 if (!vici_stringify(v
, buf
, sizeof(buf
)))
749 l
= strtoul(buf
, &end
, 0);
761 CALLBACK(parse_uint64
, bool,
762 u_int64_t
*out
, chunk_t v
)
765 unsigned long long l
;
767 if (!vici_stringify(v
, buf
, sizeof(buf
)))
771 l
= strtoull(buf
, &end
, 0);
781 * Parse a relative time
783 CALLBACK(parse_time
, bool,
784 u_int64_t
*out
, chunk_t v
)
789 if (!vici_stringify(v
, buf
, sizeof(buf
)))
794 l
= strtoul(buf
, &end
, 0);
833 CALLBACK(parse_bytes
, bool,
834 u_int64_t
*out
, chunk_t v
)
837 unsigned long long l
;
839 if (!vici_stringify(v
, buf
, sizeof(buf
)))
844 l
= strtoull(buf
, &end
, 0);
880 CALLBACK(parse_mark
, bool,
881 mark_t
*out
, chunk_t v
)
885 if (!vici_stringify(v
, buf
, sizeof(buf
)))
889 return mark_from_string(buf
, out
);
893 * Parse TFC padding option
895 CALLBACK(parse_tfc
, bool,
896 u_int32_t
*out
, chunk_t v
)
898 if (chunk_equals(v
, chunk_from_str("mtu")))
903 return parse_uint32(out
, v
);
907 * Parse authentication config
909 CALLBACK(parse_auth
, bool,
910 auth_cfg_t
*cfg
, chunk_t v
)
913 eap_vendor_type_t
*type
;
915 if (!vici_stringify(v
, buf
, sizeof(buf
)))
919 if (strcaseeq(buf
, "pubkey"))
921 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PUBKEY
);
924 if (strcaseeq(buf
, "psk"))
926 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_PSK
);
929 if (strcasepfx(buf
, "xauth"))
931 pos
= strchr(buf
, '-');
934 cfg
->add(cfg
, AUTH_RULE_XAUTH_BACKEND
, strdup(++pos
));
936 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_XAUTH
);
939 if (strcasepfx(buf
, "eap"))
941 cfg
->add(cfg
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
943 type
= eap_vendor_type_from_string(buf
);
946 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
->type
);
949 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, type
->vendor
);
959 * Parse identity; add as auth rule to config
961 static bool parse_id(auth_cfg_t
*cfg
, auth_rule_t rule
, chunk_t v
)
965 if (!vici_stringify(v
, buf
, sizeof(buf
)))
969 cfg
->add(cfg
, rule
, identification_create_from_string(buf
));
976 CALLBACK(parse_ike_id
, bool,
977 auth_cfg_t
*cfg
, chunk_t v
)
979 return parse_id(cfg
, AUTH_RULE_IDENTITY
, v
);
985 CALLBACK(parse_aaa_id
, bool,
986 auth_cfg_t
*cfg
, chunk_t v
)
988 return parse_id(cfg
, AUTH_RULE_AAA_IDENTITY
, v
);
994 CALLBACK(parse_eap_id
, bool,
995 auth_cfg_t
*cfg
, chunk_t v
)
997 return parse_id(cfg
, AUTH_RULE_EAP_IDENTITY
, v
);
1001 * Parse XAuth identity
1003 CALLBACK(parse_xauth_id
, bool,
1004 auth_cfg_t
*cfg
, chunk_t v
)
1006 return parse_id(cfg
, AUTH_RULE_XAUTH_IDENTITY
, v
);
1010 * Parse group membership
1012 CALLBACK(parse_group
, bool,
1013 auth_cfg_t
*cfg
, chunk_t v
)
1015 return parse_id(cfg
, AUTH_RULE_GROUP
, v
);
1019 * Parse a certificate; add as auth rule to config
1021 static bool parse_cert(auth_cfg_t
*cfg
, auth_rule_t rule
, chunk_t v
)
1023 certificate_t
*cert
;
1025 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
1026 BUILD_BLOB_PEM
, v
, BUILD_END
);
1029 cfg
->add(cfg
, rule
, cert
);
1036 * Parse subject certificates
1038 CALLBACK(parse_certs
, bool,
1039 auth_cfg_t
*cfg
, chunk_t v
)
1041 return parse_cert(cfg
, AUTH_RULE_SUBJECT_CERT
, v
);
1045 * Parse CA certificates
1047 CALLBACK(parse_cacerts
, bool,
1048 auth_cfg_t
*cfg
, chunk_t v
)
1050 return parse_cert(cfg
, AUTH_RULE_CA_CERT
, v
);
1054 * Parse revocation status
1056 CALLBACK(parse_revocation
, bool,
1057 auth_cfg_t
*cfg
, chunk_t v
)
1059 enum_map_t map
[] = {
1060 { "strict", VALIDATION_GOOD
},
1061 { "ifuri", VALIDATION_SKIPPED
},
1062 { "relaxed", VALIDATION_FAILED
},
1066 if (parse_map(map
, countof(map
), &d
, v
))
1068 if (d
!= VALIDATION_FAILED
)
1070 cfg
->add(cfg
, AUTH_RULE_CRL_VALIDATION
, d
);
1078 * Parse list items to comma separated strings
1080 CALLBACK(parse_stringlist
, bool,
1081 char **out
, chunk_t v
)
1085 if (!chunk_printable(v
, NULL
, ' '))
1092 if (asprintf(out
, "%s, %.*s", current
, (int)v
.len
, v
.ptr
) == -1)
1100 if (asprintf(out
, "%.*s", (int)v
.len
, v
.ptr
) == -1)
1109 * Parse an fragmentation_t
1111 CALLBACK(parse_frag
, bool,
1112 fragmentation_t
*out
, chunk_t v
)
1114 enum_map_t map
[] = {
1115 { "yes", FRAGMENTATION_YES
},
1116 { "no", FRAGMENTATION_NO
},
1117 { "force", FRAGMENTATION_FORCE
},
1121 if (parse_map(map
, countof(map
), &d
, v
))
1130 * Parse a cert_policy_t
1132 CALLBACK(parse_send_cert
, bool,
1133 cert_policy_t
*out
, chunk_t v
)
1135 enum_map_t map
[] = {
1136 { "ifasked", CERT_SEND_IF_ASKED
},
1137 { "always", CERT_ALWAYS_SEND
},
1138 { "never", CERT_NEVER_SEND
},
1142 if (parse_map(map
, countof(map
), &d
, v
))
1151 * Parse a unique_policy_t
1153 CALLBACK(parse_unique
, bool,
1154 unique_policy_t
*out
, chunk_t v
)
1156 enum_map_t map
[] = {
1157 { "never", UNIQUE_NEVER
},
1158 { "no", UNIQUE_NO
},
1159 { "replace", UNIQUE_REPLACE
},
1160 { "keep", UNIQUE_KEEP
},
1164 if (parse_map(map
, countof(map
), &d
, v
))
1173 * Parse host_t into a list
1175 CALLBACK(parse_hosts
, bool,
1176 linked_list_t
*list
, chunk_t v
)
1181 if (!vici_stringify(v
, buf
, sizeof(buf
)))
1185 host
= host_create_from_string(buf
, 0);
1190 list
->insert_last(list
, host
);
1194 CALLBACK(child_li
, bool,
1195 child_data_t
*child
, vici_message_t
*message
, char *name
, chunk_t value
)
1197 parse_rule_t rules
[] = {
1198 { "ah_proposals", parse_ah_proposal
, child
->proposals
},
1199 { "esp_proposals", parse_esp_proposal
, child
->proposals
},
1200 { "local_ts", parse_ts
, child
->local_ts
},
1201 { "remote_ts", parse_ts
, child
->remote_ts
},
1204 return parse_rules(rules
, countof(rules
), name
, value
,
1205 &child
->request
->reply
);
1208 CALLBACK(child_kv
, bool,
1209 child_data_t
*child
, vici_message_t
*message
, char *name
, chunk_t value
)
1211 parse_rule_t rules
[] = {
1212 { "updown", parse_string
, &child
->updown
},
1213 { "hostaccess", parse_bool
, &child
->hostaccess
},
1214 { "mode", parse_mode
, &child
->mode
},
1215 { "replay_window", parse_uint32
, &child
->replay_window
},
1216 { "rekey_time", parse_time
, &child
->lft
.time
.rekey
},
1217 { "life_time", parse_time
, &child
->lft
.time
.life
},
1218 { "rand_time", parse_time
, &child
->lft
.time
.jitter
},
1219 { "rekey_bytes", parse_bytes
, &child
->lft
.bytes
.rekey
},
1220 { "life_bytes", parse_bytes
, &child
->lft
.bytes
.life
},
1221 { "rand_bytes", parse_bytes
, &child
->lft
.bytes
.jitter
},
1222 { "rekey_packets", parse_uint64
, &child
->lft
.packets
.rekey
},
1223 { "life_packets", parse_uint64
, &child
->lft
.packets
.life
},
1224 { "rand_packets", parse_uint64
, &child
->lft
.packets
.jitter
},
1225 { "dpd_action", parse_action
, &child
->dpd_action
},
1226 { "start_action", parse_action
, &child
->start_action
},
1227 { "close_action", parse_action
, &child
->close_action
},
1228 { "ipcomp", parse_bool
, &child
->ipcomp
},
1229 { "inactivity", parse_time
, &child
->inactivity
},
1230 { "reqid", parse_uint32
, &child
->reqid
},
1231 { "mark_in", parse_mark
, &child
->mark_in
},
1232 { "mark_out", parse_mark
, &child
->mark_out
},
1233 { "tfc_padding", parse_tfc
, &child
->tfc
},
1236 return parse_rules(rules
, countof(rules
), name
, value
,
1237 &child
->request
->reply
);
1240 CALLBACK(auth_li
, bool,
1241 auth_data_t
*auth
, vici_message_t
*message
, char *name
, chunk_t value
)
1243 parse_rule_t rules
[] = {
1244 { "groups", parse_group
, auth
->cfg
},
1245 { "certs", parse_certs
, auth
->cfg
},
1246 { "cacerts", parse_cacerts
, auth
->cfg
},
1249 return parse_rules(rules
, countof(rules
), name
, value
,
1250 &auth
->request
->reply
);
1253 CALLBACK(auth_kv
, bool,
1254 auth_data_t
*auth
, vici_message_t
*message
, char *name
, chunk_t value
)
1256 parse_rule_t rules
[] = {
1257 { "auth", parse_auth
, auth
->cfg
},
1258 { "id", parse_ike_id
, auth
->cfg
},
1259 { "aaa_id", parse_aaa_id
, auth
->cfg
},
1260 { "eap_id", parse_eap_id
, auth
->cfg
},
1261 { "xauth_id", parse_xauth_id
, auth
->cfg
},
1262 { "revocation", parse_revocation
, auth
->cfg
},
1265 return parse_rules(rules
, countof(rules
), name
, value
,
1266 &auth
->request
->reply
);
1269 CALLBACK(peer_li
, bool,
1270 peer_data_t
*peer
, vici_message_t
*message
, char *name
, chunk_t value
)
1272 parse_rule_t rules
[] = {
1273 { "local_addrs", parse_stringlist
, &peer
->local_addrs
},
1274 { "remote_addrs", parse_stringlist
, &peer
->remote_addrs
},
1275 { "proposals", parse_ike_proposal
, peer
->proposals
},
1276 { "vips", parse_hosts
, peer
->vips
},
1277 { "pools", parse_stringlist
, &peer
->pools
},
1280 return parse_rules(rules
, countof(rules
), name
, value
,
1281 &peer
->request
->reply
);
1284 CALLBACK(peer_kv
, bool,
1285 peer_data_t
*peer
, vici_message_t
*message
, char *name
, chunk_t value
)
1287 parse_rule_t rules
[] = {
1288 { "version", parse_uint32
, &peer
->version
},
1289 { "aggressive", parse_bool
, &peer
->aggressive
},
1290 { "pull", parse_bool
, &peer
->pull
},
1291 { "encap", parse_bool
, &peer
->encap
},
1292 { "mobike", parse_bool
, &peer
->mobike
},
1293 { "dpd_delay", parse_time
, &peer
->dpd_delay
},
1294 { "dpd_timeout", parse_time
, &peer
->dpd_timeout
},
1295 { "fragmentation", parse_frag
, &peer
->fragmentation
},
1296 { "send_certreq", parse_bool
, &peer
->send_certreq
},
1297 { "send_cert", parse_send_cert
, &peer
->send_cert
},
1298 { "keyingtries", parse_uint32
, &peer
->keyingtries
},
1299 { "unique", parse_unique
, &peer
->unique
},
1300 { "local_port", parse_uint32
, &peer
->local_port
},
1301 { "remote_port", parse_uint32
, &peer
->remote_port
},
1302 { "reauth_time", parse_time
, &peer
->reauth_time
},
1303 { "rekey_time", parse_time
, &peer
->rekey_time
},
1304 { "over_time", parse_time
, &peer
->over_time
},
1305 { "rand_time", parse_time
, &peer
->rand_time
},
1308 return parse_rules(rules
, countof(rules
), name
, value
,
1309 &peer
->request
->reply
);
1312 CALLBACK(children_sn
, bool,
1313 peer_data_t
*peer
, vici_message_t
*message
, vici_parse_context_t
*ctx
,
1316 child_data_t child
= {
1317 .request
= peer
->request
,
1318 .proposals
= linked_list_create(),
1319 .local_ts
= linked_list_create(),
1320 .remote_ts
= linked_list_create(),
1321 .mode
= MODE_TUNNEL
,
1322 .replay_window
= REPLAY_UNDEFINED
,
1323 .dpd_action
= ACTION_NONE
,
1324 .start_action
= ACTION_NONE
,
1325 .close_action
= ACTION_NONE
,
1328 .rekey
= LFT_DEFAULT_CHILD_REKEY
,
1329 .life
= LFT_UNDEFINED
,
1330 .jitter
= LFT_UNDEFINED
,
1333 .life
= LFT_UNDEFINED
,
1334 .jitter
= LFT_UNDEFINED
,
1337 .life
= LFT_UNDEFINED
,
1338 .jitter
= LFT_UNDEFINED
,
1343 proposal_t
*proposal
;
1344 traffic_selector_t
*ts
;
1346 if (!message
->parse(message
, ctx
, NULL
, child_kv
, child_li
, &child
))
1348 free_child_data(&child
);
1352 if (child
.local_ts
->get_count(child
.local_ts
) == 0)
1354 child
.local_ts
->insert_last(child
.local_ts
,
1355 traffic_selector_create_dynamic(0, 0, 65535));
1357 if (child
.remote_ts
->get_count(child
.remote_ts
) == 0)
1359 child
.remote_ts
->insert_last(child
.remote_ts
,
1360 traffic_selector_create_dynamic(0, 0, 65535));
1362 if (child
.proposals
->get_count(child
.proposals
) == 0)
1364 proposal
= proposal_create_default(PROTO_ESP
);
1367 child
.proposals
->insert_last(child
.proposals
, proposal
);
1369 proposal
= proposal_create_default_aead(PROTO_ESP
);
1372 child
.proposals
->insert_last(child
.proposals
, proposal
);
1376 /* if no hard lifetime specified, add one at soft lifetime + 10% */
1377 if (child
.lft
.time
.life
== LFT_UNDEFINED
)
1379 child
.lft
.time
.life
= child
.lft
.time
.rekey
* 110 / 100;
1381 if (child
.lft
.bytes
.life
== LFT_UNDEFINED
)
1383 child
.lft
.bytes
.life
= child
.lft
.bytes
.rekey
* 110 / 100;
1385 if (child
.lft
.packets
.life
== LFT_UNDEFINED
)
1387 child
.lft
.packets
.life
= child
.lft
.packets
.rekey
* 110 / 100;
1389 /* if no rand time defined, use difference of hard and soft */
1390 if (child
.lft
.time
.jitter
== LFT_UNDEFINED
)
1392 child
.lft
.time
.jitter
= child
.lft
.time
.life
-
1393 min(child
.lft
.time
.life
, child
.lft
.time
.rekey
);
1395 if (child
.lft
.bytes
.jitter
== LFT_UNDEFINED
)
1397 child
.lft
.bytes
.jitter
= child
.lft
.bytes
.life
-
1398 min(child
.lft
.bytes
.life
, child
.lft
.bytes
.rekey
);
1400 if (child
.lft
.packets
.jitter
== LFT_UNDEFINED
)
1402 child
.lft
.packets
.jitter
= child
.lft
.packets
.life
-
1403 min(child
.lft
.packets
.life
, child
.lft
.packets
.rekey
);
1406 log_child_data(&child
, name
);
1408 cfg
= child_cfg_create(name
, &child
.lft
, child
.updown
,
1409 child
.hostaccess
, child
.mode
, child
.start_action
,
1410 child
.dpd_action
, child
.close_action
, child
.ipcomp
,
1411 child
.inactivity
, child
.reqid
, &child
.mark_in
,
1412 &child
.mark_out
, child
.tfc
);
1414 if (child
.replay_window
!= REPLAY_UNDEFINED
)
1416 cfg
->set_replay_window(cfg
, child
.replay_window
);
1418 while (child
.local_ts
->remove_first(child
.local_ts
,
1419 (void**)&ts
) == SUCCESS
)
1421 cfg
->add_traffic_selector(cfg
, TRUE
, ts
);
1423 while (child
.remote_ts
->remove_first(child
.remote_ts
,
1424 (void**)&ts
) == SUCCESS
)
1426 cfg
->add_traffic_selector(cfg
, FALSE
, ts
);
1428 while (child
.proposals
->remove_first(child
.proposals
,
1429 (void**)&proposal
) == SUCCESS
)
1431 cfg
->add_proposal(cfg
, proposal
);
1434 peer
->children
->insert_last(peer
->children
, cfg
);
1436 free_child_data(&child
);
1441 CALLBACK(peer_sn
, bool,
1442 peer_data_t
*peer
, vici_message_t
*message
, vici_parse_context_t
*ctx
,
1445 if (strcaseeq(name
, "children"))
1447 return message
->parse(message
, ctx
, children_sn
, NULL
, NULL
, peer
);
1449 if (strcasepfx(name
, "local") ||
1450 strcasepfx(name
, "remote"))
1452 auth_data_t auth
= {
1453 .request
= peer
->request
,
1454 .cfg
= auth_cfg_create(),
1457 if (!message
->parse(message
, ctx
, NULL
, auth_kv
, auth_li
, &auth
))
1459 auth
.cfg
->destroy(auth
.cfg
);
1463 if (strcasepfx(name
, "local"))
1465 peer
->local
->insert_last(peer
->local
, auth
.cfg
);
1469 peer
->remote
->insert_last(peer
->remote
, auth
.cfg
);
1473 peer
->request
->reply
= create_reply("invalid section: %s", name
);
1478 * Find reqid of an existing CHILD_SA
1480 static u_int32_t
find_reqid(child_cfg_t
*cfg
)
1482 enumerator_t
*enumerator
, *children
;
1483 child_sa_t
*child_sa
;
1487 reqid
= charon
->traps
->find_reqid(charon
->traps
, cfg
);
1489 { /* already trapped */
1493 enumerator
= charon
->controller
->create_ike_sa_enumerator(
1494 charon
->controller
, TRUE
);
1495 while (!reqid
&& enumerator
->enumerate(enumerator
, &ike_sa
))
1497 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
1498 while (children
->enumerate(children
, &child_sa
))
1500 if (streq(cfg
->get_name(cfg
), child_sa
->get_name(child_sa
)))
1502 reqid
= child_sa
->get_reqid(child_sa
);
1506 children
->destroy(children
);
1508 enumerator
->destroy(enumerator
);
1513 * Perform start actions associated to a child config
1515 static void run_start_action(private_vici_config_t
*this, peer_cfg_t
*peer_cfg
,
1516 child_cfg_t
*child_cfg
)
1518 switch (child_cfg
->get_start_action(child_cfg
))
1520 case ACTION_RESTART
:
1521 DBG1(DBG_CFG
, "initiating '%s'", child_cfg
->get_name(child_cfg
));
1522 charon
->controller
->initiate(charon
->controller
,
1523 peer_cfg
->get_ref(peer_cfg
), child_cfg
->get_ref(child_cfg
),
1527 DBG1(DBG_CFG
, "installing '%s'", child_cfg
->get_name(child_cfg
));
1528 switch (child_cfg
->get_mode(child_cfg
))
1532 charon
->shunts
->install(charon
->shunts
, child_cfg
);
1535 charon
->traps
->install(charon
->traps
, peer_cfg
, child_cfg
,
1536 find_reqid(child_cfg
));
1546 * Undo start actions associated to a child config
1548 static void clear_start_action(private_vici_config_t
*this,
1549 child_cfg_t
*child_cfg
)
1551 enumerator_t
*enumerator
, *children
;
1552 child_sa_t
*child_sa
;
1554 u_int32_t id
= 0, *del
;
1555 array_t
*ids
= NULL
;
1558 name
= child_cfg
->get_name(child_cfg
);
1559 switch (child_cfg
->get_start_action(child_cfg
))
1561 case ACTION_RESTART
:
1562 enumerator
= charon
->controller
->create_ike_sa_enumerator(
1563 charon
->controller
, TRUE
);
1564 while (enumerator
->enumerate(enumerator
, &ike_sa
))
1566 children
= ike_sa
->create_child_sa_enumerator(ike_sa
);
1567 while (children
->enumerate(children
, &child_sa
))
1569 if (streq(name
, child_sa
->get_name(child_sa
)))
1571 id
= child_sa
->get_unique_id(child_sa
);
1572 array_insert_create(&ids
, ARRAY_TAIL
, &id
);
1575 children
->destroy(children
);
1577 enumerator
->destroy(enumerator
);
1579 if (array_count(ids
))
1581 while (array_remove(ids
, ARRAY_HEAD
, &del
))
1583 DBG1(DBG_CFG
, "closing '%s' #%u", name
, *del
);
1584 charon
->controller
->terminate_child(charon
->controller
,
1585 *del
, NULL
, NULL
, 0);
1591 DBG1(DBG_CFG
, "uninstalling '%s'", name
);
1592 switch (child_cfg
->get_mode(child_cfg
))
1596 charon
->shunts
->uninstall(charon
->shunts
, name
);
1599 enumerator
= charon
->traps
->create_enumerator(charon
->traps
);
1600 while (enumerator
->enumerate(enumerator
, NULL
, &child_sa
))
1602 if (streq(name
, child_sa
->get_name(child_sa
)))
1604 id
= child_sa
->get_reqid(child_sa
);
1608 enumerator
->destroy(enumerator
);
1611 charon
->traps
->uninstall(charon
->traps
, id
);
1622 * Run start actions associated to all child configs of a peer config
1624 static void run_start_actions(private_vici_config_t
*this, peer_cfg_t
*peer_cfg
)
1626 enumerator_t
*enumerator
;
1627 child_cfg_t
*child_cfg
;
1629 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
1630 while (enumerator
->enumerate(enumerator
, &child_cfg
))
1632 run_start_action(this, peer_cfg
, child_cfg
);
1634 enumerator
->destroy(enumerator
);
1638 * Undo start actions associated to all child configs of a peer config
1640 static void clear_start_actions(private_vici_config_t
*this,
1641 peer_cfg_t
*peer_cfg
)
1643 enumerator_t
*enumerator
;
1644 child_cfg_t
*child_cfg
;
1646 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
1647 while (enumerator
->enumerate(enumerator
, &child_cfg
))
1649 clear_start_action(this, child_cfg
);
1651 enumerator
->destroy(enumerator
);
1655 * Replace children of a peer config by a new config
1657 static void replace_children(private_vici_config_t
*this,
1658 peer_cfg_t
*from
, peer_cfg_t
*to
)
1660 enumerator_t
*enumerator
;
1663 enumerator
= to
->create_child_cfg_enumerator(to
);
1664 while (enumerator
->enumerate(enumerator
, &child
))
1666 to
->remove_child_cfg(to
, enumerator
);
1667 clear_start_action(this, child
);
1668 child
->destroy(child
);
1670 enumerator
->destroy(enumerator
);
1672 enumerator
= from
->create_child_cfg_enumerator(from
);
1673 while (enumerator
->enumerate(enumerator
, &child
))
1675 from
->remove_child_cfg(from
, enumerator
);
1676 to
->add_child_cfg(to
, child
);
1677 run_start_action(this, to
, child
);
1679 enumerator
->destroy(enumerator
);
1683 * Merge/replace a peer config with existing configs
1685 static void merge_config(private_vici_config_t
*this, peer_cfg_t
*peer_cfg
)
1687 enumerator_t
*enumerator
;
1688 peer_cfg_t
*current
;
1690 bool merged
= FALSE
;
1692 this->lock
->write_lock(this->lock
);
1694 enumerator
= this->conns
->create_enumerator(this->conns
);
1695 while (enumerator
->enumerate(enumerator
, ¤t
))
1697 if (streq(peer_cfg
->get_name(peer_cfg
), current
->get_name(current
)))
1699 ike_cfg
= current
->get_ike_cfg(current
);
1700 if (peer_cfg
->equals(peer_cfg
, current
) &&
1701 ike_cfg
->equals(ike_cfg
, peer_cfg
->get_ike_cfg(peer_cfg
)))
1703 DBG1(DBG_CFG
, "updated vici connection: %s",
1704 peer_cfg
->get_name(peer_cfg
));
1705 replace_children(this, peer_cfg
, current
);
1706 peer_cfg
->destroy(peer_cfg
);
1710 DBG1(DBG_CFG
, "replaced vici connection: %s",
1711 peer_cfg
->get_name(peer_cfg
));
1712 this->conns
->remove_at(this->conns
, enumerator
);
1713 clear_start_actions(this, current
);
1714 current
->destroy(current
);
1715 this->conns
->insert_last(this->conns
, peer_cfg
);
1716 run_start_actions(this, peer_cfg
);
1722 enumerator
->destroy(enumerator
);
1726 DBG1(DBG_CFG
, "added vici connection: %s", peer_cfg
->get_name(peer_cfg
));
1727 this->conns
->insert_last(this->conns
, peer_cfg
);
1728 run_start_actions(this, peer_cfg
);
1731 this->lock
->unlock(this->lock
);
1734 CALLBACK(config_sn
, bool,
1735 request_data_t
*request
, vici_message_t
*message
,
1736 vici_parse_context_t
*ctx
, char *name
)
1738 peer_data_t peer
= {
1740 .local
= linked_list_create(),
1741 .remote
= linked_list_create(),
1742 .vips
= linked_list_create(),
1743 .children
= linked_list_create(),
1744 .proposals
= linked_list_create(),
1746 .send_certreq
= TRUE
,
1748 .send_cert
= CERT_SEND_IF_ASKED
,
1750 .remote_port
= IKEV2_UDP_PORT
,
1751 .fragmentation
= FRAGMENTATION_NO
,
1752 .unique
= UNIQUE_NO
,
1754 .rekey_time
= LFT_UNDEFINED
,
1755 .reauth_time
= LFT_UNDEFINED
,
1756 .over_time
= LFT_UNDEFINED
,
1757 .rand_time
= LFT_UNDEFINED
,
1759 enumerator_t
*enumerator
;
1760 peer_cfg_t
*peer_cfg
;
1762 child_cfg_t
*child_cfg
;
1763 auth_cfg_t
*auth_cfg
;
1764 proposal_t
*proposal
;
1768 DBG2(DBG_CFG
, " conn %s:", name
);
1770 if (!message
->parse(message
, ctx
, peer_sn
, peer_kv
, peer_li
, &peer
))
1772 free_peer_data(&peer
);
1776 if (peer
.local
->get_count(peer
.local
) == 0)
1778 free_peer_data(&peer
);
1779 peer
.request
->reply
= create_reply("missing local auth config");
1782 if (peer
.remote
->get_count(peer
.remote
) == 0)
1784 auth_cfg
= auth_cfg_create();
1785 peer
.remote
->insert_last(peer
.remote
, auth_cfg
);
1787 if (peer
.proposals
->get_count(peer
.proposals
) == 0)
1789 proposal
= proposal_create_default(PROTO_IKE
);
1792 peer
.proposals
->insert_last(peer
.proposals
, proposal
);
1794 proposal
= proposal_create_default_aead(PROTO_IKE
);
1797 peer
.proposals
->insert_last(peer
.proposals
, proposal
);
1800 if (!peer
.local_addrs
)
1802 peer
.local_addrs
= strdup("%any");
1804 if (!peer
.remote_addrs
)
1806 peer
.remote_addrs
= strdup("%any");
1808 if (!peer
.local_port
)
1810 peer
.local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
);
1813 if (peer
.rekey_time
== LFT_UNDEFINED
&& peer
.reauth_time
== LFT_UNDEFINED
)
1815 /* apply a default rekey time if no rekey/reauth time set */
1816 peer
.rekey_time
= LFT_DEFAULT_IKE_REKEY
;
1817 peer
.reauth_time
= 0;
1819 if (peer
.rekey_time
== LFT_UNDEFINED
)
1821 peer
.rekey_time
= 0;
1823 if (peer
.reauth_time
== LFT_UNDEFINED
)
1825 peer
.reauth_time
= 0;
1827 if (peer
.over_time
== LFT_UNDEFINED
)
1829 /* default over_time to 10% of rekey/reauth time if not given */
1830 peer
.over_time
= max(peer
.rekey_time
, peer
.reauth_time
) / 10;
1832 if (peer
.rand_time
== LFT_UNDEFINED
)
1834 /* default rand_time to over_time if not given, but don't make it
1835 * longer than half of rekey/rauth time */
1836 if (peer
.rekey_time
&& peer
.reauth_time
)
1838 peer
.rand_time
= min(peer
.rekey_time
, peer
.reauth_time
);
1842 peer
.rand_time
= max(peer
.rekey_time
, peer
.reauth_time
);
1844 peer
.rand_time
= min(peer
.over_time
, peer
.rand_time
/ 2);
1847 log_peer_data(&peer
);
1849 ike_cfg
= ike_cfg_create(peer
.version
, peer
.send_certreq
, peer
.encap
,
1850 peer
.local_addrs
, peer
.local_port
,
1851 peer
.remote_addrs
, peer
.remote_port
,
1852 peer
.fragmentation
, 0);
1853 peer_cfg
= peer_cfg_create(name
, ike_cfg
, peer
.send_cert
, peer
.unique
,
1854 peer
.keyingtries
, peer
.rekey_time
, peer
.reauth_time
,
1855 peer
.rand_time
, peer
.over_time
, peer
.mobike
,
1856 peer
.aggressive
, peer
.pull
,
1857 peer
.dpd_delay
, peer
.dpd_timeout
,
1860 while (peer
.local
->remove_first(peer
.local
,
1861 (void**)&auth_cfg
) == SUCCESS
)
1863 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, TRUE
);
1865 while (peer
.remote
->remove_first(peer
.remote
,
1866 (void**)&auth_cfg
) == SUCCESS
)
1868 peer_cfg
->add_auth_cfg(peer_cfg
, auth_cfg
, FALSE
);
1870 while (peer
.children
->remove_first(peer
.children
,
1871 (void**)&child_cfg
) == SUCCESS
)
1873 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
);
1875 while (peer
.proposals
->remove_first(peer
.proposals
,
1876 (void**)&proposal
) == SUCCESS
)
1878 ike_cfg
->add_proposal(ike_cfg
, proposal
);
1880 while (peer
.vips
->remove_first(peer
.vips
, (void**)&host
) == SUCCESS
)
1882 peer_cfg
->add_virtual_ip(peer_cfg
, host
);
1886 enumerator
= enumerator_create_token(peer
.pools
, ",", " ");
1887 while (enumerator
->enumerate(enumerator
, &str
))
1889 peer_cfg
->add_pool(peer_cfg
, str
);
1891 enumerator
->destroy(enumerator
);
1894 free_peer_data(&peer
);
1896 merge_config(request
->this, peer_cfg
);
1901 CALLBACK(load_conn
, vici_message_t
*,
1902 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
1904 request_data_t request
= {
1908 if (!message
->parse(message
, NULL
, config_sn
, NULL
, NULL
, &request
))
1912 return request
.reply
;
1914 return create_reply("parsing request failed");
1916 return create_reply(NULL
);
1919 CALLBACK(unload_conn
, vici_message_t
*,
1920 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
1922 enumerator_t
*enumerator
;
1927 conn
= message
->get_str(message
, NULL
, "name");
1930 return create_reply("missing connection name to unload");
1933 this->lock
->write_lock(this->lock
);
1934 enumerator
= this->conns
->create_enumerator(this->conns
);
1935 while (enumerator
->enumerate(enumerator
, &cfg
))
1937 if (streq(cfg
->get_name(cfg
), conn
))
1939 this->conns
->remove_at(this->conns
, enumerator
);
1945 enumerator
->destroy(enumerator
);
1946 this->lock
->unlock(this->lock
);
1950 return create_reply("connection '%s' not found for unloading", conn
);
1952 return create_reply(NULL
);
1955 CALLBACK(get_conns
, vici_message_t
*,
1956 private_vici_config_t
*this, char *name
, u_int id
, vici_message_t
*message
)
1958 vici_builder_t
*builder
;
1959 enumerator_t
*enumerator
;
1962 builder
= vici_builder_create();
1963 builder
->begin_list(builder
, "conns");
1965 this->lock
->read_lock(this->lock
);
1966 enumerator
= this->conns
->create_enumerator(this->conns
);
1967 while (enumerator
->enumerate(enumerator
, &cfg
))
1969 builder
->add_li(builder
, "%s", cfg
->get_name(cfg
));
1971 enumerator
->destroy(enumerator
);
1972 this->lock
->unlock(this->lock
);
1974 builder
->end_list(builder
);
1976 return builder
->finalize(builder
);
1979 static void manage_command(private_vici_config_t
*this,
1980 char *name
, vici_command_cb_t cb
, bool reg
)
1982 this->dispatcher
->manage_command(this->dispatcher
, name
,
1983 reg ? cb
: NULL
, this);
1987 * (Un-)register dispatcher functions
1989 static void manage_commands(private_vici_config_t
*this, bool reg
)
1991 manage_command(this, "load-conn", load_conn
, reg
);
1992 manage_command(this, "unload-conn", unload_conn
, reg
);
1993 manage_command(this, "get-conns", get_conns
, reg
);
1996 METHOD(vici_config_t
, destroy
, void,
1997 private_vici_config_t
*this)
1999 manage_commands(this, FALSE
);
2000 this->conns
->destroy_offset(this->conns
, offsetof(peer_cfg_t
, destroy
));
2001 this->lock
->destroy(this->lock
);
2008 vici_config_t
*vici_config_create(vici_dispatcher_t
*dispatcher
)
2010 private_vici_config_t
*this;
2015 .create_peer_cfg_enumerator
= _create_peer_cfg_enumerator
,
2016 .create_ike_cfg_enumerator
= _create_ike_cfg_enumerator
,
2017 .get_peer_cfg_by_name
= _get_peer_cfg_by_name
,
2019 .destroy
= _destroy
,
2021 .dispatcher
= dispatcher
,
2022 .conns
= linked_list_create(),
2023 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
2026 manage_commands(this, TRUE
);
2028 return &this->public;