Clear virtual IPs before storing assigned ones on the IKE_SA
[strongswan.git] / src / libcharon / sa / ikev2 / 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 * Received list of virtual IPs, host_t*
47 */
48 linked_list_t *vips;
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_chunk(CONFIGURATION_ATTRIBUTE,
102 type, chunk);
103 }
104
105 /**
106 * Handle a received attribute as initiator
107 */
108 static void handle_attribute(private_ike_config_t *this,
109 configuration_attribute_t *ca)
110 {
111 attribute_handler_t *handler = NULL;
112 enumerator_t *enumerator;
113 entry_t *entry;
114
115 /* find the handler which requested this attribute */
116 enumerator = this->requested->create_enumerator(this->requested);
117 while (enumerator->enumerate(enumerator, &entry))
118 {
119 if (entry->type == ca->get_type(ca))
120 {
121 handler = entry->handler;
122 this->requested->remove_at(this->requested, enumerator);
123 free(entry);
124 break;
125 }
126 }
127 enumerator->destroy(enumerator);
128
129 /* and pass it to the handle function */
130 handler = hydra->attributes->handle(hydra->attributes,
131 this->ike_sa->get_other_id(this->ike_sa), handler,
132 ca->get_type(ca), ca->get_chunk(ca));
133 if (handler)
134 {
135 this->ike_sa->add_configuration_attribute(this->ike_sa,
136 handler, ca->get_type(ca), ca->get_chunk(ca));
137 }
138 }
139
140 /**
141 * process a single configuration attribute
142 */
143 static void process_attribute(private_ike_config_t *this,
144 configuration_attribute_t *ca)
145 {
146 host_t *ip;
147 chunk_t addr;
148 int family = AF_INET6;
149
150 switch (ca->get_type(ca))
151 {
152 case INTERNAL_IP4_ADDRESS:
153 family = AF_INET;
154 /* fall */
155 case INTERNAL_IP6_ADDRESS:
156 {
157 addr = ca->get_chunk(ca);
158 if (addr.len == 0)
159 {
160 ip = host_create_any(family);
161 }
162 else
163 {
164 /* skip prefix byte in IPv6 payload*/
165 if (family == AF_INET6)
166 {
167 addr.len--;
168 }
169 ip = host_create_from_chunk(family, addr, 0);
170 }
171 if (ip)
172 {
173 this->vips->insert_last(this->vips, 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 METHOD(task_t, build_i, status_t,
234 private_ike_config_t *this, message_t *message)
235 {
236 if (message->get_message_id(message) == 1)
237 { /* in first IKE_AUTH only */
238 cp_payload_t *cp = NULL;
239 enumerator_t *enumerator;
240 attribute_handler_t *handler;
241 peer_cfg_t *config;
242 configuration_attribute_type_t type;
243 chunk_t data;
244 linked_list_t *vips;
245 host_t *host;
246
247 vips = linked_list_create();
248
249 /* reuse virtual IP if we already have one */
250 enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
251 TRUE);
252 while (enumerator->enumerate(enumerator, &host))
253 {
254 vips->insert_last(vips, host);
255 }
256 enumerator->destroy(enumerator);
257
258 if (vips->get_count(vips) == 0)
259 {
260 config = this->ike_sa->get_peer_cfg(this->ike_sa);
261 enumerator = config->create_virtual_ip_enumerator(config);
262 while (enumerator->enumerate(enumerator, &host))
263 {
264 vips->insert_last(vips, host);
265 }
266 enumerator->destroy(enumerator);
267 }
268
269 if (vips->get_count(vips))
270 {
271 cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST);
272 enumerator = vips->create_enumerator(vips);
273 while (enumerator->enumerate(enumerator, &host))
274 {
275 cp->add_attribute(cp, build_vip(host));
276 }
277 enumerator->destroy(enumerator);
278 }
279
280 enumerator = hydra->attributes->create_initiator_enumerator(
281 hydra->attributes,
282 this->ike_sa->get_other_id(this->ike_sa), vips);
283 while (enumerator->enumerate(enumerator, &handler, &type, &data))
284 {
285 configuration_attribute_t *ca;
286 entry_t *entry;
287
288 /* create configuration attribute */
289 DBG2(DBG_IKE, "building %N attribute",
290 configuration_attribute_type_names, type);
291 ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE,
292 type, data);
293 if (!cp)
294 {
295 cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST);
296 }
297 cp->add_attribute(cp, ca);
298
299 /* save handler along with requested type */
300 entry = malloc_thing(entry_t);
301 entry->type = type;
302 entry->handler = handler;
303
304 this->requested->insert_last(this->requested, entry);
305 }
306 enumerator->destroy(enumerator);
307
308 vips->destroy(vips);
309
310 if (cp)
311 {
312 message->add_payload(message, (payload_t*)cp);
313 }
314 }
315 return NEED_MORE;
316 }
317
318 METHOD(task_t, process_r, status_t,
319 private_ike_config_t *this, message_t *message)
320 {
321 if (message->get_message_id(message) == 1)
322 { /* in first IKE_AUTH only */
323 process_payloads(this, message);
324 }
325 return NEED_MORE;
326 }
327
328 METHOD(task_t, build_r, status_t,
329 private_ike_config_t *this, message_t *message)
330 {
331 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
332 { /* in last IKE_AUTH exchange */
333 enumerator_t *enumerator;
334 configuration_attribute_type_t type;
335 chunk_t value;
336 cp_payload_t *cp = NULL;
337 peer_cfg_t *config;
338 identification_t *id;
339 linked_list_t *vips, *pools;
340 host_t *requested;
341
342 id = this->ike_sa->get_other_eap_id(this->ike_sa);
343 config = this->ike_sa->get_peer_cfg(this->ike_sa);
344 vips = linked_list_create();
345 pools = linked_list_create();
346
347 this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
348
349 enumerator = this->vips->create_enumerator(this->vips);
350 while (enumerator->enumerate(enumerator, &requested))
351 {
352 enumerator_t *poolenum;
353 char *pool;
354 host_t *found = NULL;
355
356 /* query all pools until we get an address */
357 DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
358
359 poolenum = config->create_pool_enumerator(config);
360 while (poolenum->enumerate(poolenum, &pool))
361 {
362 found = hydra->attributes->acquire_address(hydra->attributes,
363 pool, id, requested);
364 if (!found)
365 {
366 continue;
367 }
368 DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
369 this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
370 if (!cp)
371 {
372 cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
373 }
374 cp->add_attribute(cp, build_vip(found));
375 /* use pool to request other attributes */
376 if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
377 {
378 pools->insert_last(pools, pool);
379 }
380 vips->insert_last(vips, found);
381 break;
382 }
383 poolenum->destroy(poolenum);
384
385 if (!found)
386 {
387 DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
388 requested, id);
389 }
390 }
391 enumerator->destroy(enumerator);
392
393 if (this->vips->get_count(this->vips) && !vips->get_count(vips))
394 {
395 DBG1(DBG_IKE, "no virtual IP found, sending %N",
396 notify_type_names, INTERNAL_ADDRESS_FAILURE);
397 message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
398 chunk_empty);
399 vips->destroy_offset(vips, offsetof(host_t, destroy));
400 pools->destroy(pools);
401 return SUCCESS;
402 }
403
404 /* query registered providers for additional attributes to include */
405 enumerator = hydra->attributes->create_responder_enumerator(
406 hydra->attributes, pools, id, vips);
407 while (enumerator->enumerate(enumerator, &type, &value))
408 {
409 if (!cp)
410 {
411 cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
412 }
413 DBG2(DBG_IKE, "building %N attribute",
414 configuration_attribute_type_names, type);
415 cp->add_attribute(cp,
416 configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE,
417 type, value));
418 }
419 enumerator->destroy(enumerator);
420 vips->destroy_offset(vips, offsetof(host_t, destroy));
421 pools->destroy(pools);
422
423 if (cp)
424 {
425 message->add_payload(message, (payload_t*)cp);
426 }
427 return SUCCESS;
428 }
429 return NEED_MORE;
430 }
431
432 METHOD(task_t, process_i, status_t,
433 private_ike_config_t *this, message_t *message)
434 {
435 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
436 { /* in last IKE_AUTH exchange */
437 enumerator_t *enumerator;
438 host_t *host;
439
440 process_payloads(this, message);
441
442 this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
443
444 enumerator = this->vips->create_enumerator(this->vips);
445 while (enumerator->enumerate(enumerator, &host))
446 {
447 if (!host->is_anyaddr(host))
448 {
449 this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
450 }
451 }
452 enumerator->destroy(enumerator);
453 return SUCCESS;
454 }
455 return NEED_MORE;
456 }
457
458 METHOD(task_t, get_type, task_type_t,
459 private_ike_config_t *this)
460 {
461 return TASK_IKE_CONFIG;
462 }
463
464 METHOD(task_t, migrate, void,
465 private_ike_config_t *this, ike_sa_t *ike_sa)
466 {
467 this->ike_sa = ike_sa;
468 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
469 this->vips = linked_list_create();
470 this->requested->destroy_function(this->requested, free);
471 this->requested = linked_list_create();
472 }
473
474 METHOD(task_t, destroy, void,
475 private_ike_config_t *this)
476 {
477 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
478 this->requested->destroy_function(this->requested, free);
479 free(this);
480 }
481
482 /*
483 * Described in header.
484 */
485 ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
486 {
487 private_ike_config_t *this;
488
489 INIT(this,
490 .public = {
491 .task = {
492 .get_type = _get_type,
493 .migrate = _migrate,
494 .destroy = _destroy,
495 },
496 },
497 .initiator = initiator,
498 .ike_sa = ike_sa,
499 .vips = linked_list_create(),
500 .requested = linked_list_create(),
501 );
502
503 if (initiator)
504 {
505 this->public.task.build = _build_i;
506 this->public.task.process = _process_i;
507 }
508 else
509 {
510 this->public.task.build = _build_r;
511 this->public.task.process = _process_r;
512 }
513
514 return &this->public;
515 }