Added possibility to register custom kernel algorithms to kernel interface
[strongswan.git] / src / libhydra / kernel / kernel_interface.c
1 /*
2 * Copyright (C) 2008-2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2010 Martin Willi
5 * Copyright (C) 2010 revosec AG
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 /*
19 * Copyright (c) 2012 Nanoteq Pty Ltd
20 *
21 * Permission is hereby granted, free of charge, to any person obtaining a copy
22 * of this software and associated documentation files (the "Software"), to deal
23 * in the Software without restriction, including without limitation the rights
24 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 * copies of the Software, and to permit persons to whom the Software is
26 * furnished to do so, subject to the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be included in
29 * all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37 * THE SOFTWARE.
38 */
39
40 #include "kernel_interface.h"
41
42 #include <debug.h>
43 #include <threading/mutex.h>
44 #include <utils/linked_list.h>
45
46 typedef struct private_kernel_interface_t private_kernel_interface_t;
47
48 typedef struct kernel_algorithm_t kernel_algorithm_t;
49
50 /**
51 * Mapping of IKE algorithms to kernel-specific algorithm identifiers
52 */
53 struct kernel_algorithm_t {
54
55 /**
56 * Transform type of the algorithm
57 */
58 transform_type_t type;
59
60 /**
61 * Identifier specified in IKE
62 */
63 u_int16_t ike;
64
65 /**
66 * Identifier as defined in pfkeyv2.h
67 */
68 u_int16_t kernel;
69
70 /**
71 * Name of the algorithm in linux crypto API
72 */
73 char *name;
74 };
75
76 /**
77 * Private data of a kernel_interface_t object.
78 */
79 struct private_kernel_interface_t {
80
81 /**
82 * Public part of kernel_interface_t object.
83 */
84 kernel_interface_t public;
85
86 /**
87 * Registered IPsec constructor
88 */
89 kernel_ipsec_constructor_t ipsec_constructor;
90
91 /**
92 * Registered net constructor
93 */
94 kernel_net_constructor_t net_constructor;
95
96 /**
97 * ipsec interface
98 */
99 kernel_ipsec_t *ipsec;
100
101 /**
102 * network interface
103 */
104 kernel_net_t *net;
105
106 /**
107 * mutex for listeners
108 */
109 mutex_t *mutex;
110
111 /**
112 * list of registered listeners
113 */
114 linked_list_t *listeners;
115
116 /**
117 * mutex for algorithm mappings
118 */
119 mutex_t *mutex_algs;
120
121 /**
122 * List of algorithm mappings (kernel_algorithm_t*)
123 */
124 linked_list_t *algorithms;
125 };
126
127 METHOD(kernel_interface_t, get_spi, status_t,
128 private_kernel_interface_t *this, host_t *src, host_t *dst,
129 u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
130 {
131 if (!this->ipsec)
132 {
133 return NOT_SUPPORTED;
134 }
135 return this->ipsec->get_spi(this->ipsec, src, dst, protocol, reqid, spi);
136 }
137
138 METHOD(kernel_interface_t, get_cpi, status_t,
139 private_kernel_interface_t *this, host_t *src, host_t *dst,
140 u_int32_t reqid, u_int16_t *cpi)
141 {
142 if (!this->ipsec)
143 {
144 return NOT_SUPPORTED;
145 }
146 return this->ipsec->get_cpi(this->ipsec, src, dst, reqid, cpi);
147 }
148
149 METHOD(kernel_interface_t, add_sa, status_t,
150 private_kernel_interface_t *this, host_t *src, host_t *dst,
151 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
152 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
153 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
154 u_int16_t cpi, bool encap, bool esn, bool inbound,
155 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
156 {
157 if (!this->ipsec)
158 {
159 return NOT_SUPPORTED;
160 }
161 return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
162 mark, tfc, lifetime, enc_alg, enc_key, int_alg, int_key, mode,
163 ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts);
164 }
165
166 METHOD(kernel_interface_t, update_sa, status_t,
167 private_kernel_interface_t *this, u_int32_t spi, u_int8_t protocol,
168 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
169 bool encap, bool new_encap, mark_t mark)
170 {
171 if (!this->ipsec)
172 {
173 return NOT_SUPPORTED;
174 }
175 return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst,
176 new_src, new_dst, encap, new_encap, mark);
177 }
178
179 METHOD(kernel_interface_t, query_sa, status_t,
180 private_kernel_interface_t *this, host_t *src, host_t *dst,
181 u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes)
182 {
183 if (!this->ipsec)
184 {
185 return NOT_SUPPORTED;
186 }
187 return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, bytes);
188 }
189
190 METHOD(kernel_interface_t, del_sa, status_t,
191 private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi,
192 u_int8_t protocol, u_int16_t cpi, mark_t mark)
193 {
194 if (!this->ipsec)
195 {
196 return NOT_SUPPORTED;
197 }
198 return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark);
199 }
200
201 METHOD(kernel_interface_t, flush_sas, status_t,
202 private_kernel_interface_t *this)
203 {
204 if (!this->ipsec)
205 {
206 return NOT_SUPPORTED;
207 }
208 return this->ipsec->flush_sas(this->ipsec);
209 }
210
211 METHOD(kernel_interface_t, add_policy, status_t,
212 private_kernel_interface_t *this, host_t *src, host_t *dst,
213 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
214 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
215 mark_t mark, policy_priority_t priority)
216 {
217 if (!this->ipsec)
218 {
219 return NOT_SUPPORTED;
220 }
221 return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
222 direction, type, sa, mark, priority);
223 }
224
225 METHOD(kernel_interface_t, query_policy, status_t,
226 private_kernel_interface_t *this, traffic_selector_t *src_ts,
227 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
228 u_int32_t *use_time)
229 {
230 if (!this->ipsec)
231 {
232 return NOT_SUPPORTED;
233 }
234 return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
235 direction, mark, use_time);
236 }
237
238 METHOD(kernel_interface_t, del_policy, status_t,
239 private_kernel_interface_t *this, traffic_selector_t *src_ts,
240 traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
241 mark_t mark, policy_priority_t priority)
242 {
243 if (!this->ipsec)
244 {
245 return NOT_SUPPORTED;
246 }
247 return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
248 direction, reqid, mark, priority);
249 }
250
251 METHOD(kernel_interface_t, flush_policies, status_t,
252 private_kernel_interface_t *this)
253 {
254 if (!this->ipsec)
255 {
256 return NOT_SUPPORTED;
257 }
258 return this->ipsec->flush_policies(this->ipsec);
259 }
260
261 METHOD(kernel_interface_t, get_source_addr, host_t*,
262 private_kernel_interface_t *this, host_t *dest, host_t *src)
263 {
264 if (!this->net)
265 {
266 return NULL;
267 }
268 return this->net->get_source_addr(this->net, dest, src);
269 }
270
271 METHOD(kernel_interface_t, get_nexthop, host_t*,
272 private_kernel_interface_t *this, host_t *dest)
273 {
274 if (!this->net)
275 {
276 return NULL;
277 }
278 return this->net->get_nexthop(this->net, dest);
279 }
280
281 METHOD(kernel_interface_t, get_interface, char*,
282 private_kernel_interface_t *this, host_t *host)
283 {
284 if (!this->net)
285 {
286 return NULL;
287 }
288 return this->net->get_interface(this->net, host);
289 }
290
291 METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
292 private_kernel_interface_t *this, bool include_down_ifaces,
293 bool include_virtual_ips)
294 {
295 if (!this->net)
296 {
297 return enumerator_create_empty();
298 }
299 return this->net->create_address_enumerator(this->net, include_down_ifaces,
300 include_virtual_ips);
301 }
302
303 METHOD(kernel_interface_t, add_ip, status_t,
304 private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip)
305 {
306 if (!this->net)
307 {
308 return NOT_SUPPORTED;
309 }
310 return this->net->add_ip(this->net, virtual_ip, iface_ip);
311 }
312
313 METHOD(kernel_interface_t, del_ip, status_t,
314 private_kernel_interface_t *this, host_t *virtual_ip)
315 {
316 if (!this->net)
317 {
318 return NOT_SUPPORTED;
319 }
320 return this->net->del_ip(this->net, virtual_ip);
321 }
322
323 METHOD(kernel_interface_t, add_route, status_t,
324 private_kernel_interface_t *this, chunk_t dst_net,
325 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
326 {
327 if (!this->net)
328 {
329 return NOT_SUPPORTED;
330 }
331 return this->net->add_route(this->net, dst_net, prefixlen, gateway,
332 src_ip, if_name);
333 }
334
335 METHOD(kernel_interface_t, del_route, status_t,
336 private_kernel_interface_t *this, chunk_t dst_net,
337 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
338 {
339 if (!this->net)
340 {
341 return NOT_SUPPORTED;
342 }
343 return this->net->del_route(this->net, dst_net, prefixlen, gateway,
344 src_ip, if_name);
345 }
346
347 METHOD(kernel_interface_t, bypass_socket, bool,
348 private_kernel_interface_t *this, int fd, int family)
349 {
350 if (!this->ipsec)
351 {
352 return FALSE;
353 }
354 return this->ipsec->bypass_socket(this->ipsec, fd, family);
355 }
356
357 METHOD(kernel_interface_t, enable_udp_decap, bool,
358 private_kernel_interface_t *this, int fd, int family, u_int16_t port)
359 {
360 if (!this->ipsec)
361 {
362 return FALSE;
363 }
364 return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port);
365 }
366
367 METHOD(kernel_interface_t, get_address_by_ts, status_t,
368 private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
369 {
370 enumerator_t *addrs;
371 host_t *host;
372 int family;
373 bool found = FALSE;
374
375 DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
376
377 /* if we have a family which includes localhost, we do not
378 * search for an IP, we use the default */
379 family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
380
381 if (family == AF_INET)
382 {
383 host = host_create_from_string("127.0.0.1", 0);
384 }
385 else
386 {
387 host = host_create_from_string("::1", 0);
388 }
389
390 if (ts->includes(ts, host))
391 {
392 *ip = host_create_any(family);
393 host->destroy(host);
394 DBG2(DBG_KNL, "using host %H", *ip);
395 return SUCCESS;
396 }
397 host->destroy(host);
398
399 addrs = create_address_enumerator(this, TRUE, TRUE);
400 while (addrs->enumerate(addrs, (void**)&host))
401 {
402 if (ts->includes(ts, host))
403 {
404 found = TRUE;
405 *ip = host->clone(host);
406 break;
407 }
408 }
409 addrs->destroy(addrs);
410
411 if (!found)
412 {
413 DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
414 return FAILED;
415 }
416
417 DBG2(DBG_KNL, "using host %H", *ip);
418 return SUCCESS;
419 }
420
421
422 METHOD(kernel_interface_t, add_ipsec_interface, void,
423 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
424 {
425 if (!this->ipsec)
426 {
427 this->ipsec_constructor = constructor;
428 this->ipsec = constructor();
429 }
430 }
431
432 METHOD(kernel_interface_t, remove_ipsec_interface, void,
433 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
434 {
435 if (constructor == this->ipsec_constructor && this->ipsec)
436 {
437 this->ipsec->destroy(this->ipsec);
438 this->ipsec = NULL;
439 }
440 }
441
442 METHOD(kernel_interface_t, add_net_interface, void,
443 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
444 {
445 if (!this->net)
446 {
447 this->net_constructor = constructor;
448 this->net = constructor();
449 }
450 }
451
452 METHOD(kernel_interface_t, remove_net_interface, void,
453 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
454 {
455 if (constructor == this->net_constructor && this->net)
456 {
457 this->net->destroy(this->net);
458 this->net = NULL;
459 }
460 }
461
462 METHOD(kernel_interface_t, add_listener, void,
463 private_kernel_interface_t *this, kernel_listener_t *listener)
464 {
465 this->mutex->lock(this->mutex);
466 this->listeners->insert_last(this->listeners, listener);
467 this->mutex->unlock(this->mutex);
468 }
469
470 METHOD(kernel_interface_t, remove_listener, void,
471 private_kernel_interface_t *this, kernel_listener_t *listener)
472 {
473 this->mutex->lock(this->mutex);
474 this->listeners->remove(this->listeners, listener, NULL);
475 this->mutex->unlock(this->mutex);
476 }
477
478 METHOD(kernel_interface_t, acquire, void,
479 private_kernel_interface_t *this, u_int32_t reqid,
480 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
481 {
482 kernel_listener_t *listener;
483 enumerator_t *enumerator;
484 this->mutex->lock(this->mutex);
485 enumerator = this->listeners->create_enumerator(this->listeners);
486 while (enumerator->enumerate(enumerator, &listener))
487 {
488 if (listener->acquire &&
489 !listener->acquire(listener, reqid, src_ts, dst_ts))
490 {
491 this->listeners->remove_at(this->listeners, enumerator);
492 }
493 }
494 enumerator->destroy(enumerator);
495 this->mutex->unlock(this->mutex);
496 }
497
498 METHOD(kernel_interface_t, expire, void,
499 private_kernel_interface_t *this, u_int32_t reqid, u_int8_t protocol,
500 u_int32_t spi, bool hard)
501 {
502 kernel_listener_t *listener;
503 enumerator_t *enumerator;
504 this->mutex->lock(this->mutex);
505 enumerator = this->listeners->create_enumerator(this->listeners);
506 while (enumerator->enumerate(enumerator, &listener))
507 {
508 if (listener->expire &&
509 !listener->expire(listener, reqid, protocol, spi, hard))
510 {
511 this->listeners->remove_at(this->listeners, enumerator);
512 }
513 }
514 enumerator->destroy(enumerator);
515 this->mutex->unlock(this->mutex);
516 }
517
518 METHOD(kernel_interface_t, mapping, void,
519 private_kernel_interface_t *this, u_int32_t reqid, u_int32_t spi,
520 host_t *remote)
521 {
522 kernel_listener_t *listener;
523 enumerator_t *enumerator;
524 this->mutex->lock(this->mutex);
525 enumerator = this->listeners->create_enumerator(this->listeners);
526 while (enumerator->enumerate(enumerator, &listener))
527 {
528 if (listener->mapping &&
529 !listener->mapping(listener, reqid, spi, remote))
530 {
531 this->listeners->remove_at(this->listeners, enumerator);
532 }
533 }
534 enumerator->destroy(enumerator);
535 this->mutex->unlock(this->mutex);
536 }
537
538 METHOD(kernel_interface_t, migrate, void,
539 private_kernel_interface_t *this, u_int32_t reqid,
540 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
541 policy_dir_t direction, host_t *local, host_t *remote)
542 {
543 kernel_listener_t *listener;
544 enumerator_t *enumerator;
545 this->mutex->lock(this->mutex);
546 enumerator = this->listeners->create_enumerator(this->listeners);
547 while (enumerator->enumerate(enumerator, &listener))
548 {
549 if (listener->migrate &&
550 !listener->migrate(listener, reqid, src_ts, dst_ts, direction,
551 local, remote))
552 {
553 this->listeners->remove_at(this->listeners, enumerator);
554 }
555 }
556 enumerator->destroy(enumerator);
557 this->mutex->unlock(this->mutex);
558 }
559
560 static bool call_roam(kernel_listener_t *listener, bool *roam)
561 {
562 return listener->roam && !listener->roam(listener, *roam);
563 }
564
565 METHOD(kernel_interface_t, roam, void,
566 private_kernel_interface_t *this, bool address)
567 {
568 this->mutex->lock(this->mutex);
569 this->listeners->remove(this->listeners, &address, (void*)call_roam);
570 this->mutex->unlock(this->mutex);
571 }
572
573 METHOD(kernel_interface_t, register_algorithm, void,
574 private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type,
575 u_int16_t kernel_id, char *kernel_name)
576 {
577 kernel_algorithm_t *algorithm;
578
579 INIT(algorithm,
580 .type = type,
581 .ike = alg_id,
582 .kernel = kernel_id,
583 .name = strdup(kernel_name),
584 );
585
586 this->mutex_algs->lock(this->mutex_algs);
587 this->algorithms->insert_first(this->algorithms, algorithm);
588 this->mutex_algs->unlock(this->mutex_algs);
589 }
590
591 METHOD(kernel_interface_t, lookup_algorithm, bool,
592 private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type,
593 u_int16_t *kernel_id, char **kernel_name)
594 {
595 kernel_algorithm_t *algorithm;
596 enumerator_t *enumerator;
597 bool found = FALSE;
598
599 this->mutex_algs->lock(this->mutex_algs);
600 enumerator = this->algorithms->create_enumerator(this->algorithms);
601 while (enumerator->enumerate(enumerator, &algorithm))
602 {
603 if (algorithm->type == type && algorithm->ike == alg_id)
604 {
605 if (kernel_id)
606 {
607 *kernel_id = algorithm->kernel;
608 }
609 if (kernel_name)
610 {
611 *kernel_name = algorithm->name;
612 }
613 found = TRUE;
614 break;
615 }
616 }
617 enumerator->destroy(enumerator);
618 this->mutex_algs->unlock(this->mutex_algs);
619 return found;
620 }
621
622 METHOD(kernel_interface_t, destroy, void,
623 private_kernel_interface_t *this)
624 {
625 kernel_algorithm_t *algorithm;
626
627 while (this->algorithms->remove_first(this->algorithms,
628 (void**)&algorithm) == SUCCESS)
629 {
630 free(algorithm->name);
631 free(algorithm);
632 }
633 this->algorithms->destroy(this->algorithms);
634 this->mutex_algs->destroy(this->mutex_algs);
635 DESTROY_IF(this->ipsec);
636 DESTROY_IF(this->net);
637 this->listeners->destroy(this->listeners);
638 this->mutex->destroy(this->mutex);
639 free(this);
640 }
641
642 /*
643 * Described in header-file
644 */
645 kernel_interface_t *kernel_interface_create()
646 {
647 private_kernel_interface_t *this;
648
649 INIT(this,
650 .public = {
651 .get_spi = _get_spi,
652 .get_cpi = _get_cpi,
653 .add_sa = _add_sa,
654 .update_sa = _update_sa,
655 .query_sa = _query_sa,
656 .del_sa = _del_sa,
657 .flush_sas = _flush_sas,
658 .add_policy = _add_policy,
659 .query_policy = _query_policy,
660 .del_policy = _del_policy,
661 .flush_policies = _flush_policies,
662 .get_source_addr = _get_source_addr,
663 .get_nexthop = _get_nexthop,
664 .get_interface = _get_interface,
665 .create_address_enumerator = _create_address_enumerator,
666 .add_ip = _add_ip,
667 .del_ip = _del_ip,
668 .add_route = _add_route,
669 .del_route = _del_route,
670 .bypass_socket = _bypass_socket,
671 .enable_udp_decap = _enable_udp_decap,
672
673 .get_address_by_ts = _get_address_by_ts,
674 .add_ipsec_interface = _add_ipsec_interface,
675 .remove_ipsec_interface = _remove_ipsec_interface,
676 .add_net_interface = _add_net_interface,
677 .remove_net_interface = _remove_net_interface,
678
679 .add_listener = _add_listener,
680 .remove_listener = _remove_listener,
681 .register_algorithm = _register_algorithm,
682 .lookup_algorithm = _lookup_algorithm,
683 .acquire = _acquire,
684 .expire = _expire,
685 .mapping = _mapping,
686 .migrate = _migrate,
687 .roam = _roam,
688 .destroy = _destroy,
689 },
690 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
691 .listeners = linked_list_create(),
692 .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT),
693 .algorithms = linked_list_create(),
694 );
695
696 return &this->public;
697 }
698