kernel-netlink: Check return value of both halfs when installing default route in...
[strongswan.git] / src / libipsec / ipsec_sa_mgr.c
1 /*
2 * Copyright (C) 2012-2017 Tobias Brunner
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "ipsec.h"
19 #include "ipsec_sa_mgr.h"
20
21 #include <utils/debug.h>
22 #include <library.h>
23 #include <processing/jobs/callback_job.h>
24 #include <threading/condvar.h>
25 #include <threading/mutex.h>
26 #include <collections/hashtable.h>
27 #include <collections/linked_list.h>
28
29 typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t;
30
31 /**
32 * Private additions to ipsec_sa_mgr_t.
33 */
34 struct private_ipsec_sa_mgr_t {
35
36 /**
37 * Public members of ipsec_sa_mgr_t.
38 */
39 ipsec_sa_mgr_t public;
40
41 /**
42 * Installed SAs
43 */
44 linked_list_t *sas;
45
46 /**
47 * SPIs allocated using get_spi()
48 */
49 hashtable_t *allocated_spis;
50
51 /**
52 * Mutex used to synchronize access to the SA manager
53 */
54 mutex_t *mutex;
55
56 /**
57 * RNG used to generate SPIs
58 */
59 rng_t *rng;
60 };
61
62 /**
63 * Struct to keep track of locked IPsec SAs
64 */
65 typedef struct {
66
67 /**
68 * IPsec SA
69 */
70 ipsec_sa_t *sa;
71
72 /**
73 * Set if this SA is currently in use by a thread
74 */
75 bool locked;
76
77 /**
78 * Condvar used by threads to wait for this entry
79 */
80 condvar_t *condvar;
81
82 /**
83 * Number of threads waiting for this entry
84 */
85 u_int waiting_threads;
86
87 /**
88 * Set if this entry is awaiting deletion
89 */
90 bool awaits_deletion;
91
92 } ipsec_sa_entry_t;
93
94 /**
95 * Helper struct for expiration events
96 */
97 typedef struct {
98
99 /**
100 * IPsec SA manager
101 */
102 private_ipsec_sa_mgr_t *manager;
103
104 /**
105 * Entry that expired
106 */
107 ipsec_sa_entry_t *entry;
108
109 /**
110 * SPI of the expired entry
111 */
112 uint32_t spi;
113
114 /**
115 * 0 if this is a hard expire, otherwise the offset in s (soft->hard)
116 */
117 uint32_t hard_offset;
118
119 } ipsec_sa_expired_t;
120
121 /*
122 * Used for the hash table of allocated SPIs
123 */
124 static bool spi_equals(uint32_t *spi, uint32_t *other_spi)
125 {
126 return *spi == *other_spi;
127 }
128
129 static u_int spi_hash(uint32_t *spi)
130 {
131 return chunk_hash(chunk_from_thing(*spi));
132 }
133
134 /**
135 * Create an SA entry
136 */
137 static ipsec_sa_entry_t *create_entry(ipsec_sa_t *sa)
138 {
139 ipsec_sa_entry_t *this;
140
141 INIT(this,
142 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
143 .sa = sa,
144 );
145 return this;
146 }
147
148 /**
149 * Destroy an SA entry
150 */
151 static void destroy_entry(ipsec_sa_entry_t *entry)
152 {
153 entry->condvar->destroy(entry->condvar);
154 entry->sa->destroy(entry->sa);
155 free(entry);
156 }
157
158 /**
159 * Makes sure an entry is safe to remove
160 * Must be called with this->mutex held.
161 *
162 * @return TRUE if entry can be removed, FALSE if entry is already
163 * being removed by another thread
164 */
165 static bool wait_remove_entry(private_ipsec_sa_mgr_t *this,
166 ipsec_sa_entry_t *entry)
167 {
168 if (entry->awaits_deletion)
169 {
170 /* this will be deleted by another thread already */
171 return FALSE;
172 }
173 entry->awaits_deletion = TRUE;
174 while (entry->locked)
175 {
176 entry->condvar->wait(entry->condvar, this->mutex);
177 }
178 while (entry->waiting_threads > 0)
179 {
180 entry->condvar->broadcast(entry->condvar);
181 entry->condvar->wait(entry->condvar, this->mutex);
182 }
183 return TRUE;
184 }
185
186 /**
187 * Waits until an is available and then locks it.
188 * Must only be called with this->mutex held
189 */
190 static bool wait_for_entry(private_ipsec_sa_mgr_t *this,
191 ipsec_sa_entry_t *entry)
192 {
193 while (entry->locked && !entry->awaits_deletion)
194 {
195 entry->waiting_threads++;
196 entry->condvar->wait(entry->condvar, this->mutex);
197 entry->waiting_threads--;
198 }
199 if (entry->awaits_deletion)
200 {
201 /* others may still be waiting, */
202 entry->condvar->signal(entry->condvar);
203 return FALSE;
204 }
205 entry->locked = TRUE;
206 return TRUE;
207 }
208
209 /**
210 * Flushes all entries
211 * Must be called with this->mutex held.
212 */
213 static void flush_entries(private_ipsec_sa_mgr_t *this)
214 {
215 ipsec_sa_entry_t *current;
216 enumerator_t *enumerator;
217
218 DBG2(DBG_ESP, "flushing SAD");
219
220 enumerator = this->sas->create_enumerator(this->sas);
221 while (enumerator->enumerate(enumerator, (void**)&current))
222 {
223 if (wait_remove_entry(this, current))
224 {
225 this->sas->remove_at(this->sas, enumerator);
226 destroy_entry(current);
227 }
228 }
229 enumerator->destroy(enumerator);
230 }
231
232 CALLBACK(match_entry_by_sa_ptr, bool,
233 ipsec_sa_entry_t *item, va_list args)
234 {
235 ipsec_sa_t *sa;
236
237 VA_ARGS_VGET(args, sa);
238 return item->sa == sa;
239 }
240
241 CALLBACK(match_entry_by_spi_inbound, bool,
242 ipsec_sa_entry_t *item, va_list args)
243 {
244 uint32_t spi;
245 int inbound;
246
247 VA_ARGS_VGET(args, spi, inbound);
248 return item->sa->get_spi(item->sa) == spi &&
249 item->sa->is_inbound(item->sa) == inbound;
250 }
251
252 static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, uint32_t spi,
253 host_t *src, host_t *dst)
254 {
255 return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst);
256 }
257
258 CALLBACK(match_entry_by_spi_src_dst_cb, bool,
259 ipsec_sa_entry_t *item, va_list args)
260 {
261 host_t *src, *dst;
262 uint32_t spi;
263
264 VA_ARGS_VGET(args, spi, src, dst);
265 return match_entry_by_spi_src_dst(item, spi, src, dst);
266 }
267
268 CALLBACK(match_entry_by_reqid_inbound, bool,
269 ipsec_sa_entry_t *item, va_list args)
270 {
271 uint32_t reqid;
272 int inbound;
273
274 VA_ARGS_VGET(args, reqid, inbound);
275 return item->sa->match_by_reqid(item->sa, reqid, inbound);
276 }
277
278 CALLBACK(match_entry_by_spi_dst, bool,
279 ipsec_sa_entry_t *item, va_list args)
280 {
281 host_t *dst;
282 uint32_t spi;
283
284 VA_ARGS_VGET(args, spi, dst);
285 return item->sa->match_by_spi_dst(item->sa, spi, dst);
286 }
287
288 /**
289 * Remove an entry
290 */
291 static bool remove_entry(private_ipsec_sa_mgr_t *this, ipsec_sa_entry_t *entry)
292 {
293 ipsec_sa_entry_t *current;
294 enumerator_t *enumerator;
295 bool removed = FALSE;
296
297 enumerator = this->sas->create_enumerator(this->sas);
298 while (enumerator->enumerate(enumerator, (void**)&current))
299 {
300 if (current == entry)
301 {
302 if (wait_remove_entry(this, current))
303 {
304 this->sas->remove_at(this->sas, enumerator);
305 removed = TRUE;
306 }
307 break;
308 }
309 }
310 enumerator->destroy(enumerator);
311 return removed;
312 }
313
314 /**
315 * Callback for expiration events
316 */
317 static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
318 {
319 private_ipsec_sa_mgr_t *this = expired->manager;
320
321 this->mutex->lock(this->mutex);
322 if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry) &&
323 expired->spi == expired->entry->sa->get_spi(expired->entry->sa))
324 { /* only if we find the right SA at this pointer location */
325 uint32_t hard_offset;
326
327 hard_offset = expired->hard_offset;
328 expired->entry->sa->expire(expired->entry->sa, hard_offset == 0);
329 if (hard_offset)
330 { /* soft limit reached, schedule hard expire */
331 expired->hard_offset = 0;
332 this->mutex->unlock(this->mutex);
333 return JOB_RESCHEDULE(hard_offset);
334 }
335 /* hard limit reached */
336 if (remove_entry(this, expired->entry))
337 {
338 destroy_entry(expired->entry);
339 }
340 }
341 this->mutex->unlock(this->mutex);
342 return JOB_REQUEUE_NONE;
343 }
344
345 /**
346 * Schedule a job to handle IPsec SA expiration
347 */
348 static void schedule_expiration(private_ipsec_sa_mgr_t *this,
349 ipsec_sa_entry_t *entry)
350 {
351 lifetime_cfg_t *lifetime = entry->sa->get_lifetime(entry->sa);
352 ipsec_sa_expired_t *expired;
353 callback_job_t *job;
354 uint32_t timeout;
355
356 if (!lifetime->time.life)
357 { /* no expiration at all */
358 return;
359 }
360
361 INIT(expired,
362 .manager = this,
363 .entry = entry,
364 .spi = entry->sa->get_spi(entry->sa),
365 );
366
367 /* schedule a rekey first, a hard timeout will be scheduled then, if any */
368 expired->hard_offset = lifetime->time.life - lifetime->time.rekey;
369 timeout = lifetime->time.rekey;
370
371 if (lifetime->time.life <= lifetime->time.rekey ||
372 lifetime->time.rekey == 0)
373 { /* no rekey, schedule hard timeout */
374 expired->hard_offset = 0;
375 timeout = lifetime->time.life;
376 }
377
378 job = callback_job_create((callback_job_cb_t)sa_expired, expired,
379 (callback_job_cleanup_t)free, NULL);
380 lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout);
381 }
382
383 /**
384 * Remove all allocated SPIs
385 */
386 static void flush_allocated_spis(private_ipsec_sa_mgr_t *this)
387 {
388 enumerator_t *enumerator;
389 uint32_t *current;
390
391 DBG2(DBG_ESP, "flushing allocated SPIs");
392 enumerator = this->allocated_spis->create_enumerator(this->allocated_spis);
393 while (enumerator->enumerate(enumerator, NULL, (void**)&current))
394 {
395 this->allocated_spis->remove_at(this->allocated_spis, enumerator);
396 DBG2(DBG_ESP, " removed allocated SPI %.8x", ntohl(*current));
397 free(current);
398 }
399 enumerator->destroy(enumerator);
400 }
401
402 /**
403 * Pre-allocate an SPI for an inbound SA
404 */
405 static bool allocate_spi(private_ipsec_sa_mgr_t *this, uint32_t spi)
406 {
407 uint32_t *spi_alloc;
408
409 if (this->allocated_spis->get(this->allocated_spis, &spi) ||
410 this->sas->find_first(this->sas, match_entry_by_spi_inbound,
411 NULL, spi, TRUE))
412 {
413 return FALSE;
414 }
415 spi_alloc = malloc_thing(uint32_t);
416 *spi_alloc = spi;
417 this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc);
418 return TRUE;
419 }
420
421 METHOD(ipsec_sa_mgr_t, get_spi, status_t,
422 private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint8_t protocol,
423 uint32_t *spi)
424 {
425 uint32_t spi_min, spi_max, spi_new;
426
427 spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
428 0x00000100, lib->ns);
429 spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
430 0xffffffff, lib->ns);
431 if (spi_min > spi_max)
432 {
433 spi_new = spi_min;
434 spi_min = spi_max;
435 spi_max = spi_new;
436 }
437 /* make sure the SPI is valid (not in range 0-255) */
438 spi_min = max(spi_min, 0x00000100);
439 spi_max = max(spi_max, 0x00000100);
440
441 this->mutex->lock(this->mutex);
442 if (!this->rng)
443 {
444 this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
445 if (!this->rng)
446 {
447 this->mutex->unlock(this->mutex);
448 DBG1(DBG_ESP, "failed to create RNG for SPI generation");
449 return FAILED;
450 }
451 }
452
453 do
454 {
455 if (!this->rng->get_bytes(this->rng, sizeof(spi_new),
456 (uint8_t*)&spi_new))
457 {
458 this->mutex->unlock(this->mutex);
459 DBG1(DBG_ESP, "failed to allocate SPI");
460 return FAILED;
461 }
462 spi_new = spi_min + spi_new % (spi_max - spi_min + 1);
463 spi_new = htonl(spi_new);
464 }
465 while (!allocate_spi(this, spi_new));
466 this->mutex->unlock(this->mutex);
467
468 *spi = spi_new;
469
470 DBG2(DBG_ESP, "allocated SPI %.8x", ntohl(*spi));
471 return SUCCESS;
472 }
473
474 METHOD(ipsec_sa_mgr_t, add_sa, status_t,
475 private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
476 uint8_t protocol, uint32_t reqid, mark_t mark, uint32_t tfc,
477 lifetime_cfg_t *lifetime, uint16_t enc_alg, chunk_t enc_key,
478 uint16_t int_alg, chunk_t int_key, ipsec_mode_t mode, uint16_t ipcomp,
479 uint16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
480 bool update)
481 {
482 ipsec_sa_entry_t *entry;
483 ipsec_sa_t *sa_new;
484
485 DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}",
486 ntohl(spi), reqid);
487 DBG2(DBG_ESP, " using encryption algorithm %N with key size %d",
488 encryption_algorithm_names, enc_alg, enc_key.len * 8);
489 DBG2(DBG_ESP, " using integrity algorithm %N with key size %d",
490 integrity_algorithm_names, int_alg, int_key.len * 8);
491
492 sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc,
493 lifetime, enc_alg, enc_key, int_alg, int_key, mode,
494 ipcomp, cpi, encap, esn, inbound);
495 if (!sa_new)
496 {
497 DBG1(DBG_ESP, "failed to create SAD entry");
498 return FAILED;
499 }
500
501 this->mutex->lock(this->mutex);
502
503 if (update)
504 { /* remove any pre-allocated SPIs */
505 uint32_t *spi_alloc;
506
507 spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi);
508 free(spi_alloc);
509 }
510
511 if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb, NULL,
512 spi, src, dst))
513 {
514 this->mutex->unlock(this->mutex);
515 DBG1(DBG_ESP, "failed to install SAD entry: already installed");
516 sa_new->destroy(sa_new);
517 return FAILED;
518 }
519
520 entry = create_entry(sa_new);
521 schedule_expiration(this, entry);
522 this->sas->insert_first(this->sas, entry);
523
524 this->mutex->unlock(this->mutex);
525 return SUCCESS;
526 }
527
528 METHOD(ipsec_sa_mgr_t, update_sa, status_t,
529 private_ipsec_sa_mgr_t *this, uint32_t spi, uint8_t protocol,
530 uint16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
531 bool encap, bool new_encap, mark_t mark)
532 {
533 ipsec_sa_entry_t *entry = NULL;
534
535 DBG2(DBG_ESP, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
536 ntohl(spi), src, dst, new_src, new_dst);
537
538 if (!new_encap)
539 {
540 DBG1(DBG_ESP, "failed to update SAD entry: can't deactivate UDP "
541 "encapsulation");
542 return NOT_SUPPORTED;
543 }
544
545 this->mutex->lock(this->mutex);
546 if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
547 (void**)&entry, spi, src, dst) &&
548 wait_for_entry(this, entry))
549 {
550 entry->sa->set_source(entry->sa, new_src);
551 entry->sa->set_destination(entry->sa, new_dst);
552 /* checkin the entry */
553 entry->locked = FALSE;
554 entry->condvar->signal(entry->condvar);
555 }
556 this->mutex->unlock(this->mutex);
557
558 if (!entry)
559 {
560 DBG1(DBG_ESP, "failed to update SAD entry: not found");
561 return FAILED;
562 }
563 return SUCCESS;
564 }
565
566 METHOD(ipsec_sa_mgr_t, query_sa, status_t,
567 private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
568 uint32_t spi, uint8_t protocol, mark_t mark,
569 uint64_t *bytes, uint64_t *packets, time_t *time)
570 {
571 ipsec_sa_entry_t *entry = NULL;
572
573 this->mutex->lock(this->mutex);
574 if (this->sas->find_first(this->sas, match_entry_by_spi_src_dst_cb,
575 (void**)&entry, spi, src, dst) &&
576 wait_for_entry(this, entry))
577 {
578 entry->sa->get_usestats(entry->sa, bytes, packets, time);
579 /* checkin the entry */
580 entry->locked = FALSE;
581 entry->condvar->signal(entry->condvar);
582 }
583 this->mutex->unlock(this->mutex);
584
585 return entry ? SUCCESS : NOT_FOUND;
586 }
587
588 METHOD(ipsec_sa_mgr_t, del_sa, status_t,
589 private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint32_t spi,
590 uint8_t protocol, uint16_t cpi, mark_t mark)
591 {
592 ipsec_sa_entry_t *current, *found = NULL;
593 enumerator_t *enumerator;
594
595 this->mutex->lock(this->mutex);
596 enumerator = this->sas->create_enumerator(this->sas);
597 while (enumerator->enumerate(enumerator, (void**)&current))
598 {
599 if (match_entry_by_spi_src_dst(current, spi, src, dst))
600 {
601 if (wait_remove_entry(this, current))
602 {
603 this->sas->remove_at(this->sas, enumerator);
604 found = current;
605 }
606 break;
607 }
608 }
609 enumerator->destroy(enumerator);
610 this->mutex->unlock(this->mutex);
611
612 if (found)
613 {
614 DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x",
615 found->sa->is_inbound(found->sa) ? "in" : "out", ntohl(spi));
616 destroy_entry(found);
617 return SUCCESS;
618 }
619 return FAILED;
620 }
621
622 METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*,
623 private_ipsec_sa_mgr_t *this, uint32_t reqid, bool inbound)
624 {
625 ipsec_sa_entry_t *entry;
626 ipsec_sa_t *sa = NULL;
627
628 this->mutex->lock(this->mutex);
629 if (this->sas->find_first(this->sas, match_entry_by_reqid_inbound,
630 (void**)&entry, reqid, inbound) &&
631 wait_for_entry(this, entry))
632 {
633 sa = entry->sa;
634 }
635 this->mutex->unlock(this->mutex);
636 return sa;
637 }
638
639 METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*,
640 private_ipsec_sa_mgr_t *this, uint32_t spi, host_t *dst)
641 {
642 ipsec_sa_entry_t *entry;
643 ipsec_sa_t *sa = NULL;
644
645 this->mutex->lock(this->mutex);
646 if (this->sas->find_first(this->sas, match_entry_by_spi_dst,
647 (void**)&entry, spi, dst) &&
648 wait_for_entry(this, entry))
649 {
650 sa = entry->sa;
651 }
652 this->mutex->unlock(this->mutex);
653 return sa;
654 }
655
656 METHOD(ipsec_sa_mgr_t, checkin, void,
657 private_ipsec_sa_mgr_t *this, ipsec_sa_t *sa)
658 {
659 ipsec_sa_entry_t *entry;
660
661 this->mutex->lock(this->mutex);
662 if (this->sas->find_first(this->sas, match_entry_by_sa_ptr,
663 (void**)&entry, sa))
664 {
665 if (entry->locked)
666 {
667 entry->locked = FALSE;
668 entry->condvar->signal(entry->condvar);
669 }
670 }
671 this->mutex->unlock(this->mutex);
672 }
673
674 METHOD(ipsec_sa_mgr_t, flush_sas, status_t,
675 private_ipsec_sa_mgr_t *this)
676 {
677 this->mutex->lock(this->mutex);
678 flush_entries(this);
679 this->mutex->unlock(this->mutex);
680 return SUCCESS;
681 }
682
683 METHOD(ipsec_sa_mgr_t, destroy, void,
684 private_ipsec_sa_mgr_t *this)
685 {
686 this->mutex->lock(this->mutex);
687 flush_entries(this);
688 flush_allocated_spis(this);
689 this->mutex->unlock(this->mutex);
690
691 this->allocated_spis->destroy(this->allocated_spis);
692 this->sas->destroy(this->sas);
693
694 this->mutex->destroy(this->mutex);
695 DESTROY_IF(this->rng);
696 free(this);
697 }
698
699 /**
700 * Described in header.
701 */
702 ipsec_sa_mgr_t *ipsec_sa_mgr_create()
703 {
704 private_ipsec_sa_mgr_t *this;
705
706 INIT(this,
707 .public = {
708 .get_spi = _get_spi,
709 .add_sa = _add_sa,
710 .update_sa = _update_sa,
711 .query_sa = _query_sa,
712 .del_sa = _del_sa,
713 .checkout_by_spi = _checkout_by_spi,
714 .checkout_by_reqid = _checkout_by_reqid,
715 .checkin = _checkin,
716 .flush_sas = _flush_sas,
717 .destroy = _destroy,
718 },
719 .sas = linked_list_create(),
720 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
721 .allocated_spis = hashtable_create((hashtable_hash_t)spi_hash,
722 (hashtable_equals_t)spi_equals, 16),
723 );
724
725 return &this->public;
726 }