6bfab8c85c41b6700bcc141903d4252d0638a6a3
[strongswan.git] / src / charon / sa / tasks / ike_config.c
1 /**
2 * @file ike_config.c
3 *
4 * @brief Implementation of the ike_config task.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include "ike_config.h"
25
26 #include <daemon.h>
27 #include <encoding/payloads/cp_payload.h>
28
29 typedef struct private_ike_config_t private_ike_config_t;
30
31 /**
32 * Private members of a ike_config_t task.
33 */
34 struct private_ike_config_t {
35
36 /**
37 * Public methods and task_t interface.
38 */
39 ike_config_t public;
40
41 /**
42 * Assigned IKE_SA.
43 */
44 ike_sa_t *ike_sa;
45
46 /**
47 * Are we the initiator?
48 */
49 bool initiator;
50
51 /**
52 * virtual ip
53 */
54 host_t *virtual_ip;
55
56 /**
57 * list of DNS servers
58 */
59 linked_list_t *dns;
60 };
61
62 /**
63 * build configuration payloads and attributes
64 */
65 static void build_payloads(private_ike_config_t *this, message_t *message,
66 config_type_t type)
67 {
68 cp_payload_t *cp;
69 configuration_attribute_t *ca;
70 chunk_t chunk, prefix;
71
72 if (!this->virtual_ip)
73 {
74 return;
75 }
76
77 cp = cp_payload_create();
78 cp->set_config_type(cp, type);
79
80 ca = configuration_attribute_create();
81
82 if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
83 {
84 ca->set_type(ca, INTERNAL_IP4_ADDRESS);
85 if (this->virtual_ip->is_anyaddr(this->virtual_ip))
86 {
87 chunk = chunk_empty;
88 }
89 else
90 {
91 chunk = this->virtual_ip->get_address(this->virtual_ip);
92 }
93 }
94 else
95 {
96 ca->set_type(ca, INTERNAL_IP6_ADDRESS);
97 if (this->virtual_ip->is_anyaddr(this->virtual_ip))
98 {
99 chunk = chunk_empty;
100 }
101 else
102 {
103 prefix = chunk_alloca(1);
104 *prefix.ptr = 64;
105 chunk = this->virtual_ip->get_address(this->virtual_ip);
106 chunk = chunk_cata("cc", chunk, prefix);
107 }
108 }
109 ca->set_value(ca, chunk);
110 cp->add_configuration_attribute(cp, ca);
111
112 /* we currently always add a DNS request if we request an IP */
113 if (this->initiator)
114 {
115 ca = configuration_attribute_create();
116 if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
117 {
118 ca->set_type(ca, INTERNAL_IP4_DNS);
119 }
120 else
121 {
122 ca->set_type(ca, INTERNAL_IP6_DNS);
123 }
124 cp->add_configuration_attribute(cp, ca);
125 }
126 else
127 {
128 host_t *ip;
129 iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
130 while (iterator->iterate(iterator, (void**)&ip))
131 {
132 ca = configuration_attribute_create();
133 if (ip->get_family(ip) == AF_INET)
134 {
135 ca->set_type(ca, INTERNAL_IP4_DNS);
136 }
137 else
138 {
139 ca->set_type(ca, INTERNAL_IP6_DNS);
140 }
141 chunk = ip->get_address(ip);
142 ca->set_value(ca, chunk);
143 cp->add_configuration_attribute(cp, ca);
144 }
145 iterator->destroy(iterator);
146 }
147 message->add_payload(message, (payload_t*)cp);
148 }
149
150 /**
151 * process a single configuration attribute
152 */
153 static void process_attribute(private_ike_config_t *this,
154 configuration_attribute_t *ca)
155 {
156 host_t *ip;
157 chunk_t addr;
158 int family = AF_INET6;
159
160 switch (ca->get_type(ca))
161 {
162 case INTERNAL_IP4_ADDRESS:
163 family = AF_INET;
164 /* fall */
165 case INTERNAL_IP6_ADDRESS:
166 {
167 addr = ca->get_value(ca);
168 if (addr.len == 0)
169 {
170 ip = host_create_any(family);
171 }
172 else
173 {
174 /* skip prefix byte in IPv6 payload*/
175 if (family == AF_INET6)
176 {
177 addr.len--;
178 }
179 ip = host_create_from_chunk(family, addr, 0);
180 }
181 if (ip && !this->virtual_ip)
182 {
183 this->virtual_ip = ip;
184 }
185 break;
186 }
187 case INTERNAL_IP4_DNS:
188 family = AF_INET;
189 /* fall */
190 case INTERNAL_IP6_DNS:
191 {
192 addr = ca->get_value(ca);
193 if (addr.len == 0)
194 {
195 ip = host_create_any(family);
196 }
197 else
198 {
199 ip = host_create_from_chunk(family, addr, 0);
200 }
201 if (ip)
202 {
203 this->dns->insert_last(this->dns, ip);
204 }
205 break;
206 }
207 case INTERNAL_IP4_NBNS:
208 case INTERNAL_IP6_NBNS:
209 /* TODO */
210 default:
211 DBG1(DBG_IKE, "ignoring %N config attribute",
212 configuration_attribute_type_names,
213 ca->get_type(ca));
214 break;
215 }
216 }
217
218 /**
219 * Scan for configuration payloads and attributes
220 */
221 static void process_payloads(private_ike_config_t *this, message_t *message)
222 {
223 iterator_t *iterator, *attributes;
224 payload_t *payload;
225
226 iterator = message->get_payload_iterator(message);
227 while (iterator->iterate(iterator, (void**)&payload))
228 {
229 if (payload->get_type(payload) == CONFIGURATION)
230 {
231 cp_payload_t *cp = (cp_payload_t*)payload;
232 configuration_attribute_t *ca;
233 switch (cp->get_config_type(cp))
234 {
235 case CFG_REQUEST:
236 case CFG_REPLY:
237 {
238 attributes = cp->create_attribute_iterator(cp);
239 while (attributes->iterate(attributes, (void**)&ca))
240 {
241 process_attribute(this, ca);
242 }
243 attributes->destroy(attributes);
244 break;
245 }
246 default:
247 DBG1(DBG_IKE, "ignoring %N config payload",
248 config_type_names, cp->get_config_type(cp));
249 break;
250 }
251 }
252 }
253 iterator->destroy(iterator);
254 }
255
256 /**
257 * Implementation of task_t.process for initiator
258 */
259 static status_t build_i(private_ike_config_t *this, message_t *message)
260 {
261 if (message->get_exchange_type(message) == IKE_AUTH &&
262 message->get_payload(message, ID_INITIATOR))
263 {
264 peer_cfg_t *config;
265 host_t *vip;
266
267 /* reuse virtual IP if we already have one */
268 vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
269 if (vip)
270 {
271 this->virtual_ip = vip->clone(vip);
272 }
273 else
274 {
275 config = this->ike_sa->get_peer_cfg(this->ike_sa);
276 this->virtual_ip = config->get_virtual_ip(config, NULL);
277 }
278
279 build_payloads(this, message, CFG_REQUEST);
280 }
281
282 return NEED_MORE;
283 }
284
285 /**
286 * Implementation of task_t.process for responder
287 */
288 static status_t process_r(private_ike_config_t *this, message_t *message)
289 {
290 if (message->get_exchange_type(message) == IKE_AUTH &&
291 message->get_payload(message, ID_INITIATOR))
292 {
293 process_payloads(this, message);
294 }
295 return NEED_MORE;
296 }
297
298 /**
299 * Implementation of task_t.build for responder
300 */
301 static status_t build_r(private_ike_config_t *this, message_t *message)
302 {
303 if (message->get_exchange_type(message) == IKE_AUTH &&
304 message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL)
305 {
306 peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa);
307
308 if (config && this->virtual_ip)
309 {
310 host_t *ip;
311
312 DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
313 ip = config->get_virtual_ip(config, this->virtual_ip);
314 if (ip == NULL || ip->is_anyaddr(ip))
315 {
316 DBG1(DBG_IKE, "not assigning a virtual IP to peer");
317 DESTROY_IF(ip);
318 return SUCCESS;
319 }
320 DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
321 this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
322
323 this->virtual_ip->destroy(this->virtual_ip);
324 this->virtual_ip = ip;
325
326 /* DNS testing values
327 if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
328 {
329 ip->destroy(ip);
330 ip = host_create_from_string("10.3.0.1", 0);
331 this->dns->insert_last(this->dns, ip);
332 ip = host_create_from_string("10.3.0.2", 0);
333 this->dns->insert_last(this->dns, ip);
334 } */
335
336 build_payloads(this, message, CFG_REPLY);
337 }
338 return SUCCESS;
339 }
340 return NEED_MORE;
341 }
342
343 /**
344 * Implementation of task_t.process for initiator
345 */
346 static status_t process_i(private_ike_config_t *this, message_t *message)
347 {
348 if (message->get_exchange_type(message) == IKE_AUTH &&
349 !message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
350 {
351 host_t *ip;
352
353 DESTROY_IF(this->virtual_ip);
354 this->virtual_ip = NULL;
355
356 process_payloads(this, message);
357
358 if (this->virtual_ip)
359 {
360 this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
361
362 while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
363 {
364 if (!ip->is_anyaddr(ip))
365 {
366 this->ike_sa->add_dns_server(this->ike_sa, ip);
367 }
368 ip->destroy(ip);
369 }
370 }
371 return SUCCESS;
372 }
373 return NEED_MORE;
374 }
375
376 /**
377 * Implementation of task_t.get_type
378 */
379 static task_type_t get_type(private_ike_config_t *this)
380 {
381 return IKE_CONFIG;
382 }
383
384 /**
385 * Implementation of task_t.migrate
386 */
387 static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
388 {
389 DESTROY_IF(this->virtual_ip);
390 this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
391
392 this->ike_sa = ike_sa;
393 this->virtual_ip = NULL;
394 this->dns = linked_list_create();
395 }
396
397 /**
398 * Implementation of task_t.destroy
399 */
400 static void destroy(private_ike_config_t *this)
401 {
402 DESTROY_IF(this->virtual_ip);
403 this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
404 free(this);
405 }
406
407 /*
408 * Described in header.
409 */
410 ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
411 {
412 private_ike_config_t *this = malloc_thing(private_ike_config_t);
413
414 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
415 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
416 this->public.task.destroy = (void(*)(task_t*))destroy;
417
418 if (initiator)
419 {
420 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
421 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
422 }
423 else
424 {
425 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
426 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
427 }
428 this->initiator = initiator;
429 this->ike_sa = ike_sa;
430 this->virtual_ip = NULL;
431 this->dns = linked_list_create();
432
433 return &this->public;
434 }