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"
20 #include <encoding/payloads/cp_payload.h>
22 typedef struct private_mode_config_t private_mode_config_t
;
25 * Private members of a mode_config_t task.
27 struct private_mode_config_t
{
30 * Public methods and task_t interface.
40 * Are we the initiator?
45 * Received list of virtual IPs, host_t*
50 * list of attributes requested and its handler, entry_t
52 linked_list_t
*requested
;
55 * Identifier to include in response
61 * Entry for a requested attribute and the requesting handler
64 /** attribute requested */
65 configuration_attribute_type_t type
;
66 /** handler requesting this attribute */
67 attribute_handler_t
*handler
;
71 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
73 static configuration_attribute_t
*build_vip(host_t
*vip
)
75 configuration_attribute_type_t type
;
76 chunk_t chunk
, prefix
;
78 if (vip
->get_family(vip
) == AF_INET
)
80 type
= INTERNAL_IP4_ADDRESS
;
81 if (vip
->is_anyaddr(vip
))
87 chunk
= vip
->get_address(vip
);
92 type
= INTERNAL_IP6_ADDRESS
;
93 if (vip
->is_anyaddr(vip
))
99 prefix
= chunk_alloca(1);
101 chunk
= vip
->get_address(vip
);
102 chunk
= chunk_cata("cc", chunk
, prefix
);
105 return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1
,
110 * Handle a received attribute as initiator
112 static void handle_attribute(private_mode_config_t
*this,
113 configuration_attribute_t
*ca
)
115 attribute_handler_t
*handler
= NULL
;
116 enumerator_t
*enumerator
;
119 /* find the handler which requested this attribute */
120 enumerator
= this->requested
->create_enumerator(this->requested
);
121 while (enumerator
->enumerate(enumerator
, &entry
))
123 if (entry
->type
== ca
->get_type(ca
))
125 handler
= entry
->handler
;
126 this->requested
->remove_at(this->requested
, enumerator
);
131 enumerator
->destroy(enumerator
);
133 /* and pass it to the handle function */
134 handler
= hydra
->attributes
->handle(hydra
->attributes
,
135 this->ike_sa
->get_other_id(this->ike_sa
), handler
,
136 ca
->get_type(ca
), ca
->get_chunk(ca
));
139 this->ike_sa
->add_configuration_attribute(this->ike_sa
,
140 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
);
185 handle_attribute(this, ca
);
192 * Scan for configuration payloads and attributes
194 static void process_payloads(private_mode_config_t
*this, message_t
*message
)
196 enumerator_t
*enumerator
, *attributes
;
199 enumerator
= message
->create_payload_enumerator(message
);
200 while (enumerator
->enumerate(enumerator
, &payload
))
202 if (payload
->get_type(payload
) == CONFIGURATION_V1
)
204 cp_payload_t
*cp
= (cp_payload_t
*)payload
;
205 configuration_attribute_t
*ca
;
207 switch (cp
->get_type(cp
))
210 this->identifier
= cp
->get_identifier(cp
);
213 attributes
= cp
->create_attribute_enumerator(cp
);
214 while (attributes
->enumerate(attributes
, &ca
))
216 DBG2(DBG_IKE
, "processing %N attribute",
217 configuration_attribute_type_names
, ca
->get_type(ca
));
218 process_attribute(this, ca
);
220 attributes
->destroy(attributes
);
223 DBG1(DBG_IKE
, "ignoring %N config payload",
224 config_type_names
, cp
->get_type(cp
));
229 enumerator
->destroy(enumerator
);
232 METHOD(task_t
, build_i
, status_t
,
233 private_mode_config_t
*this, message_t
*message
)
236 enumerator_t
*enumerator
;
237 attribute_handler_t
*handler
;
239 configuration_attribute_type_t type
;
244 cp
= cp_payload_create_type(CONFIGURATION_V1
, CFG_REQUEST
);
246 vips
= linked_list_create();
248 /* reuse virtual IP if we already have one */
249 enumerator
= this->ike_sa
->create_virtual_ip_enumerator(this->ike_sa
, TRUE
);
250 while (enumerator
->enumerate(enumerator
, &host
))
252 vips
->insert_last(vips
, host
);
254 enumerator
->destroy(enumerator
);
256 if (vips
->get_count(vips
) == 0)
258 config
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
259 enumerator
= config
->create_virtual_ip_enumerator(config
);
260 while (enumerator
->enumerate(enumerator
, &host
))
262 vips
->insert_last(vips
, host
);
264 enumerator
->destroy(enumerator
);
267 if (vips
->get_count(vips
))
269 enumerator
= vips
->create_enumerator(vips
);
270 while (enumerator
->enumerate(enumerator
, &host
))
272 cp
->add_attribute(cp
, build_vip(host
));
274 enumerator
->destroy(enumerator
);
277 enumerator
= hydra
->attributes
->create_initiator_enumerator(
279 this->ike_sa
->get_other_id(this->ike_sa
), vips
);
280 while (enumerator
->enumerate(enumerator
, &handler
, &type
, &data
))
284 DBG2(DBG_IKE
, "building %N attribute",
285 configuration_attribute_type_names
, type
);
286 cp
->add_attribute(cp
,
287 configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1
,
293 this->requested
->insert_last(this->requested
, entry
);
295 enumerator
->destroy(enumerator
);
299 message
->add_payload(message
, (payload_t
*)cp
);
304 METHOD(task_t
, process_r
, status_t
,
305 private_mode_config_t
*this, message_t
*message
)
307 process_payloads(this, message
);
311 METHOD(task_t
, build_r
, status_t
,
312 private_mode_config_t
*this, message_t
*message
)
314 enumerator_t
*enumerator
;
315 configuration_attribute_type_t type
;
319 identification_t
*id
;
320 linked_list_t
*vips
, *pools
;
323 cp
= cp_payload_create_type(CONFIGURATION_V1
, CFG_REPLY
);
325 id
= this->ike_sa
->get_other_eap_id(this->ike_sa
);
326 config
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
327 vips
= linked_list_create();
328 pools
= linked_list_create_from_enumerator(
329 config
->create_pool_enumerator(config
));
331 this->ike_sa
->clear_virtual_ips(this->ike_sa
, FALSE
);
333 enumerator
= this->vips
->create_enumerator(this->vips
);
334 while (enumerator
->enumerate(enumerator
, &requested
))
336 host_t
*found
= NULL
;
338 /* query all pools until we get an address */
339 DBG1(DBG_IKE
, "peer requested virtual IP %H", requested
);
341 found
= hydra
->attributes
->acquire_address(hydra
->attributes
,
342 pools
, id
, requested
);
345 DBG1(DBG_IKE
, "assigning virtual IP %H to peer '%Y'", found
, id
);
346 this->ike_sa
->add_virtual_ip(this->ike_sa
, FALSE
, found
);
347 cp
->add_attribute(cp
, build_vip(found
));
348 vips
->insert_last(vips
, found
);
352 DBG1(DBG_IKE
, "no virtual IP found for %H requested by '%Y'",
356 enumerator
->destroy(enumerator
);
358 /* query registered providers for additional attributes to include */
359 enumerator
= hydra
->attributes
->create_responder_enumerator(
360 hydra
->attributes
, pools
, id
, vips
);
361 while (enumerator
->enumerate(enumerator
, &type
, &value
))
363 DBG2(DBG_IKE
, "building %N attribute",
364 configuration_attribute_type_names
, type
);
365 cp
->add_attribute(cp
,
366 configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1
,
369 enumerator
->destroy(enumerator
);
370 vips
->destroy_offset(vips
, offsetof(host_t
, destroy
));
371 pools
->destroy(pools
);
373 cp
->set_identifier(cp
, this->identifier
);
374 message
->add_payload(message
, (payload_t
*)cp
);
379 METHOD(task_t
, process_i
, status_t
,
380 private_mode_config_t
*this, message_t
*message
)
382 enumerator_t
*enumerator
;
385 process_payloads(this, message
);
387 this->ike_sa
->clear_virtual_ips(this->ike_sa
, TRUE
);
389 enumerator
= this->vips
->create_enumerator(this->vips
);
390 while (enumerator
->enumerate(enumerator
, &host
))
392 if (!host
->is_anyaddr(host
))
394 this->ike_sa
->add_virtual_ip(this->ike_sa
, TRUE
, host
);
397 enumerator
->destroy(enumerator
);
402 METHOD(task_t
, get_type
, task_type_t
,
403 private_mode_config_t
*this)
405 return TASK_MODE_CONFIG
;
408 METHOD(task_t
, migrate
, void,
409 private_mode_config_t
*this, ike_sa_t
*ike_sa
)
411 this->ike_sa
= ike_sa
;
412 this->vips
->destroy_offset(this->vips
, offsetof(host_t
, destroy
));
413 this->vips
= linked_list_create();
414 this->requested
->destroy_function(this->requested
, free
);
415 this->requested
= linked_list_create();
418 METHOD(task_t
, destroy
, void,
419 private_mode_config_t
*this)
421 this->vips
->destroy_offset(this->vips
, offsetof(host_t
, destroy
));
422 this->requested
->destroy_function(this->requested
, free
);
427 * Described in header.
429 mode_config_t
*mode_config_create(ike_sa_t
*ike_sa
, bool initiator
)
431 private_mode_config_t
*this;
436 .get_type
= _get_type
,
441 .initiator
= initiator
,
443 .requested
= linked_list_create(),
444 .vips
= linked_list_create(),
449 this->public.task
.build
= _build_i
;
450 this->public.task
.process
= _process_i
;
454 this->public.task
.build
= _build_r
;
455 this->public.task
.process
= _process_r
;
458 return &this->public;