2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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>.
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
16 #include "mode_config.h"
19 #include <encoding/payloads/cp_payload.h>
21 typedef struct private_mode_config_t private_mode_config_t
;
24 * Private members of a mode_config_t task.
26 struct private_mode_config_t
{
29 * Public methods and task_t interface.
39 * Are we the initiator?
44 * Use pull (CFG_REQUEST/RESPONSE) or push (CFG_SET/ACK)?
49 * Received list of virtual IPs, host_t*
54 * Requested/received list of attributes, entry_t
56 linked_list_t
*attributes
;
59 * Identifier to include in response
65 * Entry for a attribute and associated handler
69 configuration_attribute_type_t type
;
70 /** handler for this attribute */
71 attribute_handler_t
*handler
;
75 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
77 static configuration_attribute_t
*build_vip(host_t
*vip
)
79 configuration_attribute_type_t type
;
80 chunk_t chunk
, prefix
;
82 if (vip
->get_family(vip
) == AF_INET
)
84 type
= INTERNAL_IP4_ADDRESS
;
85 if (vip
->is_anyaddr(vip
))
91 chunk
= vip
->get_address(vip
);
96 type
= INTERNAL_IP6_ADDRESS
;
97 if (vip
->is_anyaddr(vip
))
103 prefix
= chunk_alloca(1);
105 chunk
= vip
->get_address(vip
);
106 chunk
= chunk_cata("cc", chunk
, prefix
);
109 return configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE
,
114 * Handle a received attribute as initiator
116 static void handle_attribute(private_mode_config_t
*this,
117 configuration_attribute_t
*ca
)
119 attribute_handler_t
*handler
= NULL
;
120 enumerator_t
*enumerator
;
123 /* find the handler which requested this attribute */
124 enumerator
= this->attributes
->create_enumerator(this->attributes
);
125 while (enumerator
->enumerate(enumerator
, &entry
))
127 if (entry
->type
== ca
->get_type(ca
))
129 handler
= entry
->handler
;
130 this->attributes
->remove_at(this->attributes
, enumerator
);
135 enumerator
->destroy(enumerator
);
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
));
145 * process a single configuration attribute
147 static void process_attribute(private_mode_config_t
*this,
148 configuration_attribute_t
*ca
)
152 int family
= AF_INET6
;
154 switch (ca
->get_type(ca
))
156 case INTERNAL_IP4_ADDRESS
:
159 case INTERNAL_IP6_ADDRESS
:
161 addr
= ca
->get_chunk(ca
);
164 ip
= host_create_any(family
);
168 /* skip prefix byte in IPv6 payload*/
169 if (family
== AF_INET6
)
173 ip
= host_create_from_chunk(family
, addr
, 0);
177 this->vips
->insert_last(this->vips
, ip
);
183 if (this->initiator
== this->pull
)
185 handle_attribute(this, ca
);
192 * Check if config allows push mode when acting as task responder
194 static bool accept_push(private_mode_config_t
*this)
196 enumerator_t
*enumerator
;
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
);
206 return vip
&& !config
->use_pull_mode(config
);
210 * Scan for configuration payloads and attributes
212 static void process_payloads(private_mode_config_t
*this, message_t
*message
)
214 enumerator_t
*enumerator
, *attributes
;
217 enumerator
= message
->create_payload_enumerator(message
);
218 while (enumerator
->enumerate(enumerator
, &payload
))
220 if (payload
->get_type(payload
) == PLV1_CONFIGURATION
)
222 cp_payload_t
*cp
= (cp_payload_t
*)payload
;
223 configuration_attribute_t
*ca
;
225 switch (cp
->get_type(cp
))
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))
237 this->identifier
= cp
->get_identifier(cp
);
240 attributes
= cp
->create_attribute_enumerator(cp
);
241 while (attributes
->enumerate(attributes
, &ca
))
243 DBG2(DBG_IKE
, "processing %N attribute",
244 configuration_attribute_type_names
, ca
->get_type(ca
));
245 process_attribute(this, ca
);
247 attributes
->destroy(attributes
);
252 DBG1(DBG_IKE
, "ignoring %N config payload",
253 config_type_names
, cp
->get_type(cp
));
258 enumerator
->destroy(enumerator
);
262 * Add an attribute to a configuration payload, and store it in task
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
)
270 cp
->add_attribute(cp
,
271 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE
,
277 this->attributes
->insert_last(this->attributes
, entry
);
281 * Build a CFG_REQUEST as initiator
283 static status_t
build_request(private_mode_config_t
*this, message_t
*message
)
286 enumerator_t
*enumerator
;
287 attribute_handler_t
*handler
;
289 configuration_attribute_type_t type
;
294 cp
= cp_payload_create_type(PLV1_CONFIGURATION
, CFG_REQUEST
);
296 vips
= linked_list_create();
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
))
302 vips
->insert_last(vips
, host
);
304 enumerator
->destroy(enumerator
);
306 if (vips
->get_count(vips
) == 0)
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
))
312 vips
->insert_last(vips
, host
);
314 enumerator
->destroy(enumerator
);
317 if (vips
->get_count(vips
))
319 enumerator
= vips
->create_enumerator(vips
);
320 while (enumerator
->enumerate(enumerator
, &host
))
322 cp
->add_attribute(cp
, build_vip(host
));
324 enumerator
->destroy(enumerator
);
327 enumerator
= charon
->attributes
->create_initiator_enumerator(
328 charon
->attributes
, this->ike_sa
, vips
);
329 while (enumerator
->enumerate(enumerator
, &handler
, &type
, &data
))
331 add_attribute(this, cp
, type
, data
, handler
);
333 enumerator
->destroy(enumerator
);
337 message
->add_payload(message
, (payload_t
*)cp
);
343 * Build a CFG_SET as initiator
345 static status_t
build_set(private_mode_config_t
*this, message_t
*message
)
347 enumerator_t
*enumerator
;
348 configuration_attribute_type_t type
;
352 identification_t
*id
;
353 linked_list_t
*pools
, *migrated
, *vips
;
354 host_t
*any4
, *any6
, *found
;
357 cp
= cp_payload_create_type(PLV1_CONFIGURATION
, CFG_SET
);
359 id
= this->ike_sa
->get_other_eap_id(this->ike_sa
);
360 config
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
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
,
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
);
370 /* in push mode, we ask each configured pool for an address */
371 if (!vips
->get_count(vips
))
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
))
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
);
384 found
= charon
->attributes
->acquire_address(charon
->attributes
,
385 pools
, this->ike_sa
, any6
);
387 pools
->destroy(pools
);
390 vips
->insert_last(vips
, found
);
393 enumerator
->destroy(enumerator
);
398 enumerator
= vips
->create_enumerator(vips
);
399 while (enumerator
->enumerate(enumerator
, &found
))
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
);
407 enumerator
->destroy(enumerator
);
410 charon
->bus
->assign_vips(charon
->bus
, this->ike_sa
, TRUE
);
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
))
419 add_attribute(this, cp
, type
, value
, NULL
);
421 enumerator
->destroy(enumerator
);
422 pools
->destroy(pools
);
424 message
->add_payload(message
, (payload_t
*)cp
);
429 METHOD(task_t
, build_i
, status_t
,
430 private_mode_config_t
*this, message_t
*message
)
434 return build_request(this, message
);
436 return build_set(this, message
);
440 * Store received virtual IPs to the IKE_SA, install them
442 static void install_vips(private_mode_config_t
*this)
444 enumerator_t
*enumerator
;
447 this->ike_sa
->clear_virtual_ips(this->ike_sa
, TRUE
);
449 enumerator
= this->vips
->create_enumerator(this->vips
);
450 while (enumerator
->enumerate(enumerator
, &host
))
452 if (!host
->is_anyaddr(host
))
454 this->ike_sa
->add_virtual_ip(this->ike_sa
, TRUE
, host
);
457 enumerator
->destroy(enumerator
);
459 charon
->bus
->handle_vips(charon
->bus
, this->ike_sa
, TRUE
);
462 METHOD(task_t
, process_r
, status_t
,
463 private_mode_config_t
*this, message_t
*message
)
465 process_payloads(this, message
);
475 * Assign a migrated virtual IP
477 static host_t
*assign_migrated_vip(linked_list_t
*migrated
, host_t
*requested
)
479 enumerator_t
*enumerator
;
480 host_t
*found
= NULL
, *vip
;
482 enumerator
= migrated
->create_enumerator(migrated
);
483 while (enumerator
->enumerate(enumerator
, &vip
))
485 if (vip
->ip_equals(vip
, requested
))
487 migrated
->remove_at(migrated
, enumerator
);
492 enumerator
->destroy(enumerator
);
497 * Build CFG_REPLY message after receiving CFG_REQUEST
499 static status_t
build_reply(private_mode_config_t
*this, message_t
*message
)
501 enumerator_t
*enumerator
;
502 configuration_attribute_type_t type
;
506 identification_t
*id
;
507 linked_list_t
*vips
, *pools
, *migrated
;
508 host_t
*requested
, *found
;
510 cp
= cp_payload_create_type(PLV1_CONFIGURATION
, CFG_REPLY
);
512 id
= this->ike_sa
->get_other_eap_id(this->ike_sa
);
513 config
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
514 pools
= linked_list_create_from_enumerator(
515 config
->create_pool_enumerator(config
));
516 /* if we migrated virtual IPs during reauthentication, reassign them */
517 vips
= linked_list_create_from_enumerator(
518 this->ike_sa
->create_virtual_ip_enumerator(this->ike_sa
,
520 migrated
= vips
->clone_offset(vips
, offsetof(host_t
, clone
));
522 this->ike_sa
->clear_virtual_ips(this->ike_sa
, FALSE
);
524 vips
= linked_list_create();
525 enumerator
= this->vips
->create_enumerator(this->vips
);
526 while (enumerator
->enumerate(enumerator
, &requested
))
528 DBG1(DBG_IKE
, "peer requested virtual IP %H", requested
);
530 found
= assign_migrated_vip(migrated
, requested
);
533 found
= charon
->attributes
->acquire_address(charon
->attributes
,
534 pools
, this->ike_sa
, requested
);
538 DBG1(DBG_IKE
, "assigning virtual IP %H to peer '%Y'", found
, id
);
539 this->ike_sa
->add_virtual_ip(this->ike_sa
, FALSE
, found
);
540 cp
->add_attribute(cp
, build_vip(found
));
541 vips
->insert_last(vips
, found
);
545 DBG1(DBG_IKE
, "no virtual IP found for %H requested by '%Y'",
549 enumerator
->destroy(enumerator
);
551 charon
->bus
->assign_vips(charon
->bus
, this->ike_sa
, TRUE
);
553 /* query registered providers for additional attributes to include */
554 enumerator
= charon
->attributes
->create_responder_enumerator(
555 charon
->attributes
, pools
, this->ike_sa
, vips
);
556 while (enumerator
->enumerate(enumerator
, &type
, &value
))
558 cp
->add_attribute(cp
,
559 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE
,
562 enumerator
->destroy(enumerator
);
563 /* if a client did not re-request all adresses, release them */
564 enumerator
= migrated
->create_enumerator(migrated
);
565 while (enumerator
->enumerate(enumerator
, &found
))
567 charon
->attributes
->release_address(charon
->attributes
,
568 pools
, found
, this->ike_sa
);
570 enumerator
->destroy(enumerator
);
571 migrated
->destroy_offset(migrated
, offsetof(host_t
, destroy
));
572 vips
->destroy_offset(vips
, offsetof(host_t
, destroy
));
573 pools
->destroy(pools
);
575 cp
->set_identifier(cp
, this->identifier
);
576 message
->add_payload(message
, (payload_t
*)cp
);
582 * Build CFG_ACK for a received CFG_SET
584 static status_t
build_ack(private_mode_config_t
*this, message_t
*message
)
587 enumerator_t
*enumerator
;
589 configuration_attribute_type_t type
;
592 cp
= cp_payload_create_type(PLV1_CONFIGURATION
, CFG_ACK
);
594 /* return empty attributes for installed IPs */
596 enumerator
= this->vips
->create_enumerator(this->vips
);
597 while (enumerator
->enumerate(enumerator
, &host
))
599 type
= INTERNAL_IP6_ADDRESS
;
600 if (host
->get_family(host
) == AF_INET6
)
602 type
= INTERNAL_IP6_ADDRESS
;
606 type
= INTERNAL_IP4_ADDRESS
;
608 cp
->add_attribute(cp
, configuration_attribute_create_chunk(
609 PLV1_CONFIGURATION_ATTRIBUTE
, type
, chunk_empty
));
611 enumerator
->destroy(enumerator
);
613 enumerator
= this->attributes
->create_enumerator(this->attributes
);
614 while (enumerator
->enumerate(enumerator
, &entry
))
616 cp
->add_attribute(cp
,
617 configuration_attribute_create_chunk(PLV1_CONFIGURATION_ATTRIBUTE
,
618 entry
->type
, chunk_empty
));
620 enumerator
->destroy(enumerator
);
622 cp
->set_identifier(cp
, this->identifier
);
623 message
->add_payload(message
, (payload_t
*)cp
);
628 METHOD(task_t
, build_r
, status_t
,
629 private_mode_config_t
*this, message_t
*message
)
633 return build_reply(this, message
);
635 return build_ack(this, message
);
638 METHOD(task_t
, process_i
, status_t
,
639 private_mode_config_t
*this, message_t
*message
)
641 process_payloads(this, message
);
650 METHOD(task_t
, get_type
, task_type_t
,
651 private_mode_config_t
*this)
653 return TASK_MODE_CONFIG
;
656 METHOD(task_t
, migrate
, void,
657 private_mode_config_t
*this, ike_sa_t
*ike_sa
)
659 this->ike_sa
= ike_sa
;
660 this->vips
->destroy_offset(this->vips
, offsetof(host_t
, destroy
));
661 this->vips
= linked_list_create();
662 this->attributes
->destroy_function(this->attributes
, free
);
663 this->attributes
= linked_list_create();
666 METHOD(task_t
, destroy
, void,
667 private_mode_config_t
*this)
669 this->vips
->destroy_offset(this->vips
, offsetof(host_t
, destroy
));
670 this->attributes
->destroy_function(this->attributes
, free
);
675 * Described in header.
677 mode_config_t
*mode_config_create(ike_sa_t
*ike_sa
, bool initiator
, bool pull
)
679 private_mode_config_t
*this;
684 .get_type
= _get_type
,
689 .initiator
= initiator
,
690 .pull
= initiator ? pull
: TRUE
,
692 .attributes
= linked_list_create(),
693 .vips
= linked_list_create(),
698 this->public.task
.build
= _build_i
;
699 this->public.task
.process
= _process_i
;
703 this->public.task
.build
= _build_r
;
704 this->public.task
.process
= _process_r
;
707 return &this->public;