84247117c7e9f6448983207f224ece5e040fa3a7
[strongswan.git] / src / libcharon / sa / tasks / ike_config.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "ike_config.h"
18
19 #include <daemon.h>
20 #include <hydra.h>
21 #include <encoding/payloads/cp_payload.h>
22
23 typedef struct private_ike_config_t private_ike_config_t;
24
25 /**
26 * Private members of a ike_config_t task.
27 */
28 struct private_ike_config_t {
29
30 /**
31 * Public methods and task_t interface.
32 */
33 ike_config_t public;
34
35 /**
36 * Assigned IKE_SA.
37 */
38 ike_sa_t *ike_sa;
39
40 /**
41 * Are we the initiator?
42 */
43 bool initiator;
44
45 /**
46 * virtual ip
47 */
48 host_t *virtual_ip;
49
50 /**
51 * list of attributes requested and its handler, entry_t
52 */
53 linked_list_t *requested;
54 };
55
56 /**
57 * Entry for a requested attribute and the requesting handler
58 */
59 typedef struct {
60 /** attribute requested */
61 configuration_attribute_type_t type;
62 /** handler requesting this attribute */
63 attribute_handler_t *handler;
64 } entry_t;
65
66 /**
67 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
68 */
69 static configuration_attribute_t *build_vip(host_t *vip)
70 {
71 configuration_attribute_type_t type;
72 chunk_t chunk, prefix;
73
74 if (vip->get_family(vip) == AF_INET)
75 {
76 type = INTERNAL_IP4_ADDRESS;
77 if (vip->is_anyaddr(vip))
78 {
79 chunk = chunk_empty;
80 }
81 else
82 {
83 chunk = vip->get_address(vip);
84 }
85 }
86 else
87 {
88 type = INTERNAL_IP6_ADDRESS;
89 if (vip->is_anyaddr(vip))
90 {
91 chunk = chunk_empty;
92 }
93 else
94 {
95 prefix = chunk_alloca(1);
96 *prefix.ptr = 64;
97 chunk = vip->get_address(vip);
98 chunk = chunk_cata("cc", chunk, prefix);
99 }
100 }
101 return configuration_attribute_create_value(type, chunk);
102 }
103
104 /**
105 * Handle a received attribute as initiator
106 */
107 static void handle_attribute(private_ike_config_t *this,
108 configuration_attribute_t *ca)
109 {
110 attribute_handler_t *handler = NULL;
111 enumerator_t *enumerator;
112 entry_t *entry;
113
114 /* find the handler which requested this attribute */
115 enumerator = this->requested->create_enumerator(this->requested);
116 while (enumerator->enumerate(enumerator, &entry))
117 {
118 if (entry->type == ca->get_type(ca))
119 {
120 handler = entry->handler;
121 this->requested->remove_at(this->requested, enumerator);
122 free(entry);
123 break;
124 }
125 }
126 enumerator->destroy(enumerator);
127
128 /* and pass it to the handle function */
129 handler = hydra->attributes->handle(hydra->attributes,
130 this->ike_sa->get_other_id(this->ike_sa), handler,
131 ca->get_type(ca), ca->get_value(ca));
132 if (handler)
133 {
134 this->ike_sa->add_configuration_attribute(this->ike_sa,
135 handler, ca->get_type(ca), ca->get_value(ca));
136 }
137 }
138
139 /**
140 * process a single configuration attribute
141 */
142 static void process_attribute(private_ike_config_t *this,
143 configuration_attribute_t *ca)
144 {
145 host_t *ip;
146 chunk_t addr;
147 int family = AF_INET6;
148
149 switch (ca->get_type(ca))
150 {
151 case INTERNAL_IP4_ADDRESS:
152 family = AF_INET;
153 /* fall */
154 case INTERNAL_IP6_ADDRESS:
155 {
156 addr = ca->get_value(ca);
157 if (addr.len == 0)
158 {
159 ip = host_create_any(family);
160 }
161 else
162 {
163 /* skip prefix byte in IPv6 payload*/
164 if (family == AF_INET6)
165 {
166 addr.len--;
167 }
168 ip = host_create_from_chunk(family, addr, 0);
169 }
170 if (ip)
171 {
172 DESTROY_IF(this->virtual_ip);
173 this->virtual_ip = ip;
174 }
175 break;
176 }
177 case INTERNAL_IP4_SERVER:
178 case INTERNAL_IP6_SERVER:
179 /* assume it's a Windows client if we see proprietary attributes */
180 this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS);
181 /* fall */
182 default:
183 {
184 if (this->initiator)
185 {
186 handle_attribute(this, ca);
187 }
188 }
189 }
190 }
191
192 /**
193 * Scan for configuration payloads and attributes
194 */
195 static void process_payloads(private_ike_config_t *this, message_t *message)
196 {
197 enumerator_t *enumerator, *attributes;
198 payload_t *payload;
199
200 enumerator = message->create_payload_enumerator(message);
201 while (enumerator->enumerate(enumerator, &payload))
202 {
203 if (payload->get_type(payload) == CONFIGURATION)
204 {
205 cp_payload_t *cp = (cp_payload_t*)payload;
206 configuration_attribute_t *ca;
207
208 switch (cp->get_type(cp))
209 {
210 case CFG_REQUEST:
211 case CFG_REPLY:
212 {
213 attributes = cp->create_attribute_enumerator(cp);
214 while (attributes->enumerate(attributes, &ca))
215 {
216 DBG2(DBG_IKE, "processing %N attribute",
217 configuration_attribute_type_names, ca->get_type(ca));
218 process_attribute(this, ca);
219 }
220 attributes->destroy(attributes);
221 break;
222 }
223 default:
224 DBG1(DBG_IKE, "ignoring %N config payload",
225 config_type_names, cp->get_type(cp));
226 break;
227 }
228 }
229 }
230 enumerator->destroy(enumerator);
231 }
232
233 /**
234 * Implementation of task_t.process for initiator
235 */
236 static status_t build_i(private_ike_config_t *this, message_t *message)
237 {
238 if (message->get_message_id(message) == 1)
239 { /* in first IKE_AUTH only */
240 cp_payload_t *cp = NULL;
241 enumerator_t *enumerator;
242 attribute_handler_t *handler;
243 peer_cfg_t *config;
244 configuration_attribute_type_t type;
245 chunk_t data;
246 host_t *vip;
247
248 /* reuse virtual IP if we already have one */
249 vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
250 if (!vip)
251 {
252 config = this->ike_sa->get_peer_cfg(this->ike_sa);
253 vip = config->get_virtual_ip(config);
254 }
255 if (vip)
256 {
257 cp = cp_payload_create_type(CFG_REQUEST);
258 cp->add_attribute(cp, build_vip(vip));
259 }
260
261 enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes,
262 this->ike_sa->get_other_id(this->ike_sa), vip);
263 while (enumerator->enumerate(enumerator, &handler, &type, &data))
264 {
265 configuration_attribute_t *ca;
266 entry_t *entry;
267
268 /* create configuration attribute */
269 DBG2(DBG_IKE, "building %N attribute",
270 configuration_attribute_type_names, type);
271 ca = configuration_attribute_create_value(type, data);
272 if (!cp)
273 {
274 cp = cp_payload_create_type(CFG_REQUEST);
275 }
276 cp->add_attribute(cp, ca);
277
278 /* save handler along with requested type */
279 entry = malloc_thing(entry_t);
280 entry->type = type;
281 entry->handler = handler;
282
283 this->requested->insert_last(this->requested, entry);
284 }
285 enumerator->destroy(enumerator);
286
287 if (cp)
288 {
289 message->add_payload(message, (payload_t*)cp);
290 }
291 }
292 return NEED_MORE;
293 }
294
295 /**
296 * Implementation of task_t.process for responder
297 */
298 static status_t process_r(private_ike_config_t *this, message_t *message)
299 {
300 if (message->get_message_id(message) == 1)
301 { /* in first IKE_AUTH only */
302 process_payloads(this, message);
303 }
304 return NEED_MORE;
305 }
306
307 /**
308 * Implementation of task_t.build for responder
309 */
310 static status_t build_r(private_ike_config_t *this, message_t *message)
311 {
312 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
313 { /* in last IKE_AUTH exchange */
314 enumerator_t *enumerator;
315 configuration_attribute_type_t type;
316 chunk_t value;
317 host_t *vip = NULL;
318 cp_payload_t *cp = NULL;
319 peer_cfg_t *config;
320 identification_t *id;
321
322 id = this->ike_sa->get_other_eap_id(this->ike_sa);
323
324 config = this->ike_sa->get_peer_cfg(this->ike_sa);
325 if (this->virtual_ip)
326 {
327 DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
328 if (config->get_pool(config))
329 {
330 vip = hydra->attributes->acquire_address(hydra->attributes,
331 config->get_pool(config), id, this->virtual_ip);
332 }
333 if (vip == NULL)
334 {
335 DBG1(DBG_IKE, "no virtual IP found, sending %N",
336 notify_type_names, INTERNAL_ADDRESS_FAILURE);
337 message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
338 chunk_empty);
339 return SUCCESS;
340 }
341 DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id);
342 this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
343
344 cp = cp_payload_create_type(CFG_REPLY);
345 cp->add_attribute(cp, build_vip(vip));
346 }
347
348 /* query registered providers for additional attributes to include */
349 enumerator = hydra->attributes->create_responder_enumerator(
350 hydra->attributes, config->get_pool(config), id, vip);
351 while (enumerator->enumerate(enumerator, &type, &value))
352 {
353 if (!cp)
354 {
355 cp = cp_payload_create_type(CFG_REPLY);
356 }
357 DBG2(DBG_IKE, "building %N attribute",
358 configuration_attribute_type_names, type);
359 cp->add_attribute(cp,
360 configuration_attribute_create_value(type, value));
361 }
362 enumerator->destroy(enumerator);
363
364 if (cp)
365 {
366 message->add_payload(message, (payload_t*)cp);
367 }
368 DESTROY_IF(vip);
369 return SUCCESS;
370 }
371 return NEED_MORE;
372 }
373
374 /**
375 * Implementation of task_t.process for initiator
376 */
377 static status_t process_i(private_ike_config_t *this, message_t *message)
378 {
379 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
380 { /* in last IKE_AUTH exchange */
381
382 process_payloads(this, message);
383
384 if (this->virtual_ip)
385 {
386 this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
387 }
388 return SUCCESS;
389 }
390 return NEED_MORE;
391 }
392
393 /**
394 * Implementation of task_t.get_type
395 */
396 static task_type_t get_type(private_ike_config_t *this)
397 {
398 return IKE_CONFIG;
399 }
400
401 /**
402 * Implementation of task_t.migrate
403 */
404 static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
405 {
406 DESTROY_IF(this->virtual_ip);
407
408 this->ike_sa = ike_sa;
409 this->virtual_ip = NULL;
410 this->requested->destroy_function(this->requested, free);
411 this->requested = linked_list_create();
412 }
413
414 /**
415 * Implementation of task_t.destroy
416 */
417 static void destroy(private_ike_config_t *this)
418 {
419 DESTROY_IF(this->virtual_ip);
420 this->requested->destroy_function(this->requested, free);
421 free(this);
422 }
423
424 /*
425 * Described in header.
426 */
427 ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
428 {
429 private_ike_config_t *this = malloc_thing(private_ike_config_t);
430
431 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
432 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
433 this->public.task.destroy = (void(*)(task_t*))destroy;
434
435 this->initiator = initiator;
436 this->ike_sa = ike_sa;
437 this->virtual_ip = NULL;
438 this->requested = linked_list_create();
439
440 if (initiator)
441 {
442 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
443 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
444 }
445 else
446 {
447 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
448 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
449 }
450
451 return &this->public;
452 }
453