Separated libcharon/sa directory with ikev1 and ikev2 subfolders
[strongswan.git] / src / libcharon / sa / ikev2 / tasks / ike_mobike.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 "ike_mobike.h"
17
18 #include <string.h>
19
20 #include <hydra.h>
21 #include <daemon.h>
22 #include <sa/ikev2/tasks/ike_natd.h>
23 #include <encoding/payloads/notify_payload.h>
24
25 #define COOKIE2_SIZE 16
26 #define MAX_ADDITIONAL_ADDRS 8
27
28 typedef struct private_ike_mobike_t private_ike_mobike_t;
29
30 /**
31 * Private members of a ike_mobike_t task.
32 */
33 struct private_ike_mobike_t {
34
35 /**
36 * Public methods and task_t interface.
37 */
38 ike_mobike_t public;
39
40 /**
41 * Assigned IKE_SA.
42 */
43 ike_sa_t *ike_sa;
44
45 /**
46 * Are we the initiator?
47 */
48 bool initiator;
49
50 /**
51 * cookie2 value to verify new addresses
52 */
53 chunk_t cookie2;
54
55 /**
56 * NAT discovery reusing the TASK_IKE_NATD task
57 */
58 ike_natd_t *natd;
59
60 /**
61 * use task to update addresses
62 */
63 bool update;
64
65 /**
66 * do routability check
67 */
68 bool check;
69
70 /**
71 * include address list update
72 */
73 bool address;
74
75 /**
76 * additional addresses got updated
77 */
78 bool addresses_updated;
79 };
80
81 /**
82 * read notifys from message and evaluate them
83 */
84 static void process_payloads(private_ike_mobike_t *this, message_t *message)
85 {
86 enumerator_t *enumerator;
87 payload_t *payload;
88 bool first = TRUE;
89
90 enumerator = message->create_payload_enumerator(message);
91 while (enumerator->enumerate(enumerator, &payload))
92 {
93 int family = AF_INET;
94 notify_payload_t *notify;
95 chunk_t data;
96 host_t *host;
97
98 if (payload->get_type(payload) != NOTIFY)
99 {
100 continue;
101 }
102 notify = (notify_payload_t*)payload;
103 switch (notify->get_notify_type(notify))
104 {
105 case MOBIKE_SUPPORTED:
106 {
107 peer_cfg_t *peer_cfg;
108
109 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
110 if (!this->initiator &&
111 peer_cfg && !peer_cfg->use_mobike(peer_cfg))
112 {
113 DBG1(DBG_IKE, "peer supports MOBIKE, but disabled in config");
114 }
115 else
116 {
117 DBG1(DBG_IKE, "peer supports MOBIKE");
118 this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE);
119 }
120 break;
121 }
122 case COOKIE2:
123 {
124 chunk_free(&this->cookie2);
125 this->cookie2 = chunk_clone(notify->get_notification_data(notify));
126 break;
127 }
128 case ADDITIONAL_IP6_ADDRESS:
129 {
130 family = AF_INET6;
131 /* fall through */
132 }
133 case ADDITIONAL_IP4_ADDRESS:
134 {
135 if (first)
136 { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
137 this->ike_sa->remove_additional_addresses(this->ike_sa);
138 first = FALSE;
139 }
140 data = notify->get_notification_data(notify);
141 host = host_create_from_chunk(family, data, 0);
142 DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host);
143 this->ike_sa->add_additional_address(this->ike_sa, host);
144 this->addresses_updated = TRUE;
145 break;
146 }
147 case UPDATE_SA_ADDRESSES:
148 {
149 this->update = TRUE;
150 break;
151 }
152 case NO_ADDITIONAL_ADDRESSES:
153 {
154 this->ike_sa->remove_additional_addresses(this->ike_sa);
155 this->addresses_updated = TRUE;
156 break;
157 }
158 case NAT_DETECTION_SOURCE_IP:
159 case NAT_DETECTION_DESTINATION_IP:
160 {
161 /* NAT check in this MOBIKE exchange, create subtask for it */
162 if (this->natd == NULL)
163 {
164 this->natd = ike_natd_create(this->ike_sa, this->initiator);
165 }
166 break;
167 }
168 default:
169 break;
170 }
171 }
172 enumerator->destroy(enumerator);
173 }
174
175 /**
176 * Add ADDITIONAL_*_ADDRESS notifys depending on our address list
177 */
178 static void build_address_list(private_ike_mobike_t *this, message_t *message)
179 {
180 enumerator_t *enumerator;
181 host_t *host, *me;
182 notify_type_t type;
183 int added = 0;
184
185 me = this->ike_sa->get_my_host(this->ike_sa);
186 enumerator = hydra->kernel_interface->create_address_enumerator(
187 hydra->kernel_interface, FALSE, FALSE);
188 while (enumerator->enumerate(enumerator, (void**)&host))
189 {
190 if (me->ip_equals(me, host))
191 { /* "ADDITIONAL" means do not include IKE_SAs host */
192 continue;
193 }
194 switch (host->get_family(host))
195 {
196 case AF_INET:
197 type = ADDITIONAL_IP4_ADDRESS;
198 break;
199 case AF_INET6:
200 type = ADDITIONAL_IP6_ADDRESS;
201 break;
202 default:
203 continue;
204 }
205 message->add_notify(message, FALSE, type, host->get_address(host));
206 if (++added >= MAX_ADDITIONAL_ADDRS)
207 { /* limit number of notifys, some implementations do not like too
208 * many of them (f.e. strongSwan ;-) */
209 break;
210 }
211 }
212 if (!added)
213 {
214 message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty);
215 }
216 enumerator->destroy(enumerator);
217 }
218
219 /**
220 * build a cookie and add it to the message
221 */
222 static void build_cookie(private_ike_mobike_t *this, message_t *message)
223 {
224 rng_t *rng;
225
226 chunk_free(&this->cookie2);
227 rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
228 if (rng)
229 {
230 rng->allocate_bytes(rng, COOKIE2_SIZE, &this->cookie2);
231 rng->destroy(rng);
232 message->add_notify(message, FALSE, COOKIE2, this->cookie2);
233 }
234 }
235
236 /**
237 * update addresses of associated CHILD_SAs
238 */
239 static void update_children(private_ike_mobike_t *this)
240 {
241 enumerator_t *enumerator;
242 child_sa_t *child_sa;
243
244 enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
245 while (enumerator->enumerate(enumerator, (void**)&child_sa))
246 {
247 if (child_sa->update(child_sa,
248 this->ike_sa->get_my_host(this->ike_sa),
249 this->ike_sa->get_other_host(this->ike_sa),
250 this->ike_sa->get_virtual_ip(this->ike_sa, TRUE),
251 this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
252 {
253 this->ike_sa->rekey_child_sa(this->ike_sa,
254 child_sa->get_protocol(child_sa),
255 child_sa->get_spi(child_sa, TRUE));
256 }
257 }
258 enumerator->destroy(enumerator);
259 }
260
261 /**
262 * Apply the port of the old host, if its ip equals the new, use port otherwise.
263 */
264 static void apply_port(host_t *host, host_t *old, u_int16_t port)
265 {
266 if (host->ip_equals(host, old))
267 {
268 port = old->get_port(old);
269 }
270 else if (port == IKEV2_UDP_PORT)
271 {
272 port = IKEV2_NATT_PORT;
273 }
274 host->set_port(host, port);
275 }
276
277 METHOD(ike_mobike_t, transmit, void,
278 private_ike_mobike_t *this, packet_t *packet)
279 {
280 host_t *me, *other, *me_old, *other_old;
281 enumerator_t *enumerator;
282 ike_cfg_t *ike_cfg;
283 packet_t *copy;
284
285 if (!this->check)
286 {
287 return;
288 }
289
290 me_old = this->ike_sa->get_my_host(this->ike_sa);
291 other_old = this->ike_sa->get_other_host(this->ike_sa);
292 ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
293
294 me = hydra->kernel_interface->get_source_addr(
295 hydra->kernel_interface, other_old, NULL);
296 if (me)
297 {
298 apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg));
299 DBG1(DBG_IKE, "checking original path %#H - %#H", me, other_old);
300 copy = packet->clone(packet);
301 copy->set_source(copy, me);
302 charon->sender->send(charon->sender, copy);
303 }
304
305 enumerator = this->ike_sa->create_additional_address_enumerator(this->ike_sa);
306 while (enumerator->enumerate(enumerator, (void**)&other))
307 {
308 me = hydra->kernel_interface->get_source_addr(
309 hydra->kernel_interface, other, NULL);
310 if (me)
311 {
312 if (me->get_family(me) != other->get_family(other))
313 {
314 me->destroy(me);
315 continue;
316 }
317 /* reuse port for an active address, 4500 otherwise */
318 apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg));
319 other = other->clone(other);
320 apply_port(other, other_old, ike_cfg->get_other_port(ike_cfg));
321 DBG1(DBG_IKE, "checking path %#H - %#H", me, other);
322 copy = packet->clone(packet);
323 copy->set_source(copy, me);
324 copy->set_destination(copy, other);
325 charon->sender->send(charon->sender, copy);
326 }
327 }
328 enumerator->destroy(enumerator);
329 }
330
331 METHOD(task_t, build_i, status_t,
332 private_ike_mobike_t *this, message_t *message)
333 {
334 if (message->get_exchange_type(message) == IKE_AUTH &&
335 message->get_message_id(message) == 1)
336 { /* only in first IKE_AUTH */
337 message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
338 build_address_list(this, message);
339 }
340 else if (message->get_exchange_type(message) == INFORMATIONAL)
341 {
342 host_t *old, *new;
343
344 /* we check if the existing address is still valid */
345 old = message->get_source(message);
346 new = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
347 message->get_destination(message), old);
348 if (new)
349 {
350 if (!new->ip_equals(new, old))
351 {
352 new->set_port(new, old->get_port(old));
353 message->set_source(message, new);
354 }
355 else
356 {
357 new->destroy(new);
358 }
359 }
360 if (this->update)
361 {
362 message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES,
363 chunk_empty);
364 build_cookie(this, message);
365 update_children(this);
366 }
367 if (this->address && !this->check)
368 {
369 build_address_list(this, message);
370 }
371 if (this->natd)
372 {
373 this->natd->task.build(&this->natd->task, message);
374 }
375 }
376 return NEED_MORE;
377 }
378
379 METHOD(task_t, process_r, status_t,
380 private_ike_mobike_t *this, message_t *message)
381 {
382 if (message->get_exchange_type(message) == IKE_AUTH &&
383 message->get_message_id(message) == 1)
384 { /* only first IKE_AUTH */
385 process_payloads(this, message);
386 }
387 else if (message->get_exchange_type(message) == INFORMATIONAL)
388 {
389 process_payloads(this, message);
390 if (this->update)
391 {
392 host_t *me, *other;
393
394 me = message->get_destination(message);
395 other = message->get_source(message);
396 this->ike_sa->set_my_host(this->ike_sa, me->clone(me));
397 this->ike_sa->set_other_host(this->ike_sa, other->clone(other));
398 }
399
400 if (this->natd)
401 {
402 this->natd->task.process(&this->natd->task, message);
403 }
404 if (this->addresses_updated && this->ike_sa->has_condition(this->ike_sa,
405 COND_ORIGINAL_INITIATOR))
406 {
407 host_t *other = message->get_source(message);
408 host_t *other_old = this->ike_sa->get_other_host(this->ike_sa);
409 if (!other->equals(other, other_old))
410 {
411 DBG1(DBG_IKE, "remote address changed from %H to %H", other_old,
412 other);
413 this->ike_sa->set_other_host(this->ike_sa, other->clone(other));
414 this->update = TRUE;
415 }
416 }
417 }
418 return NEED_MORE;
419 }
420
421 METHOD(task_t, build_r, status_t,
422 private_ike_mobike_t *this, message_t *message)
423 {
424 if (message->get_exchange_type(message) == IKE_AUTH &&
425 this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
426 {
427 if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
428 {
429 message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
430 build_address_list(this, message);
431 }
432 return SUCCESS;
433 }
434 else if (message->get_exchange_type(message) == INFORMATIONAL)
435 {
436 if (this->natd)
437 {
438 this->natd->task.build(&this->natd->task, message);
439 }
440 if (this->cookie2.ptr)
441 {
442 message->add_notify(message, FALSE, COOKIE2, this->cookie2);
443 chunk_free(&this->cookie2);
444 }
445 if (this->update)
446 {
447 update_children(this);
448 }
449 return SUCCESS;
450 }
451 return NEED_MORE;
452 }
453
454 METHOD(task_t, process_i, status_t,
455 private_ike_mobike_t *this, message_t *message)
456 {
457 if (message->get_exchange_type(message) == IKE_AUTH &&
458 this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
459 {
460 process_payloads(this, message);
461 return SUCCESS;
462 }
463 else if (message->get_exchange_type(message) == INFORMATIONAL)
464 {
465 u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1;
466 this->ike_sa->set_pending_updates(this->ike_sa, updates);
467 if (updates > 0)
468 {
469 /* newer update queued, ignore this one */
470 return SUCCESS;
471 }
472 if (this->cookie2.ptr)
473 { /* check cookie if we included one */
474 chunk_t cookie2;
475
476 cookie2 = this->cookie2;
477 this->cookie2 = chunk_empty;
478 process_payloads(this, message);
479 if (!chunk_equals(cookie2, this->cookie2))
480 {
481 chunk_free(&cookie2);
482 DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA");
483 return FAILED;
484 }
485 chunk_free(&cookie2);
486 }
487 else
488 {
489 process_payloads(this, message);
490 }
491 if (this->natd)
492 {
493 this->natd->task.process(&this->natd->task, message);
494 if (this->natd->has_mapping_changed(this->natd))
495 {
496 /* force an update if mappings have changed */
497 this->update = this->check = TRUE;
498 DBG1(DBG_IKE, "detected changes in NAT mappings, "
499 "initiating MOBIKE update");
500 }
501 }
502 if (this->update)
503 {
504 /* update again, as NAT state may have changed */
505 update_children(this);
506 }
507 if (this->check)
508 {
509 host_t *me_new, *me_old, *other_new, *other_old;
510
511 me_new = message->get_destination(message);
512 other_new = message->get_source(message);
513 me_old = this->ike_sa->get_my_host(this->ike_sa);
514 other_old = this->ike_sa->get_other_host(this->ike_sa);
515
516 if (!me_new->equals(me_new, me_old))
517 {
518 this->update = TRUE;
519 this->ike_sa->set_my_host(this->ike_sa, me_new->clone(me_new));
520 }
521 if (!other_new->equals(other_new, other_old))
522 {
523 this->update = TRUE;
524 this->ike_sa->set_other_host(this->ike_sa, other_new->clone(other_new));
525 }
526 if (this->update)
527 {
528 /* use the same task to ... */
529 if (!this->ike_sa->has_condition(this->ike_sa,
530 COND_ORIGINAL_INITIATOR))
531 { /*... send an updated list of addresses as responder */
532 update_children(this);
533 this->update = FALSE;
534 }
535 else
536 { /* ... send the update as original initiator */
537 if (this->natd)
538 {
539 this->natd->task.destroy(&this->natd->task);
540 }
541 this->natd = ike_natd_create(this->ike_sa, this->initiator);
542 }
543 this->check = FALSE;
544 this->ike_sa->set_pending_updates(this->ike_sa, 1);
545 return NEED_MORE;
546 }
547 }
548 return SUCCESS;
549 }
550 return NEED_MORE;
551 }
552
553 METHOD(ike_mobike_t, addresses, void,
554 private_ike_mobike_t *this)
555 {
556 this->address = TRUE;
557 this->ike_sa->set_pending_updates(this->ike_sa,
558 this->ike_sa->get_pending_updates(this->ike_sa) + 1);
559 }
560
561 METHOD(ike_mobike_t, roam, void,
562 private_ike_mobike_t *this, bool address)
563 {
564 this->check = TRUE;
565 this->address = address;
566 this->ike_sa->set_pending_updates(this->ike_sa,
567 this->ike_sa->get_pending_updates(this->ike_sa) + 1);
568 }
569
570 METHOD(ike_mobike_t, dpd, void,
571 private_ike_mobike_t *this)
572 {
573 if (!this->natd)
574 {
575 this->natd = ike_natd_create(this->ike_sa, this->initiator);
576 }
577 this->ike_sa->set_pending_updates(this->ike_sa,
578 this->ike_sa->get_pending_updates(this->ike_sa) + 1);
579 }
580
581 METHOD(ike_mobike_t, is_probing, bool,
582 private_ike_mobike_t *this)
583 {
584 return this->check;
585 }
586
587 METHOD(task_t, get_type, task_type_t,
588 private_ike_mobike_t *this)
589 {
590 return TASK_IKE_MOBIKE;
591 }
592
593 METHOD(task_t, migrate, void,
594 private_ike_mobike_t *this, ike_sa_t *ike_sa)
595 {
596 chunk_free(&this->cookie2);
597 this->ike_sa = ike_sa;
598 if (this->natd)
599 {
600 this->natd->task.migrate(&this->natd->task, ike_sa);
601 }
602 }
603
604 METHOD(task_t, destroy, void,
605 private_ike_mobike_t *this)
606 {
607 chunk_free(&this->cookie2);
608 if (this->natd)
609 {
610 this->natd->task.destroy(&this->natd->task);
611 }
612 free(this);
613 }
614
615 /*
616 * Described in header.
617 */
618 ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
619 {
620 private_ike_mobike_t *this;
621
622 INIT(this,
623 .public = {
624 .task = {
625 .get_type = _get_type,
626 .migrate = _migrate,
627 .destroy = _destroy,
628 },
629 .addresses = _addresses,
630 .roam = _roam,
631 .dpd = _dpd,
632 .transmit = _transmit,
633 .is_probing = _is_probing,
634 },
635 .ike_sa = ike_sa,
636 .initiator = initiator,
637 );
638
639 if (initiator)
640 {
641 this->public.task.build = _build_i;
642 this->public.task.process = _process_i;
643 }
644 else
645 {
646 this->public.task.build = _build_r;
647 this->public.task.process = _process_r;
648 }
649
650 return &this->public;
651 }