mode-config: Reassign migrated virtual IP if client requests %any
[strongswan.git] / src / libcharon / sa / ikev1 / tasks / mode_config.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 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 "mode_config.h"
17
18 #include <daemon.h>
19 #include <encoding/payloads/cp_payload.h>
20
21 typedef struct private_mode_config_t private_mode_config_t;
22
23 /**
24 * Private members of a mode_config_t task.
25 */
26 struct private_mode_config_t {
27
28 /**
29 * Public methods and task_t interface.
30 */
31 mode_config_t public;
32
33 /**
34 * Assigned IKE_SA.
35 */
36 ike_sa_t *ike_sa;
37
38 /**
39 * Are we the initiator?
40 */
41 bool initiator;
42
43 /**
44 * Use pull (CFG_REQUEST/RESPONSE) or push (CFG_SET/ACK)?
45 */
46 bool pull;
47
48 /**
49 * Received list of virtual IPs, host_t*
50 */
51 linked_list_t *vips;
52
53 /**
54 * Requested/received list of attributes, entry_t
55 */
56 linked_list_t *attributes;
57
58 /**
59 * Identifier to include in response
60 */
61 u_int16_t identifier;
62 };
63
64 /**
65 * Entry for a attribute and associated handler
66 */
67 typedef struct {
68 /** attribute type */
69 configuration_attribute_type_t type;
70 /** handler for this attribute */
71 attribute_handler_t *handler;
72 } entry_t;
73
74 /**
75 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
76 */
77 static configuration_attribute_t *build_vip(host_t *vip)
78 {
79 configuration_attribute_type_t type;
80 chunk_t chunk, prefix;
81
82 if (vip->get_family(vip) == AF_INET)
83 {
84 type = INTERNAL_IP4_ADDRESS;
85 if (vip->is_anyaddr(vip))
86 {
87 chunk = chunk_empty;
88 }
89 else
90 {
91 chunk = vip->get_address(vip);
92 }
93 }
94 else
95 {
96 type = INTERNAL_IP6_ADDRESS;
97 if (vip->is_anyaddr(vip))
98 {
99 chunk = chunk_empty;
100 }
101 else
102 {
103 prefix = chunk_alloca(1);
104 *prefix.ptr = 64;
105 chunk = vip->get_address(vip);
106 chunk = chunk_cata("cc", chunk, prefix);
107 }
108 }
109 return configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
110 type, chunk);
111 }
112
113 /**
114 * Handle a received attribute as initiator
115 */
116 static void handle_attribute(private_mode_config_t *this,
117 configuration_attribute_t *ca)
118 {
119 attribute_handler_t *handler = NULL;
120 enumerator_t *enumerator;
121 entry_t *entry;
122
123 /* find the handler which requested this attribute */
124 enumerator = this->attributes->create_enumerator(this->attributes);
125 while (enumerator->enumerate(enumerator, &entry))
126 {
127 if (entry->type == ca->get_type(ca))
128 {
129 handler = entry->handler;
130 this->attributes->remove_at(this->attributes, enumerator);
131 free(entry);
132 break;
133 }
134 }
135 enumerator->destroy(enumerator);
136
137 /* and pass it to the handle function */
138 handler = charon->attributes->handle(charon->attributes,
139 this->ike_sa, handler, ca->get_type(ca), ca->get_chunk(ca));
140 this->ike_sa->add_configuration_attribute(this->ike_sa,
141 handler, ca->get_type(ca), ca->get_chunk(ca));
142 }
143
144 /**
145 * process a single configuration attribute
146 */
147 static void process_attribute(private_mode_config_t *this,
148 configuration_attribute_t *ca)
149 {
150 host_t *ip;
151 chunk_t addr;
152 int family = AF_INET6;
153
154 switch (ca->get_type(ca))
155 {
156 case INTERNAL_IP4_ADDRESS:
157 family = AF_INET;
158 /* fall */
159 case INTERNAL_IP6_ADDRESS:
160 {
161 addr = ca->get_chunk(ca);
162 if (addr.len == 0)
163 {
164 ip = host_create_any(family);
165 }
166 else
167 {
168 /* skip prefix byte in IPv6 payload*/
169 if (family == AF_INET6)
170 {
171 addr.len--;
172 }
173 ip = host_create_from_chunk(family, addr, 0);
174 }
175 if (ip)
176 {
177 this->vips->insert_last(this->vips, ip);
178 }
179 break;
180 }
181 default:
182 {
183 if (this->initiator == this->pull)
184 {
185 handle_attribute(this, ca);
186 }
187 }
188 }
189 }
190
191 /**
192 * Check if config allows push mode when acting as task responder
193 */
194 static bool accept_push(private_mode_config_t *this)
195 {
196 enumerator_t *enumerator;
197 peer_cfg_t *config;
198 bool vip;
199 host_t *host;
200
201 config = this->ike_sa->get_peer_cfg(this->ike_sa);
202 enumerator = config->create_virtual_ip_enumerator(config);
203 vip = enumerator->enumerate(enumerator, &host);
204 enumerator->destroy(enumerator);
205
206 return vip && !config->use_pull_mode(config);
207 }
208
209 /**
210 * Scan for configuration payloads and attributes
211 */
212 static void process_payloads(private_mode_config_t *this, message_t *message)
213 {
214 enumerator_t *enumerator, *attributes;
215 payload_t *payload;
216
217 enumerator = message->create_payload_enumerator(message);
218 while (enumerator->enumerate(enumerator, &payload))
219 {
220 if (payload->get_type(payload) == PLV1_CONFIGURATION)
221 {
222 cp_payload_t *cp = (cp_payload_t*)payload;
223 configuration_attribute_t *ca;
224
225 switch (cp->get_type(cp))
226 {
227 case CFG_SET:
228 /* when acting as a responder, we detect the mode using
229 * the type of configuration payload. But we should double
230 * check the peer is allowed to use push mode on us. */
231 if (!this->initiator && accept_push(this))
232 {
233 this->pull = FALSE;
234 }
235 /* FALL */
236 case CFG_REQUEST:
237 this->identifier = cp->get_identifier(cp);
238 /* FALL */
239 case CFG_REPLY:
240 attributes = cp->create_attribute_enumerator(cp);
241 while (attributes->enumerate(attributes, &ca))
242 {
243 DBG2(DBG_IKE, "processing %N attribute",
244 configuration_attribute_type_names, ca->get_type(ca));
245 process_attribute(this, ca);
246 }
247 attributes->destroy(attributes);
248 break;
249 case CFG_ACK:
250 break;
251 default:
252 DBG1(DBG_IKE, "ignoring %N config payload",
253 config_type_names, cp->get_type(cp));
254 break;
255 }
256 }
257 }
258 enumerator->destroy(enumerator);
259 }
260
261 /**
262 * Add an attribute to a configuration payload, and store it in task
263 */
264 static void add_attribute(private_mode_config_t *this, cp_payload_t *cp,
265 configuration_attribute_type_t type, chunk_t data,
266 attribute_handler_t *handler)
267 {
268 entry_t *entry;
269
270 cp->add_attribute(cp,
271 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
272 type, data));
273 INIT(entry,
274 .type = type,
275 .handler = handler,
276 );
277 this->attributes->insert_last(this->attributes, entry);
278 }
279
280 /**
281 * Build a CFG_REQUEST as initiator
282 */
283 static status_t build_request(private_mode_config_t *this, message_t *message)
284 {
285 cp_payload_t *cp;
286 enumerator_t *enumerator;
287 attribute_handler_t *handler;
288 peer_cfg_t *config;
289 configuration_attribute_type_t type;
290 chunk_t data;
291 linked_list_t *vips;
292 host_t *host;
293
294 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
295
296 vips = linked_list_create();
297
298 /* reuse virtual IP if we already have one */
299 enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
300 while (enumerator->enumerate(enumerator, &host))
301 {
302 vips->insert_last(vips, host);
303 }
304 enumerator->destroy(enumerator);
305
306 if (vips->get_count(vips) == 0)
307 {
308 config = this->ike_sa->get_peer_cfg(this->ike_sa);
309 enumerator = config->create_virtual_ip_enumerator(config);
310 while (enumerator->enumerate(enumerator, &host))
311 {
312 vips->insert_last(vips, host);
313 }
314 enumerator->destroy(enumerator);
315 }
316
317 if (vips->get_count(vips))
318 {
319 enumerator = vips->create_enumerator(vips);
320 while (enumerator->enumerate(enumerator, &host))
321 {
322 cp->add_attribute(cp, build_vip(host));
323 }
324 enumerator->destroy(enumerator);
325 }
326
327 enumerator = charon->attributes->create_initiator_enumerator(
328 charon->attributes, this->ike_sa, vips);
329 while (enumerator->enumerate(enumerator, &handler, &type, &data))
330 {
331 add_attribute(this, cp, type, data, handler);
332 }
333 enumerator->destroy(enumerator);
334
335 vips->destroy(vips);
336
337 message->add_payload(message, (payload_t*)cp);
338
339 return NEED_MORE;
340 }
341
342 /**
343 * Build a CFG_SET as initiator
344 */
345 static status_t build_set(private_mode_config_t *this, message_t *message)
346 {
347 enumerator_t *enumerator;
348 configuration_attribute_type_t type;
349 chunk_t value;
350 cp_payload_t *cp;
351 peer_cfg_t *config;
352 identification_t *id;
353 linked_list_t *pools, *migrated, *vips;
354 host_t *any4, *any6, *found;
355 char *name;
356
357 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_SET);
358
359 id = this->ike_sa->get_other_eap_id(this->ike_sa);
360 config = this->ike_sa->get_peer_cfg(this->ike_sa);
361
362 /* if we migrated virtual IPs during reauthentication, reassign them */
363 migrated = linked_list_create_from_enumerator(
364 this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
365 FALSE));
366 vips = migrated->clone_offset(migrated, offsetof(host_t, clone));
367 migrated->destroy(migrated);
368 this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
369
370 /* in push mode, we ask each configured pool for an address */
371 if (!vips->get_count(vips))
372 {
373 any4 = host_create_any(AF_INET);
374 any6 = host_create_any(AF_INET6);
375 enumerator = config->create_pool_enumerator(config);
376 while (enumerator->enumerate(enumerator, &name))
377 {
378 pools = linked_list_create_with_items(name, NULL);
379 /* try IPv4, then IPv6 */
380 found = charon->attributes->acquire_address(charon->attributes,
381 pools, this->ike_sa, any4);
382 if (!found)
383 {
384 found = charon->attributes->acquire_address(charon->attributes,
385 pools, this->ike_sa, any6);
386 }
387 pools->destroy(pools);
388 if (found)
389 {
390 vips->insert_last(vips, found);
391 }
392 }
393 enumerator->destroy(enumerator);
394 any4->destroy(any4);
395 any6->destroy(any6);
396 }
397
398 enumerator = vips->create_enumerator(vips);
399 while (enumerator->enumerate(enumerator, &found))
400 {
401 DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
402 this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
403 cp->add_attribute(cp, build_vip(found));
404 this->vips->insert_last(this->vips, found);
405 vips->remove_at(vips, enumerator);
406 }
407 enumerator->destroy(enumerator);
408 vips->destroy(vips);
409
410 charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
411
412 /* query registered providers for additional attributes to include */
413 pools = linked_list_create_from_enumerator(
414 config->create_pool_enumerator(config));
415 enumerator = charon->attributes->create_responder_enumerator(
416 charon->attributes, pools, this->ike_sa, this->vips);
417 while (enumerator->enumerate(enumerator, &type, &value))
418 {
419 add_attribute(this, cp, type, value, NULL);
420 }
421 enumerator->destroy(enumerator);
422 pools->destroy(pools);
423
424 message->add_payload(message, (payload_t*)cp);
425
426 return SUCCESS;
427 }
428
429 METHOD(task_t, build_i, status_t,
430 private_mode_config_t *this, message_t *message)
431 {
432 if (this->pull)
433 {
434 return build_request(this, message);
435 }
436 return build_set(this, message);
437 }
438
439 /**
440 * Store received virtual IPs to the IKE_SA, install them
441 */
442 static void install_vips(private_mode_config_t *this)
443 {
444 enumerator_t *enumerator;
445 host_t *host;
446
447 this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
448
449 enumerator = this->vips->create_enumerator(this->vips);
450 while (enumerator->enumerate(enumerator, &host))
451 {
452 if (!host->is_anyaddr(host))
453 {
454 this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
455 }
456 }
457 enumerator->destroy(enumerator);
458
459 charon->bus->handle_vips(charon->bus, this->ike_sa, TRUE);
460 }
461
462 METHOD(task_t, process_r, status_t,
463 private_mode_config_t *this, message_t *message)
464 {
465 process_payloads(this, message);
466
467 if (!this->pull)
468 {
469 install_vips(this);
470 }
471 return NEED_MORE;
472 }
473
474 /**
475 * Assign a migrated virtual IP
476 */
477 static host_t *assign_migrated_vip(linked_list_t *migrated, host_t *requested)
478 {
479 enumerator_t *enumerator;
480 host_t *found = NULL, *vip;
481
482 enumerator = migrated->create_enumerator(migrated);
483 while (enumerator->enumerate(enumerator, &vip))
484 {
485 if (vip->ip_equals(vip, requested) ||
486 (requested->is_anyaddr(requested) &&
487 requested->get_family(requested) == vip->get_family(vip)))
488 {
489 migrated->remove_at(migrated, enumerator);
490 found = vip;
491 break;
492 }
493 }
494 enumerator->destroy(enumerator);
495 return found;
496 }
497
498 /**
499 * Build CFG_REPLY message after receiving CFG_REQUEST
500 */
501 static status_t build_reply(private_mode_config_t *this, message_t *message)
502 {
503 enumerator_t *enumerator;
504 configuration_attribute_type_t type;
505 chunk_t value;
506 cp_payload_t *cp;
507 peer_cfg_t *config;
508 identification_t *id;
509 linked_list_t *vips, *pools, *migrated;
510 host_t *requested, *found;
511
512 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
513
514 id = this->ike_sa->get_other_eap_id(this->ike_sa);
515 config = this->ike_sa->get_peer_cfg(this->ike_sa);
516 pools = linked_list_create_from_enumerator(
517 config->create_pool_enumerator(config));
518 /* if we migrated virtual IPs during reauthentication, reassign them */
519 vips = linked_list_create_from_enumerator(
520 this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
521 FALSE));
522 migrated = vips->clone_offset(vips, offsetof(host_t, clone));
523 vips->destroy(vips);
524 this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
525
526 vips = linked_list_create();
527 enumerator = this->vips->create_enumerator(this->vips);
528 while (enumerator->enumerate(enumerator, &requested))
529 {
530 DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
531
532 found = assign_migrated_vip(migrated, requested);
533 if (!found)
534 {
535 found = charon->attributes->acquire_address(charon->attributes,
536 pools, this->ike_sa, requested);
537 }
538 if (found)
539 {
540 DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
541 this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
542 cp->add_attribute(cp, build_vip(found));
543 vips->insert_last(vips, found);
544 }
545 else
546 {
547 DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
548 requested, id);
549 }
550 }
551 enumerator->destroy(enumerator);
552
553 charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
554
555 /* query registered providers for additional attributes to include */
556 enumerator = charon->attributes->create_responder_enumerator(
557 charon->attributes, pools, this->ike_sa, vips);
558 while (enumerator->enumerate(enumerator, &type, &value))
559 {
560 cp->add_attribute(cp,
561 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
562 type, value));
563 }
564 enumerator->destroy(enumerator);
565 /* if a client did not re-request all adresses, release them */
566 enumerator = migrated->create_enumerator(migrated);
567 while (enumerator->enumerate(enumerator, &found))
568 {
569 charon->attributes->release_address(charon->attributes,
570 pools, found, this->ike_sa);
571 }
572 enumerator->destroy(enumerator);
573 migrated->destroy_offset(migrated, offsetof(host_t, destroy));
574 vips->destroy_offset(vips, offsetof(host_t, destroy));
575 pools->destroy(pools);
576
577 cp->set_identifier(cp, this->identifier);
578 message->add_payload(message, (payload_t*)cp);
579
580 return SUCCESS;
581 }
582
583 /**
584 * Build CFG_ACK for a received CFG_SET
585 */
586 static status_t build_ack(private_mode_config_t *this, message_t *message)
587 {
588 cp_payload_t *cp;
589 enumerator_t *enumerator;
590 host_t *host;
591 configuration_attribute_type_t type;
592 entry_t *entry;
593
594 cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_ACK);
595
596 /* return empty attributes for installed IPs */
597
598 enumerator = this->vips->create_enumerator(this->vips);
599 while (enumerator->enumerate(enumerator, &host))
600 {
601 type = INTERNAL_IP6_ADDRESS;
602 if (host->get_family(host) == AF_INET6)
603 {
604 type = INTERNAL_IP6_ADDRESS;
605 }
606 else
607 {
608 type = INTERNAL_IP4_ADDRESS;
609 }
610 cp->add_attribute(cp, configuration_attribute_create_chunk(
611 PLV1_CONFIGURATION_ATTRIBUTE, type, chunk_empty));
612 }
613 enumerator->destroy(enumerator);
614
615 enumerator = this->attributes->create_enumerator(this->attributes);
616 while (enumerator->enumerate(enumerator, &entry))
617 {
618 cp->add_attribute(cp,
619 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE,
620 entry->type, chunk_empty));
621 }
622 enumerator->destroy(enumerator);
623
624 cp->set_identifier(cp, this->identifier);
625 message->add_payload(message, (payload_t*)cp);
626
627 return SUCCESS;
628 }
629
630 METHOD(task_t, build_r, status_t,
631 private_mode_config_t *this, message_t *message)
632 {
633 if (this->pull)
634 {
635 return build_reply(this, message);
636 }
637 return build_ack(this, message);
638 }
639
640 METHOD(task_t, process_i, status_t,
641 private_mode_config_t *this, message_t *message)
642 {
643 process_payloads(this, message);
644
645 if (this->pull)
646 {
647 install_vips(this);
648 }
649 return SUCCESS;
650 }
651
652 METHOD(task_t, get_type, task_type_t,
653 private_mode_config_t *this)
654 {
655 return TASK_MODE_CONFIG;
656 }
657
658 METHOD(task_t, migrate, void,
659 private_mode_config_t *this, ike_sa_t *ike_sa)
660 {
661 this->ike_sa = ike_sa;
662 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
663 this->vips = linked_list_create();
664 this->attributes->destroy_function(this->attributes, free);
665 this->attributes = linked_list_create();
666 }
667
668 METHOD(task_t, destroy, void,
669 private_mode_config_t *this)
670 {
671 this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
672 this->attributes->destroy_function(this->attributes, free);
673 free(this);
674 }
675
676 /*
677 * Described in header.
678 */
679 mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull)
680 {
681 private_mode_config_t *this;
682
683 INIT(this,
684 .public = {
685 .task = {
686 .get_type = _get_type,
687 .migrate = _migrate,
688 .destroy = _destroy,
689 },
690 },
691 .initiator = initiator,
692 .pull = initiator ? pull : TRUE,
693 .ike_sa = ike_sa,
694 .attributes = linked_list_create(),
695 .vips = linked_list_create(),
696 );
697
698 if (initiator)
699 {
700 this->public.task.build = _build_i;
701 this->public.task.process = _process_i;
702 }
703 else
704 {
705 this->public.task.build = _build_r;
706 this->public.task.process = _process_r;
707 }
708
709 return &this->public;
710 }