child-delete: Reply as usual when concurrently rekeying the IKE_SA
[strongswan.git] / src / conftest / config.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "config.h"
17
18 #include <daemon.h>
19 #include <conftest.h>
20
21 typedef struct private_config_t private_config_t;
22
23 /**
24 * Private data of an config_t object.
25 */
26 struct private_config_t {
27
28 /**
29 * Public config_t interface.
30 */
31 config_t public;
32
33 /**
34 * List of loaded peer configs
35 */
36 linked_list_t *configs;
37 };
38
39 /**
40 * filter function for ike configs
41 */
42 static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out)
43 {
44 *out = (*in)->get_ike_cfg(*in);
45 return TRUE;
46 }
47
48 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
49 private_config_t *this, host_t *me, host_t *other)
50 {
51
52 return enumerator_create_filter(
53 this->configs->create_enumerator(this->configs),
54 (void*)ike_filter, NULL, NULL);
55 }
56
57 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
58 private_config_t *this, identification_t *me, identification_t *other)
59 {
60 return this->configs->create_enumerator(this->configs);
61 }
62
63 METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
64 private_config_t *this, char *name)
65 {
66 enumerator_t *e1, *e2;
67 peer_cfg_t *current, *found = NULL;
68 child_cfg_t *child;
69
70 e1 = this->configs->create_enumerator(this->configs);
71 while (e1->enumerate(e1, &current))
72 {
73 e2 = current->create_child_cfg_enumerator(current);
74 while (e2->enumerate(e2, &child))
75 {
76 if (streq(child->get_name(child), name))
77 {
78 found = current;
79 found->get_ref(found);
80 break;
81 }
82 }
83 e2->destroy(e2);
84 if (found)
85 {
86 break;
87 }
88 }
89 e1->destroy(e1);
90 return found;
91 }
92
93 /**
94 * Load IKE config for a given section name
95 */
96 static ike_cfg_t *load_ike_config(private_config_t *this,
97 settings_t *settings, char *config)
98 {
99 enumerator_t *enumerator;
100 ike_cfg_t *ike_cfg;
101 proposal_t *proposal;
102 char *token;
103
104 ike_cfg = ike_cfg_create(IKEV2, TRUE,
105 settings->get_bool(settings, "configs.%s.fake_nat", FALSE, config),
106 settings->get_str(settings, "configs.%s.lhost", "%any", config),
107 settings->get_int(settings, "configs.%s.lport", 500, config),
108 settings->get_str(settings, "configs.%s.rhost", "%any", config),
109 settings->get_int(settings, "configs.%s.rport", 500, config),
110 FRAGMENTATION_NO, 0);
111 token = settings->get_str(settings, "configs.%s.proposal", NULL, config);
112 if (token)
113 {
114 enumerator = enumerator_create_token(token, ",", " ");
115 while (enumerator->enumerate(enumerator, &token))
116 {
117 proposal = proposal_create_from_string(PROTO_IKE, token);
118 if (proposal)
119 {
120 ike_cfg->add_proposal(ike_cfg, proposal);
121 }
122 else
123 {
124 DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token);
125 }
126 }
127 enumerator->destroy(enumerator);
128 }
129 else
130 {
131 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
132 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
133 }
134 return ike_cfg;
135 }
136 /**
137 * Load CHILD config for given section names
138 */
139 static child_cfg_t *load_child_config(private_config_t *this,
140 settings_t *settings, char *config, char *child)
141 {
142 child_cfg_create_t data = {
143 .mode = MODE_TUNNEL,
144 };
145 child_cfg_t *child_cfg;
146 enumerator_t *enumerator;
147 proposal_t *proposal;
148 traffic_selector_t *ts;
149 char *token;
150
151 if (settings->get_bool(settings, "configs.%s.%s.transport",
152 FALSE, config, child))
153 {
154 data.mode = MODE_TRANSPORT;
155 }
156 data.tfc = settings->get_int(settings, "configs.%s.%s.tfc_padding",
157 0, config, child);
158 child_cfg = child_cfg_create(child, &data);
159
160 token = settings->get_str(settings, "configs.%s.%s.proposal",
161 NULL, config, child);
162 if (token)
163 {
164 enumerator = enumerator_create_token(token, ",", " ");
165 while (enumerator->enumerate(enumerator, &token))
166 {
167 proposal = proposal_create_from_string(PROTO_ESP, token);
168 if (proposal)
169 {
170 child_cfg->add_proposal(child_cfg, proposal);
171 }
172 else
173 {
174 DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token);
175 }
176 }
177 enumerator->destroy(enumerator);
178 }
179 else
180 {
181 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
182 child_cfg->add_proposal(child_cfg,
183 proposal_create_default_aead(PROTO_ESP));
184 }
185
186 token = settings->get_str(settings, "configs.%s.%s.lts", NULL, config, child);
187 if (token)
188 {
189 enumerator = enumerator_create_token(token, ",", " ");
190 while (enumerator->enumerate(enumerator, &token))
191 {
192 ts = traffic_selector_create_from_cidr(token, 0, 0, 65535);
193 if (ts)
194 {
195 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
196 }
197 else
198 {
199 DBG1(DBG_CFG, "invalid local ts: %s, skipped", token);
200 }
201 }
202 enumerator->destroy(enumerator);
203 }
204 else
205 {
206 ts = traffic_selector_create_dynamic(0, 0, 65535);
207 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
208 }
209
210 token = settings->get_str(settings, "configs.%s.%s.rts", NULL, config, child);
211 if (token)
212 {
213 enumerator = enumerator_create_token(token, ",", " ");
214 while (enumerator->enumerate(enumerator, &token))
215 {
216 ts = traffic_selector_create_from_cidr(token, 0, 0, 65535);
217 if (ts)
218 {
219 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
220 }
221 else
222 {
223 DBG1(DBG_CFG, "invalid remote ts: %s, skipped", token);
224 }
225 }
226 enumerator->destroy(enumerator);
227 }
228 else
229 {
230 ts = traffic_selector_create_dynamic(0, 0, 65535);
231 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
232 }
233 return child_cfg;
234 }
235
236 /**
237 * Load peer config for a given section name
238 */
239 static peer_cfg_t *load_peer_config(private_config_t *this,
240 settings_t *settings, char *config)
241 {
242 ike_cfg_t *ike_cfg;
243 peer_cfg_t *peer_cfg;
244 auth_cfg_t *auth;
245 child_cfg_t *child_cfg;
246 enumerator_t *enumerator;
247 identification_t *lid, *rid;
248 char *child, *policy, *pool;
249 uintptr_t strength;
250 peer_cfg_create_t peer = {
251 .cert_policy = CERT_ALWAYS_SEND,
252 .unique = UNIQUE_NO,
253 .keyingtries = 1,
254 .no_mobike = TRUE,
255 };
256
257 ike_cfg = load_ike_config(this, settings, config);
258 peer_cfg = peer_cfg_create(config, ike_cfg, &peer);
259
260 auth = auth_cfg_create();
261 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
262 lid = identification_create_from_string(
263 settings->get_str(settings, "configs.%s.lid", "%any", config));
264 auth->add(auth, AUTH_RULE_IDENTITY, lid);
265 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
266
267 auth = auth_cfg_create();
268 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
269 rid = identification_create_from_string(
270 settings->get_str(settings, "configs.%s.rid", "%any", config));
271 strength = settings->get_int(settings, "configs.%s.rsa_strength", 0, config);
272 if (strength)
273 {
274 auth->add(auth, AUTH_RULE_RSA_STRENGTH, strength);
275 }
276 strength = settings->get_int(settings, "configs.%s.ecdsa_strength", 0, config);
277 if (strength)
278 {
279 auth->add(auth, AUTH_RULE_ECDSA_STRENGTH, strength);
280 }
281 policy = settings->get_str(settings, "configs.%s.cert_policy", NULL, config);
282 if (policy)
283 {
284 auth->add(auth, AUTH_RULE_CERT_POLICY, strdup(policy));
285 }
286 auth->add(auth, AUTH_RULE_IDENTITY, rid);
287 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
288 pool = settings->get_str(settings, "configs.%s.named_pool", NULL, config);
289 if (pool)
290 {
291 peer_cfg->add_pool(peer_cfg, pool);
292 }
293
294 DBG1(DBG_CFG, "loaded config %s: %Y - %Y", config, lid, rid);
295
296 enumerator = settings->create_section_enumerator(settings,
297 "configs.%s", config);
298 while (enumerator->enumerate(enumerator, &child))
299 {
300 child_cfg = load_child_config(this, settings, config, child);
301 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
302 }
303 enumerator->destroy(enumerator);
304 return peer_cfg;
305 }
306
307 METHOD(config_t, load, void,
308 private_config_t *this, settings_t *settings)
309 {
310 enumerator_t *enumerator;
311 char *config;
312
313 enumerator = settings->create_section_enumerator(settings, "configs");
314 while (enumerator->enumerate(enumerator, &config))
315 {
316 this->configs->insert_last(this->configs,
317 load_peer_config(this, settings, config));
318 }
319 enumerator->destroy(enumerator);
320 }
321
322 METHOD(config_t, destroy, void,
323 private_config_t *this)
324 {
325 this->configs->destroy_offset(this->configs, offsetof(peer_cfg_t, destroy));
326 free(this);
327 }
328
329 /**
330 * See header
331 */
332 config_t *config_create()
333 {
334 private_config_t *this;
335
336 INIT(this,
337 .public = {
338 .backend = {
339 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
340 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
341 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
342 },
343 .load = _load,
344 .destroy = _destroy,
345 },
346 .configs = linked_list_create(),
347 );
348
349 return &this->public;
350 }