libhydra: Move kernel interface to libcharon
[strongswan.git] / src / libcharon / kernel / kernel_interface.c
1 /*
2 * Copyright (C) 2008-2015 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 <utils/debug.h>
43 #include <threading/mutex.h>
44 #include <collections/linked_list.h>
45 #include <collections/hashtable.h>
46 #include <collections/array.h>
47
48 typedef struct private_kernel_interface_t private_kernel_interface_t;
49
50 typedef struct kernel_algorithm_t kernel_algorithm_t;
51
52 /**
53 * Mapping of IKE algorithms to kernel-specific algorithm identifiers
54 */
55 struct kernel_algorithm_t {
56
57 /**
58 * Transform type of the algorithm
59 */
60 transform_type_t type;
61
62 /**
63 * Identifier specified in IKE
64 */
65 u_int16_t ike;
66
67 /**
68 * Identifier as defined in pfkeyv2.h
69 */
70 u_int16_t kernel;
71
72 /**
73 * Name of the algorithm in linux crypto API
74 */
75 char *name;
76 };
77
78 /**
79 * Private data of a kernel_interface_t object.
80 */
81 struct private_kernel_interface_t {
82
83 /**
84 * Public part of kernel_interface_t object.
85 */
86 kernel_interface_t public;
87
88 /**
89 * Registered IPsec constructor
90 */
91 kernel_ipsec_constructor_t ipsec_constructor;
92
93 /**
94 * Registered net constructor
95 */
96 kernel_net_constructor_t net_constructor;
97
98 /**
99 * ipsec interface
100 */
101 kernel_ipsec_t *ipsec;
102
103 /**
104 * network interface
105 */
106 kernel_net_t *net;
107
108 /**
109 * mutex for listeners
110 */
111 mutex_t *mutex;
112
113 /**
114 * list of registered listeners
115 */
116 linked_list_t *listeners;
117
118 /**
119 * Reqid entries indexed by reqids
120 */
121 hashtable_t *reqids;
122
123 /**
124 * Reqid entries indexed by traffic selectors
125 */
126 hashtable_t *reqids_by_ts;
127
128 /**
129 * mutex for algorithm mappings
130 */
131 mutex_t *mutex_algs;
132
133 /**
134 * List of algorithm mappings (kernel_algorithm_t*)
135 */
136 linked_list_t *algorithms;
137
138 /**
139 * List of interface names to include or exclude (char*), NULL if interfaces
140 * are not filtered
141 */
142 linked_list_t *ifaces_filter;
143
144 /**
145 * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider
146 * only those listed there
147 */
148 bool ifaces_exclude;
149 };
150
151 METHOD(kernel_interface_t, get_features, kernel_feature_t,
152 private_kernel_interface_t *this)
153 {
154 kernel_feature_t features = 0;
155
156 if (this->ipsec && this->ipsec->get_features)
157 {
158 features |= this->ipsec->get_features(this->ipsec);
159 }
160 if (this->net && this->net->get_features)
161 {
162 features |= this->net->get_features(this->net);
163 }
164 return features;
165 }
166
167 METHOD(kernel_interface_t, get_spi, status_t,
168 private_kernel_interface_t *this, host_t *src, host_t *dst,
169 u_int8_t protocol, u_int32_t *spi)
170 {
171 if (!this->ipsec)
172 {
173 return NOT_SUPPORTED;
174 }
175 return this->ipsec->get_spi(this->ipsec, src, dst, protocol, spi);
176 }
177
178 METHOD(kernel_interface_t, get_cpi, status_t,
179 private_kernel_interface_t *this, host_t *src, host_t *dst,
180 u_int16_t *cpi)
181 {
182 if (!this->ipsec)
183 {
184 return NOT_SUPPORTED;
185 }
186 return this->ipsec->get_cpi(this->ipsec, src, dst, cpi);
187 }
188
189 /**
190 * Reqid mapping entry
191 */
192 typedef struct {
193 /** allocated reqid */
194 u_int32_t reqid;
195 /** references to this entry */
196 u_int refs;
197 /** inbound mark used for SA */
198 mark_t mark_in;
199 /** outbound mark used for SA */
200 mark_t mark_out;
201 /** local traffic selectors */
202 array_t *local;
203 /** remote traffic selectors */
204 array_t *remote;
205 } reqid_entry_t;
206
207 /**
208 * Destroy a reqid mapping entry
209 */
210 static void reqid_entry_destroy(reqid_entry_t *entry)
211 {
212 array_destroy_offset(entry->local, offsetof(traffic_selector_t, destroy));
213 array_destroy_offset(entry->remote, offsetof(traffic_selector_t, destroy));
214 free(entry);
215 }
216
217 /**
218 * Hashtable hash function for reqid entries using reqid as key
219 */
220 static u_int hash_reqid(reqid_entry_t *entry)
221 {
222 return chunk_hash_inc(chunk_from_thing(entry->reqid),
223 chunk_hash_inc(chunk_from_thing(entry->mark_in),
224 chunk_hash(chunk_from_thing(entry->mark_out))));
225 }
226
227 /**
228 * Hashtable equals function for reqid entries using reqid as key
229 */
230 static bool equals_reqid(reqid_entry_t *a, reqid_entry_t *b)
231 {
232 return a->reqid == b->reqid &&
233 a->mark_in.value == b->mark_in.value &&
234 a->mark_in.mask == b->mark_in.mask &&
235 a->mark_out.value == b->mark_out.value &&
236 a->mark_out.mask == b->mark_out.mask;
237 }
238
239 /**
240 * Hash an array of traffic selectors
241 */
242 static u_int hash_ts_array(array_t *array, u_int hash)
243 {
244 enumerator_t *enumerator;
245 traffic_selector_t *ts;
246
247 enumerator = array_create_enumerator(array);
248 while (enumerator->enumerate(enumerator, &ts))
249 {
250 hash = ts->hash(ts, hash);
251 }
252 enumerator->destroy(enumerator);
253
254 return hash;
255 }
256
257 /**
258 * Hashtable hash function for reqid entries using traffic selectors as key
259 */
260 static u_int hash_reqid_by_ts(reqid_entry_t *entry)
261 {
262 return hash_ts_array(entry->local, hash_ts_array(entry->remote,
263 chunk_hash_inc(chunk_from_thing(entry->mark_in),
264 chunk_hash(chunk_from_thing(entry->mark_out)))));
265 }
266
267 /**
268 * Compare two array with traffic selectors for equality
269 */
270 static bool ts_array_equals(array_t *a, array_t *b)
271 {
272 traffic_selector_t *tsa, *tsb;
273 enumerator_t *ae, *be;
274 bool equal = TRUE;
275
276 if (array_count(a) != array_count(b))
277 {
278 return FALSE;
279 }
280
281 ae = array_create_enumerator(a);
282 be = array_create_enumerator(b);
283 while (equal && ae->enumerate(ae, &tsa) && be->enumerate(be, &tsb))
284 {
285 equal = tsa->equals(tsa, tsb);
286 }
287 ae->destroy(ae);
288 be->destroy(be);
289
290 return equal;
291 }
292
293 /**
294 * Hashtable equals function for reqid entries using traffic selectors as key
295 */
296 static bool equals_reqid_by_ts(reqid_entry_t *a, reqid_entry_t *b)
297 {
298 return ts_array_equals(a->local, b->local) &&
299 ts_array_equals(a->remote, b->remote) &&
300 a->mark_in.value == b->mark_in.value &&
301 a->mark_in.mask == b->mark_in.mask &&
302 a->mark_out.value == b->mark_out.value &&
303 a->mark_out.mask == b->mark_out.mask;
304 }
305
306 /**
307 * Create an array from copied traffic selector list items
308 */
309 static array_t *array_from_ts_list(linked_list_t *list)
310 {
311 enumerator_t *enumerator;
312 traffic_selector_t *ts;
313 array_t *array;
314
315 array = array_create(0, 0);
316
317 enumerator = list->create_enumerator(list);
318 while (enumerator->enumerate(enumerator, &ts))
319 {
320 array_insert(array, ARRAY_TAIL, ts->clone(ts));
321 }
322 enumerator->destroy(enumerator);
323
324 return array;
325 }
326
327 METHOD(kernel_interface_t, alloc_reqid, status_t,
328 private_kernel_interface_t *this,
329 linked_list_t *local_ts, linked_list_t *remote_ts,
330 mark_t mark_in, mark_t mark_out, u_int32_t *reqid)
331 {
332 static u_int32_t counter = 0;
333 reqid_entry_t *entry = NULL, *tmpl;
334 status_t status = SUCCESS;
335
336 INIT(tmpl,
337 .local = array_from_ts_list(local_ts),
338 .remote = array_from_ts_list(remote_ts),
339 .mark_in = mark_in,
340 .mark_out = mark_out,
341 .reqid = *reqid,
342 );
343
344 this->mutex->lock(this->mutex);
345 if (tmpl->reqid)
346 {
347 /* search by reqid if given */
348 entry = this->reqids->get(this->reqids, tmpl);
349 }
350 if (entry)
351 {
352 /* we don't require a traffic selector match for explicit reqids,
353 * as we wan't to reuse a reqid for trap-triggered policies that
354 * got narrowed during negotiation. */
355 reqid_entry_destroy(tmpl);
356 }
357 else
358 {
359 /* search by traffic selectors */
360 entry = this->reqids_by_ts->get(this->reqids_by_ts, tmpl);
361 if (entry)
362 {
363 reqid_entry_destroy(tmpl);
364 }
365 else
366 {
367 /* none found, create a new entry, allocating a reqid */
368 entry = tmpl;
369 entry->reqid = ++counter;
370 this->reqids_by_ts->put(this->reqids_by_ts, entry, entry);
371 this->reqids->put(this->reqids, entry, entry);
372 }
373 *reqid = entry->reqid;
374 }
375 entry->refs++;
376 this->mutex->unlock(this->mutex);
377
378 return status;
379 }
380
381 METHOD(kernel_interface_t, release_reqid, status_t,
382 private_kernel_interface_t *this, u_int32_t reqid,
383 mark_t mark_in, mark_t mark_out)
384 {
385 reqid_entry_t *entry, tmpl = {
386 .reqid = reqid,
387 .mark_in = mark_in,
388 .mark_out = mark_out,
389 };
390
391 this->mutex->lock(this->mutex);
392 entry = this->reqids->remove(this->reqids, &tmpl);
393 if (entry)
394 {
395 if (--entry->refs == 0)
396 {
397 entry = this->reqids_by_ts->remove(this->reqids_by_ts, entry);
398 if (entry)
399 {
400 reqid_entry_destroy(entry);
401 }
402 }
403 else
404 {
405 this->reqids->put(this->reqids, entry, entry);
406 }
407 }
408 this->mutex->unlock(this->mutex);
409
410 if (entry)
411 {
412 return SUCCESS;
413 }
414 return NOT_FOUND;
415 }
416
417 METHOD(kernel_interface_t, add_sa, status_t,
418 private_kernel_interface_t *this, host_t *src, host_t *dst,
419 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
420 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
421 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
422 u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window,
423 bool initiator, bool encap, bool esn, bool inbound, bool update,
424 linked_list_t *src_ts, linked_list_t *dst_ts)
425 {
426 if (!this->ipsec)
427 {
428 return NOT_SUPPORTED;
429 }
430 return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
431 mark, tfc, lifetime, enc_alg, enc_key, int_alg, int_key, mode,
432 ipcomp, cpi, replay_window, initiator, encap, esn, inbound,
433 update, src_ts, dst_ts);
434 }
435
436 METHOD(kernel_interface_t, update_sa, status_t,
437 private_kernel_interface_t *this, u_int32_t spi, u_int8_t protocol,
438 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
439 bool encap, bool new_encap, mark_t mark)
440 {
441 if (!this->ipsec)
442 {
443 return NOT_SUPPORTED;
444 }
445 return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst,
446 new_src, new_dst, encap, new_encap, mark);
447 }
448
449 METHOD(kernel_interface_t, query_sa, status_t,
450 private_kernel_interface_t *this, host_t *src, host_t *dst,
451 u_int32_t spi, u_int8_t protocol, mark_t mark,
452 u_int64_t *bytes, u_int64_t *packets, time_t *time)
453 {
454 if (!this->ipsec)
455 {
456 return NOT_SUPPORTED;
457 }
458 return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark,
459 bytes, packets, time);
460 }
461
462 METHOD(kernel_interface_t, del_sa, status_t,
463 private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi,
464 u_int8_t protocol, u_int16_t cpi, mark_t mark)
465 {
466 if (!this->ipsec)
467 {
468 return NOT_SUPPORTED;
469 }
470 return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark);
471 }
472
473 METHOD(kernel_interface_t, flush_sas, status_t,
474 private_kernel_interface_t *this)
475 {
476 if (!this->ipsec)
477 {
478 return NOT_SUPPORTED;
479 }
480 return this->ipsec->flush_sas(this->ipsec);
481 }
482
483 METHOD(kernel_interface_t, add_policy, status_t,
484 private_kernel_interface_t *this, host_t *src, host_t *dst,
485 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
486 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
487 mark_t mark, policy_priority_t priority)
488 {
489 if (!this->ipsec)
490 {
491 return NOT_SUPPORTED;
492 }
493 return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
494 direction, type, sa, mark, priority);
495 }
496
497 METHOD(kernel_interface_t, query_policy, status_t,
498 private_kernel_interface_t *this, traffic_selector_t *src_ts,
499 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
500 time_t *use_time)
501 {
502 if (!this->ipsec)
503 {
504 return NOT_SUPPORTED;
505 }
506 return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
507 direction, mark, use_time);
508 }
509
510 METHOD(kernel_interface_t, del_policy, status_t,
511 private_kernel_interface_t *this, host_t *src, host_t *dst,
512 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
513 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
514 mark_t mark, policy_priority_t priority)
515 {
516 if (!this->ipsec)
517 {
518 return NOT_SUPPORTED;
519 }
520 return this->ipsec->del_policy(this->ipsec, src, dst, src_ts, dst_ts,
521 direction, type, sa, mark, priority);
522 }
523
524 METHOD(kernel_interface_t, flush_policies, status_t,
525 private_kernel_interface_t *this)
526 {
527 if (!this->ipsec)
528 {
529 return NOT_SUPPORTED;
530 }
531 return this->ipsec->flush_policies(this->ipsec);
532 }
533
534 METHOD(kernel_interface_t, get_source_addr, host_t*,
535 private_kernel_interface_t *this, host_t *dest, host_t *src)
536 {
537 if (!this->net)
538 {
539 return NULL;
540 }
541 return this->net->get_source_addr(this->net, dest, src);
542 }
543
544 METHOD(kernel_interface_t, get_nexthop, host_t*,
545 private_kernel_interface_t *this, host_t *dest, int prefix, host_t *src)
546 {
547 if (!this->net)
548 {
549 return NULL;
550 }
551 return this->net->get_nexthop(this->net, dest, prefix, src);
552 }
553
554 METHOD(kernel_interface_t, get_interface, bool,
555 private_kernel_interface_t *this, host_t *host, char **name)
556 {
557 if (!this->net)
558 {
559 return NULL;
560 }
561 return this->net->get_interface(this->net, host, name);
562 }
563
564 METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
565 private_kernel_interface_t *this, kernel_address_type_t which)
566 {
567 if (!this->net)
568 {
569 return enumerator_create_empty();
570 }
571 return this->net->create_address_enumerator(this->net, which);
572 }
573
574 METHOD(kernel_interface_t, add_ip, status_t,
575 private_kernel_interface_t *this, host_t *virtual_ip, int prefix,
576 char *iface)
577 {
578 if (!this->net)
579 {
580 return NOT_SUPPORTED;
581 }
582 return this->net->add_ip(this->net, virtual_ip, prefix, iface);
583 }
584
585 METHOD(kernel_interface_t, del_ip, status_t,
586 private_kernel_interface_t *this, host_t *virtual_ip, int prefix, bool wait)
587 {
588 if (!this->net)
589 {
590 return NOT_SUPPORTED;
591 }
592 return this->net->del_ip(this->net, virtual_ip, prefix, wait);
593 }
594
595 METHOD(kernel_interface_t, add_route, status_t,
596 private_kernel_interface_t *this, chunk_t dst_net,
597 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
598 {
599 if (!this->net)
600 {
601 return NOT_SUPPORTED;
602 }
603 return this->net->add_route(this->net, dst_net, prefixlen, gateway,
604 src_ip, if_name);
605 }
606
607 METHOD(kernel_interface_t, del_route, status_t,
608 private_kernel_interface_t *this, chunk_t dst_net,
609 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
610 {
611 if (!this->net)
612 {
613 return NOT_SUPPORTED;
614 }
615 return this->net->del_route(this->net, dst_net, prefixlen, gateway,
616 src_ip, if_name);
617 }
618
619 METHOD(kernel_interface_t, bypass_socket, bool,
620 private_kernel_interface_t *this, int fd, int family)
621 {
622 if (!this->ipsec)
623 {
624 return FALSE;
625 }
626 return this->ipsec->bypass_socket(this->ipsec, fd, family);
627 }
628
629 METHOD(kernel_interface_t, enable_udp_decap, bool,
630 private_kernel_interface_t *this, int fd, int family, u_int16_t port)
631 {
632 if (!this->ipsec)
633 {
634 return FALSE;
635 }
636 return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port);
637 }
638
639 METHOD(kernel_interface_t, is_interface_usable, bool,
640 private_kernel_interface_t *this, const char *iface)
641 {
642 status_t expected;
643
644 if (!this->ifaces_filter)
645 {
646 return TRUE;
647 }
648 expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS;
649 return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq,
650 NULL, iface) == expected;
651 }
652
653 METHOD(kernel_interface_t, all_interfaces_usable, bool,
654 private_kernel_interface_t *this)
655 {
656 return this->ifaces_filter == NULL;
657 }
658
659 METHOD(kernel_interface_t, get_address_by_ts, status_t,
660 private_kernel_interface_t *this, traffic_selector_t *ts,
661 host_t **ip, bool *vip)
662 {
663 enumerator_t *addrs;
664 host_t *host;
665 int family;
666 bool found = FALSE;
667
668 DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
669
670 /* if we have a family which includes localhost, we do not
671 * search for an IP, we use the default */
672 family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
673
674 if (family == AF_INET)
675 {
676 host = host_create_from_string("127.0.0.1", 0);
677 }
678 else
679 {
680 host = host_create_from_string("::1", 0);
681 }
682
683 if (ts->includes(ts, host))
684 {
685 *ip = host_create_any(family);
686 host->destroy(host);
687 DBG2(DBG_KNL, "using host %H", *ip);
688 return SUCCESS;
689 }
690 host->destroy(host);
691
692 /* try virtual IPs only first (on all interfaces) */
693 addrs = create_address_enumerator(this,
694 ADDR_TYPE_ALL ^ ADDR_TYPE_REGULAR);
695 while (addrs->enumerate(addrs, (void**)&host))
696 {
697 if (ts->includes(ts, host))
698 {
699 found = TRUE;
700 *ip = host->clone(host);
701 if (vip)
702 {
703 *vip = TRUE;
704 }
705 break;
706 }
707 }
708 addrs->destroy(addrs);
709
710 if (!found)
711 { /* then try the regular addresses (on all interfaces) */
712 addrs = create_address_enumerator(this,
713 ADDR_TYPE_ALL ^ ADDR_TYPE_VIRTUAL);
714 while (addrs->enumerate(addrs, (void**)&host))
715 {
716 if (ts->includes(ts, host))
717 {
718 found = TRUE;
719 *ip = host->clone(host);
720 if (vip)
721 {
722 *vip = FALSE;
723 }
724 break;
725 }
726 }
727 addrs->destroy(addrs);
728 }
729
730 if (!found)
731 {
732 DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
733 return FAILED;
734 }
735
736 DBG2(DBG_KNL, "using host %H", *ip);
737 return SUCCESS;
738 }
739
740
741 METHOD(kernel_interface_t, add_ipsec_interface, bool,
742 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
743 {
744 if (!this->ipsec)
745 {
746 this->ipsec_constructor = constructor;
747 this->ipsec = constructor();
748 return this->ipsec != NULL;
749 }
750 return FALSE;
751 }
752
753 METHOD(kernel_interface_t, remove_ipsec_interface, bool,
754 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
755 {
756 if (constructor == this->ipsec_constructor && this->ipsec)
757 {
758 this->ipsec->destroy(this->ipsec);
759 this->ipsec = NULL;
760 return TRUE;
761 }
762 return FALSE;
763 }
764
765 METHOD(kernel_interface_t, add_net_interface, bool,
766 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
767 {
768 if (!this->net)
769 {
770 this->net_constructor = constructor;
771 this->net = constructor();
772 return this->net != NULL;
773 }
774 return FALSE;
775 }
776
777 METHOD(kernel_interface_t, remove_net_interface, bool,
778 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
779 {
780 if (constructor == this->net_constructor && this->net)
781 {
782 this->net->destroy(this->net);
783 this->net = NULL;
784 return TRUE;
785 }
786 return FALSE;
787 }
788
789 METHOD(kernel_interface_t, add_listener, void,
790 private_kernel_interface_t *this, kernel_listener_t *listener)
791 {
792 this->mutex->lock(this->mutex);
793 this->listeners->insert_last(this->listeners, listener);
794 this->mutex->unlock(this->mutex);
795 }
796
797 METHOD(kernel_interface_t, remove_listener, void,
798 private_kernel_interface_t *this, kernel_listener_t *listener)
799 {
800 this->mutex->lock(this->mutex);
801 this->listeners->remove(this->listeners, listener, NULL);
802 this->mutex->unlock(this->mutex);
803 }
804
805 METHOD(kernel_interface_t, acquire, void,
806 private_kernel_interface_t *this, u_int32_t reqid,
807 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
808 {
809 kernel_listener_t *listener;
810 enumerator_t *enumerator;
811 this->mutex->lock(this->mutex);
812 enumerator = this->listeners->create_enumerator(this->listeners);
813 while (enumerator->enumerate(enumerator, &listener))
814 {
815 if (listener->acquire &&
816 !listener->acquire(listener, reqid, src_ts, dst_ts))
817 {
818 this->listeners->remove_at(this->listeners, enumerator);
819 }
820 }
821 enumerator->destroy(enumerator);
822 this->mutex->unlock(this->mutex);
823 }
824
825 METHOD(kernel_interface_t, expire, void,
826 private_kernel_interface_t *this, u_int8_t protocol, u_int32_t spi,
827 host_t *dst, bool hard)
828 {
829 kernel_listener_t *listener;
830 enumerator_t *enumerator;
831
832 this->mutex->lock(this->mutex);
833 enumerator = this->listeners->create_enumerator(this->listeners);
834 while (enumerator->enumerate(enumerator, &listener))
835 {
836 if (listener->expire &&
837 !listener->expire(listener, protocol, spi, dst, hard))
838 {
839 this->listeners->remove_at(this->listeners, enumerator);
840 }
841 }
842 enumerator->destroy(enumerator);
843 this->mutex->unlock(this->mutex);
844 }
845
846 METHOD(kernel_interface_t, mapping, void,
847 private_kernel_interface_t *this, u_int8_t protocol, u_int32_t spi,
848 host_t *dst, host_t *remote)
849 {
850 kernel_listener_t *listener;
851 enumerator_t *enumerator;
852
853 this->mutex->lock(this->mutex);
854 enumerator = this->listeners->create_enumerator(this->listeners);
855 while (enumerator->enumerate(enumerator, &listener))
856 {
857 if (listener->mapping &&
858 !listener->mapping(listener, protocol, spi, dst, remote))
859 {
860 this->listeners->remove_at(this->listeners, enumerator);
861 }
862 }
863 enumerator->destroy(enumerator);
864 this->mutex->unlock(this->mutex);
865 }
866
867 METHOD(kernel_interface_t, migrate, void,
868 private_kernel_interface_t *this, u_int32_t reqid,
869 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
870 policy_dir_t direction, host_t *local, host_t *remote)
871 {
872 kernel_listener_t *listener;
873 enumerator_t *enumerator;
874 this->mutex->lock(this->mutex);
875 enumerator = this->listeners->create_enumerator(this->listeners);
876 while (enumerator->enumerate(enumerator, &listener))
877 {
878 if (listener->migrate &&
879 !listener->migrate(listener, reqid, src_ts, dst_ts, direction,
880 local, remote))
881 {
882 this->listeners->remove_at(this->listeners, enumerator);
883 }
884 }
885 enumerator->destroy(enumerator);
886 this->mutex->unlock(this->mutex);
887 }
888
889 static bool call_roam(kernel_listener_t *listener, bool *roam)
890 {
891 return listener->roam && !listener->roam(listener, *roam);
892 }
893
894 METHOD(kernel_interface_t, roam, void,
895 private_kernel_interface_t *this, bool address)
896 {
897 this->mutex->lock(this->mutex);
898 this->listeners->remove(this->listeners, &address, (void*)call_roam);
899 this->mutex->unlock(this->mutex);
900 }
901
902 METHOD(kernel_interface_t, tun, void,
903 private_kernel_interface_t *this, tun_device_t *tun, bool created)
904 {
905 kernel_listener_t *listener;
906 enumerator_t *enumerator;
907 this->mutex->lock(this->mutex);
908 enumerator = this->listeners->create_enumerator(this->listeners);
909 while (enumerator->enumerate(enumerator, &listener))
910 {
911 if (listener->tun &&
912 !listener->tun(listener, tun, created))
913 {
914 this->listeners->remove_at(this->listeners, enumerator);
915 }
916 }
917 enumerator->destroy(enumerator);
918 this->mutex->unlock(this->mutex);
919 }
920
921 METHOD(kernel_interface_t, register_algorithm, void,
922 private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type,
923 u_int16_t kernel_id, char *kernel_name)
924 {
925 kernel_algorithm_t *algorithm;
926
927 INIT(algorithm,
928 .type = type,
929 .ike = alg_id,
930 .kernel = kernel_id,
931 .name = strdup(kernel_name),
932 );
933
934 this->mutex_algs->lock(this->mutex_algs);
935 this->algorithms->insert_first(this->algorithms, algorithm);
936 this->mutex_algs->unlock(this->mutex_algs);
937 }
938
939 METHOD(kernel_interface_t, lookup_algorithm, bool,
940 private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type,
941 u_int16_t *kernel_id, char **kernel_name)
942 {
943 kernel_algorithm_t *algorithm;
944 enumerator_t *enumerator;
945 bool found = FALSE;
946
947 this->mutex_algs->lock(this->mutex_algs);
948 enumerator = this->algorithms->create_enumerator(this->algorithms);
949 while (enumerator->enumerate(enumerator, &algorithm))
950 {
951 if (algorithm->type == type && algorithm->ike == alg_id)
952 {
953 if (kernel_id)
954 {
955 *kernel_id = algorithm->kernel;
956 }
957 if (kernel_name)
958 {
959 *kernel_name = algorithm->name;
960 }
961 found = TRUE;
962 break;
963 }
964 }
965 enumerator->destroy(enumerator);
966 this->mutex_algs->unlock(this->mutex_algs);
967 return found;
968 }
969
970 METHOD(kernel_interface_t, destroy, void,
971 private_kernel_interface_t *this)
972 {
973 kernel_algorithm_t *algorithm;
974
975 while (this->algorithms->remove_first(this->algorithms,
976 (void**)&algorithm) == SUCCESS)
977 {
978 free(algorithm->name);
979 free(algorithm);
980 }
981 this->algorithms->destroy(this->algorithms);
982 this->mutex_algs->destroy(this->mutex_algs);
983 DESTROY_IF(this->ipsec);
984 DESTROY_IF(this->net);
985 DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
986 this->reqids->destroy(this->reqids);
987 this->reqids_by_ts->destroy(this->reqids_by_ts);
988 this->listeners->destroy(this->listeners);
989 this->mutex->destroy(this->mutex);
990 free(this);
991 }
992
993 /*
994 * Described in header-file
995 */
996 kernel_interface_t *kernel_interface_create()
997 {
998 private_kernel_interface_t *this;
999 char *ifaces;
1000
1001 INIT(this,
1002 .public = {
1003 .get_features = _get_features,
1004 .get_spi = _get_spi,
1005 .get_cpi = _get_cpi,
1006 .alloc_reqid = _alloc_reqid,
1007 .release_reqid = _release_reqid,
1008 .add_sa = _add_sa,
1009 .update_sa = _update_sa,
1010 .query_sa = _query_sa,
1011 .del_sa = _del_sa,
1012 .flush_sas = _flush_sas,
1013 .add_policy = _add_policy,
1014 .query_policy = _query_policy,
1015 .del_policy = _del_policy,
1016 .flush_policies = _flush_policies,
1017 .get_source_addr = _get_source_addr,
1018 .get_nexthop = _get_nexthop,
1019 .get_interface = _get_interface,
1020 .create_address_enumerator = _create_address_enumerator,
1021 .add_ip = _add_ip,
1022 .del_ip = _del_ip,
1023 .add_route = _add_route,
1024 .del_route = _del_route,
1025 .bypass_socket = _bypass_socket,
1026 .enable_udp_decap = _enable_udp_decap,
1027
1028 .is_interface_usable = _is_interface_usable,
1029 .all_interfaces_usable = _all_interfaces_usable,
1030 .get_address_by_ts = _get_address_by_ts,
1031 .add_ipsec_interface = _add_ipsec_interface,
1032 .remove_ipsec_interface = _remove_ipsec_interface,
1033 .add_net_interface = _add_net_interface,
1034 .remove_net_interface = _remove_net_interface,
1035
1036 .add_listener = _add_listener,
1037 .remove_listener = _remove_listener,
1038 .register_algorithm = _register_algorithm,
1039 .lookup_algorithm = _lookup_algorithm,
1040 .acquire = _acquire,
1041 .expire = _expire,
1042 .mapping = _mapping,
1043 .migrate = _migrate,
1044 .roam = _roam,
1045 .tun = _tun,
1046 .destroy = _destroy,
1047 },
1048 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1049 .listeners = linked_list_create(),
1050 .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT),
1051 .algorithms = linked_list_create(),
1052 .reqids = hashtable_create((hashtable_hash_t)hash_reqid,
1053 (hashtable_equals_t)equals_reqid, 8),
1054 .reqids_by_ts = hashtable_create((hashtable_hash_t)hash_reqid_by_ts,
1055 (hashtable_equals_t)equals_reqid_by_ts, 8),
1056 );
1057
1058 ifaces = lib->settings->get_str(lib->settings,
1059 "%s.interfaces_use", NULL, lib->ns);
1060 if (!ifaces)
1061 {
1062 this->ifaces_exclude = TRUE;
1063 ifaces = lib->settings->get_str(lib->settings,
1064 "%s.interfaces_ignore", NULL, lib->ns);
1065 }
1066 if (ifaces)
1067 {
1068 enumerator_t *enumerator;
1069 char *iface;
1070
1071 enumerator = enumerator_create_token(ifaces, ",", " ");
1072 while (enumerator->enumerate(enumerator, &iface))
1073 {
1074 if (!this->ifaces_filter)
1075 {
1076 this->ifaces_filter = linked_list_create();
1077 }
1078 this->ifaces_filter->insert_last(this->ifaces_filter,
1079 strdup(iface));
1080 }
1081 enumerator->destroy(enumerator);
1082 }
1083
1084 return &this->public;
1085 }