attribute_manager supports attribute_handler's to handle configuration attributes...
[strongswan.git] / src / charon / 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 * $Id$
17 */
18
19 #include "ike_config.h"
20
21 #include <daemon.h>
22 #include <encoding/payloads/cp_payload.h>
23
24 #define DNS_SERVER_MAX 2
25 #define NBNS_SERVER_MAX 2
26
27 typedef struct private_ike_config_t private_ike_config_t;
28
29 /**
30 * Private members of a ike_config_t task.
31 */
32 struct private_ike_config_t {
33
34 /**
35 * Public methods and task_t interface.
36 */
37 ike_config_t public;
38
39 /**
40 * Assigned IKE_SA.
41 */
42 ike_sa_t *ike_sa;
43
44 /**
45 * Are we the initiator?
46 */
47 bool initiator;
48
49 /**
50 * virtual ip
51 */
52 host_t *virtual_ip;
53 };
54
55 /**
56 * build INTERNAL_IPV4/6_ADDRESS from virtual ip
57 */
58 static void build_vip(private_ike_config_t *this, host_t *vip, cp_payload_t *cp)
59 {
60 configuration_attribute_t *ca;
61 chunk_t chunk, prefix;
62
63 ca = configuration_attribute_create();
64
65 if (vip->get_family(vip) == AF_INET)
66 {
67 ca->set_type(ca, INTERNAL_IP4_ADDRESS);
68 if (vip->is_anyaddr(vip))
69 {
70 chunk = chunk_empty;
71 }
72 else
73 {
74 chunk = vip->get_address(vip);
75 }
76 }
77 else
78 {
79 ca->set_type(ca, INTERNAL_IP6_ADDRESS);
80 if (vip->is_anyaddr(vip))
81 {
82 chunk = chunk_empty;
83 }
84 else
85 {
86 prefix = chunk_alloca(1);
87 *prefix.ptr = 64;
88 chunk = vip->get_address(vip);
89 chunk = chunk_cata("cc", chunk, prefix);
90 }
91 }
92 ca->set_value(ca, chunk);
93 cp->add_configuration_attribute(cp, ca);
94 }
95
96 /**
97 * process a single configuration attribute
98 */
99 static void process_attribute(private_ike_config_t *this,
100 configuration_attribute_t *ca)
101 {
102 host_t *ip;
103 chunk_t addr;
104 int family = AF_INET6;
105
106 switch (ca->get_type(ca))
107 {
108 case INTERNAL_IP4_ADDRESS:
109 family = AF_INET;
110 /* fall */
111 case INTERNAL_IP6_ADDRESS:
112 {
113 addr = ca->get_value(ca);
114 if (addr.len == 0)
115 {
116 ip = host_create_any(family);
117 }
118 else
119 {
120 /* skip prefix byte in IPv6 payload*/
121 if (family == AF_INET6)
122 {
123 addr.len--;
124 }
125 ip = host_create_from_chunk(family, addr, 0);
126 }
127 if (ip)
128 {
129 DESTROY_IF(this->virtual_ip);
130 this->virtual_ip = ip;
131 }
132 break;
133 }
134 default:
135 if (this->initiator)
136 {
137 this->ike_sa->add_configuration_attribute(this->ike_sa,
138 ca->get_type(ca), ca->get_value(ca));
139 }
140 else
141 {
142 /* we do not handle attribute requests other than for VIPs */
143 }
144 }
145 }
146
147 /**
148 * Scan for configuration payloads and attributes
149 */
150 static void process_payloads(private_ike_config_t *this, message_t *message)
151 {
152 enumerator_t *enumerator;
153 iterator_t *attributes;
154 payload_t *payload;
155
156 enumerator = message->create_payload_enumerator(message);
157 while (enumerator->enumerate(enumerator, &payload))
158 {
159 if (payload->get_type(payload) == CONFIGURATION)
160 {
161 cp_payload_t *cp = (cp_payload_t*)payload;
162 configuration_attribute_t *ca;
163 switch (cp->get_config_type(cp))
164 {
165 case CFG_REQUEST:
166 case CFG_REPLY:
167 {
168 attributes = cp->create_attribute_iterator(cp);
169 while (attributes->iterate(attributes, (void**)&ca))
170 {
171 process_attribute(this, ca);
172 }
173 attributes->destroy(attributes);
174 break;
175 }
176 default:
177 DBG1(DBG_IKE, "ignoring %N config payload",
178 config_type_names, cp->get_config_type(cp));
179 break;
180 }
181 }
182 }
183 enumerator->destroy(enumerator);
184 }
185
186 /**
187 * Implementation of task_t.process for initiator
188 */
189 static status_t build_i(private_ike_config_t *this, message_t *message)
190 {
191 if (message->get_message_id(message) == 1)
192 { /* in first IKE_AUTH only */
193 peer_cfg_t *config;
194 host_t *vip;
195
196 /* reuse virtual IP if we already have one */
197 vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
198 if (!vip)
199 {
200 config = this->ike_sa->get_peer_cfg(this->ike_sa);
201 vip = config->get_virtual_ip(config);
202 }
203 if (vip)
204 {
205 configuration_attribute_t *ca;
206 cp_payload_t *cp;
207
208 cp = cp_payload_create();
209 cp->set_config_type(cp, CFG_REQUEST);
210
211 build_vip(this, vip, cp);
212
213 /* we currently always add a DNS request if we request an IP */
214 ca = configuration_attribute_create();
215 if (vip->get_family(vip) == AF_INET)
216 {
217 ca->set_type(ca, INTERNAL_IP4_DNS);
218 }
219 else
220 {
221 ca->set_type(ca, INTERNAL_IP6_DNS);
222 }
223 cp->add_configuration_attribute(cp, ca);
224 message->add_payload(message, (payload_t*)cp);
225 }
226 }
227 return NEED_MORE;
228 }
229
230 /**
231 * Implementation of task_t.process for responder
232 */
233 static status_t process_r(private_ike_config_t *this, message_t *message)
234 {
235 if (message->get_message_id(message) == 1)
236 { /* in first IKE_AUTH only */
237 process_payloads(this, message);
238 }
239 return NEED_MORE;
240 }
241
242 /**
243 * Implementation of task_t.build for responder
244 */
245 static status_t build_r(private_ike_config_t *this, message_t *message)
246 {
247 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
248 { /* in last IKE_AUTH exchange */
249 peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa);
250
251 if (config && this->virtual_ip)
252 {
253 enumerator_t *enumerator;
254 configuration_attribute_type_t type;
255 configuration_attribute_t *ca;
256 chunk_t value;
257 cp_payload_t *cp;
258 host_t *vip = NULL;
259
260 DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
261 if (config->get_pool(config))
262 {
263 vip = charon->attributes->acquire_address(charon->attributes,
264 config->get_pool(config),
265 this->ike_sa->get_other_id(this->ike_sa),
266 this->virtual_ip);
267 }
268 if (vip == NULL)
269 {
270 DBG1(DBG_IKE, "no virtual IP found, sending %N",
271 notify_type_names, INTERNAL_ADDRESS_FAILURE);
272 message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
273 chunk_empty);
274 return SUCCESS;
275 }
276 DBG1(DBG_IKE, "assigning virtual IP %H to peer", vip);
277 this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
278
279 cp = cp_payload_create();
280 cp->set_config_type(cp, CFG_REQUEST);
281
282 build_vip(this, vip, cp);
283
284 /* if we add an IP, we also look for other attributes */
285 enumerator = charon->attributes->create_attribute_enumerator(
286 charon->attributes, this->ike_sa->get_other_id(this->ike_sa));
287 while (enumerator->enumerate(enumerator, &type, &value))
288 {
289 ca = configuration_attribute_create();
290 ca->set_type(ca, type);
291 ca->set_value(ca, value);
292 cp->add_configuration_attribute(cp, ca);
293 }
294 enumerator->destroy(enumerator);
295
296 message->add_payload(message, (payload_t*)cp);
297 }
298 return SUCCESS;
299 }
300 return NEED_MORE;
301 }
302
303 /**
304 * Implementation of task_t.process for initiator
305 */
306 static status_t process_i(private_ike_config_t *this, message_t *message)
307 {
308 if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
309 { /* in last IKE_AUTH exchange */
310
311 process_payloads(this, message);
312
313 if (this->virtual_ip)
314 {
315 this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
316 }
317 return SUCCESS;
318 }
319 return NEED_MORE;
320 }
321
322 /**
323 * Implementation of task_t.get_type
324 */
325 static task_type_t get_type(private_ike_config_t *this)
326 {
327 return IKE_CONFIG;
328 }
329
330 /**
331 * Implementation of task_t.migrate
332 */
333 static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
334 {
335 DESTROY_IF(this->virtual_ip);
336
337 this->ike_sa = ike_sa;
338 this->virtual_ip = NULL;
339 }
340
341 /**
342 * Implementation of task_t.destroy
343 */
344 static void destroy(private_ike_config_t *this)
345 {
346 DESTROY_IF(this->virtual_ip);
347 free(this);
348 }
349
350 /*
351 * Described in header.
352 */
353 ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
354 {
355 private_ike_config_t *this = malloc_thing(private_ike_config_t);
356
357 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
358 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
359 this->public.task.destroy = (void(*)(task_t*))destroy;
360
361 this->initiator = initiator;
362 this->ike_sa = ike_sa;
363 this->virtual_ip = NULL;
364
365 if (initiator)
366 {
367 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
368 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
369 }
370 else
371 {
372 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
373 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
374 }
375
376 return &this->public;
377 }
378