Merge branch 'childless'
[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 CALLBACK(ike_filter, bool,
40 void *data, enumerator_t *orig, va_list args)
41 {
42 peer_cfg_t *cfg;
43 ike_cfg_t **out;
44
45 VA_ARGS_VGET(args, out);
46
47 if (orig->enumerate(orig, &cfg))
48 {
49 *out = cfg->get_ike_cfg(cfg);
50 return TRUE;
51 }
52 return FALSE;
53 }
54
55 METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
56 private_config_t *this, host_t *me, host_t *other)
57 {
58
59 return enumerator_create_filter(
60 this->configs->create_enumerator(this->configs),
61 ike_filter, NULL, NULL);
62 }
63
64 METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
65 private_config_t *this, identification_t *me, identification_t *other)
66 {
67 return this->configs->create_enumerator(this->configs);
68 }
69
70 METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
71 private_config_t *this, char *name)
72 {
73 enumerator_t *e1, *e2;
74 peer_cfg_t *current, *found = NULL;
75 child_cfg_t *child;
76
77 e1 = this->configs->create_enumerator(this->configs);
78 while (e1->enumerate(e1, &current))
79 {
80 e2 = current->create_child_cfg_enumerator(current);
81 while (e2->enumerate(e2, &child))
82 {
83 if (streq(child->get_name(child), name))
84 {
85 found = current;
86 found->get_ref(found);
87 break;
88 }
89 }
90 e2->destroy(e2);
91 if (found)
92 {
93 break;
94 }
95 }
96 e1->destroy(e1);
97 return found;
98 }
99
100 /**
101 * Load IKE config for a given section name
102 */
103 static ike_cfg_t *load_ike_config(private_config_t *this,
104 settings_t *settings, char *config)
105 {
106 enumerator_t *enumerator;
107 ike_cfg_t *ike_cfg;
108 proposal_t *proposal;
109 char *token;
110 ike_cfg_create_t ike = {
111 .version = IKEV2,
112 .local = settings->get_str(settings, "configs.%s.lhost",
113 "%any", config),
114 .local_port = settings->get_int(settings, "configs.%s.lport",
115 500, config),
116 .remote = settings->get_str(settings, "configs.%s.rhost",
117 "%any", config),
118 .remote_port = settings->get_int(settings, "configs.%s.rport",
119 500, config),
120 .force_encap = settings->get_bool(settings, "configs.%s.fake_nat",
121 FALSE, config),
122 };
123
124 ike_cfg = ike_cfg_create(&ike);
125 token = settings->get_str(settings, "configs.%s.proposal", NULL, config);
126 if (token)
127 {
128 enumerator = enumerator_create_token(token, ",", " ");
129 while (enumerator->enumerate(enumerator, &token))
130 {
131 proposal = proposal_create_from_string(PROTO_IKE, token);
132 if (proposal)
133 {
134 ike_cfg->add_proposal(ike_cfg, proposal);
135 }
136 else
137 {
138 DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token);
139 }
140 }
141 enumerator->destroy(enumerator);
142 }
143 else
144 {
145 ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
146 ike_cfg->add_proposal(ike_cfg, proposal_create_default_aead(PROTO_IKE));
147 }
148 return ike_cfg;
149 }
150 /**
151 * Load CHILD config for given section names
152 */
153 static child_cfg_t *load_child_config(private_config_t *this,
154 settings_t *settings, char *config, char *child)
155 {
156 child_cfg_create_t data = {
157 .mode = MODE_TUNNEL,
158 };
159 child_cfg_t *child_cfg;
160 enumerator_t *enumerator;
161 proposal_t *proposal;
162 traffic_selector_t *ts;
163 char *token;
164
165 if (settings->get_bool(settings, "configs.%s.%s.transport",
166 FALSE, config, child))
167 {
168 data.mode = MODE_TRANSPORT;
169 }
170 data.tfc = settings->get_int(settings, "configs.%s.%s.tfc_padding",
171 0, config, child);
172 child_cfg = child_cfg_create(child, &data);
173
174 token = settings->get_str(settings, "configs.%s.%s.proposal",
175 NULL, config, child);
176 if (token)
177 {
178 enumerator = enumerator_create_token(token, ",", " ");
179 while (enumerator->enumerate(enumerator, &token))
180 {
181 proposal = proposal_create_from_string(PROTO_ESP, token);
182 if (proposal)
183 {
184 child_cfg->add_proposal(child_cfg, proposal);
185 }
186 else
187 {
188 DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token);
189 }
190 }
191 enumerator->destroy(enumerator);
192 }
193 else
194 {
195 child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
196 child_cfg->add_proposal(child_cfg,
197 proposal_create_default_aead(PROTO_ESP));
198 }
199
200 token = settings->get_str(settings, "configs.%s.%s.lts", NULL, config, child);
201 if (token)
202 {
203 enumerator = enumerator_create_token(token, ",", " ");
204 while (enumerator->enumerate(enumerator, &token))
205 {
206 ts = traffic_selector_create_from_cidr(token, 0, 0, 65535);
207 if (ts)
208 {
209 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
210 }
211 else
212 {
213 DBG1(DBG_CFG, "invalid local ts: %s, skipped", token);
214 }
215 }
216 enumerator->destroy(enumerator);
217 }
218 else
219 {
220 ts = traffic_selector_create_dynamic(0, 0, 65535);
221 child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
222 }
223
224 token = settings->get_str(settings, "configs.%s.%s.rts", NULL, config, child);
225 if (token)
226 {
227 enumerator = enumerator_create_token(token, ",", " ");
228 while (enumerator->enumerate(enumerator, &token))
229 {
230 ts = traffic_selector_create_from_cidr(token, 0, 0, 65535);
231 if (ts)
232 {
233 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
234 }
235 else
236 {
237 DBG1(DBG_CFG, "invalid remote ts: %s, skipped", token);
238 }
239 }
240 enumerator->destroy(enumerator);
241 }
242 else
243 {
244 ts = traffic_selector_create_dynamic(0, 0, 65535);
245 child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
246 }
247 return child_cfg;
248 }
249
250 /**
251 * Load peer config for a given section name
252 */
253 static peer_cfg_t *load_peer_config(private_config_t *this,
254 settings_t *settings, char *config)
255 {
256 ike_cfg_t *ike_cfg;
257 peer_cfg_t *peer_cfg;
258 auth_cfg_t *auth;
259 child_cfg_t *child_cfg;
260 enumerator_t *enumerator;
261 identification_t *lid, *rid;
262 char *child, *policy, *pool;
263 uintptr_t strength;
264 peer_cfg_create_t peer = {
265 .cert_policy = CERT_ALWAYS_SEND,
266 .unique = UNIQUE_NO,
267 .keyingtries = 1,
268 .no_mobike = TRUE,
269 };
270
271 ike_cfg = load_ike_config(this, settings, config);
272 peer_cfg = peer_cfg_create(config, ike_cfg, &peer);
273
274 auth = auth_cfg_create();
275 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
276 lid = identification_create_from_string(
277 settings->get_str(settings, "configs.%s.lid", "%any", config));
278 auth->add(auth, AUTH_RULE_IDENTITY, lid);
279 peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE);
280
281 auth = auth_cfg_create();
282 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
283 rid = identification_create_from_string(
284 settings->get_str(settings, "configs.%s.rid", "%any", config));
285 strength = settings->get_int(settings, "configs.%s.rsa_strength", 0, config);
286 if (strength)
287 {
288 auth->add(auth, AUTH_RULE_RSA_STRENGTH, strength);
289 }
290 strength = settings->get_int(settings, "configs.%s.ecdsa_strength", 0, config);
291 if (strength)
292 {
293 auth->add(auth, AUTH_RULE_ECDSA_STRENGTH, strength);
294 }
295 policy = settings->get_str(settings, "configs.%s.cert_policy", NULL, config);
296 if (policy)
297 {
298 auth->add(auth, AUTH_RULE_CERT_POLICY, strdup(policy));
299 }
300 auth->add(auth, AUTH_RULE_IDENTITY, rid);
301 peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE);
302 pool = settings->get_str(settings, "configs.%s.named_pool", NULL, config);
303 if (pool)
304 {
305 peer_cfg->add_pool(peer_cfg, pool);
306 }
307
308 DBG1(DBG_CFG, "loaded config %s: %Y - %Y", config, lid, rid);
309
310 enumerator = settings->create_section_enumerator(settings,
311 "configs.%s", config);
312 while (enumerator->enumerate(enumerator, &child))
313 {
314 child_cfg = load_child_config(this, settings, config, child);
315 peer_cfg->add_child_cfg(peer_cfg, child_cfg);
316 }
317 enumerator->destroy(enumerator);
318 return peer_cfg;
319 }
320
321 METHOD(config_t, load, void,
322 private_config_t *this, settings_t *settings)
323 {
324 enumerator_t *enumerator;
325 char *config;
326
327 enumerator = settings->create_section_enumerator(settings, "configs");
328 while (enumerator->enumerate(enumerator, &config))
329 {
330 this->configs->insert_last(this->configs,
331 load_peer_config(this, settings, config));
332 }
333 enumerator->destroy(enumerator);
334 }
335
336 METHOD(config_t, destroy, void,
337 private_config_t *this)
338 {
339 this->configs->destroy_offset(this->configs, offsetof(peer_cfg_t, destroy));
340 free(this);
341 }
342
343 /**
344 * See header
345 */
346 config_t *config_create()
347 {
348 private_config_t *this;
349
350 INIT(this,
351 .public = {
352 .backend = {
353 .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
354 .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
355 .get_peer_cfg_by_name = _get_peer_cfg_by_name,
356 },
357 .load = _load,
358 .destroy = _destroy,
359 },
360 .configs = linked_list_create(),
361 );
362
363 return &this->public;
364 }