Consistently log XFRM mark masks with 0 prefix in kernel-netlink plugin
[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 #include "kernel_interface.h"
19
20 #include <debug.h>
21 #include <threading/mutex.h>
22 #include <utils/linked_list.h>
23
24 typedef struct private_kernel_interface_t private_kernel_interface_t;
25
26 /**
27 * Private data of a kernel_interface_t object.
28 */
29 struct private_kernel_interface_t {
30
31 /**
32 * Public part of kernel_interface_t object.
33 */
34 kernel_interface_t public;
35
36 /**
37 * Registered IPsec constructor
38 */
39 kernel_ipsec_constructor_t ipsec_constructor;
40
41 /**
42 * Registered net constructor
43 */
44 kernel_net_constructor_t net_constructor;
45
46 /**
47 * ipsec interface
48 */
49 kernel_ipsec_t *ipsec;
50
51 /**
52 * network interface
53 */
54 kernel_net_t *net;
55
56 /**
57 * mutex for listeners
58 */
59 mutex_t *mutex;
60
61 /**
62 * list of registered listeners
63 */
64 linked_list_t *listeners;
65 };
66
67 METHOD(kernel_interface_t, get_spi, status_t,
68 private_kernel_interface_t *this, host_t *src, host_t *dst,
69 u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
70 {
71 if (!this->ipsec)
72 {
73 return NOT_SUPPORTED;
74 }
75 return this->ipsec->get_spi(this->ipsec, src, dst, protocol, reqid, spi);
76 }
77
78 METHOD(kernel_interface_t, get_cpi, status_t,
79 private_kernel_interface_t *this, host_t *src, host_t *dst,
80 u_int32_t reqid, u_int16_t *cpi)
81 {
82 if (!this->ipsec)
83 {
84 return NOT_SUPPORTED;
85 }
86 return this->ipsec->get_cpi(this->ipsec, src, dst, reqid, cpi);
87 }
88
89 METHOD(kernel_interface_t, add_sa, status_t,
90 private_kernel_interface_t *this, host_t *src, host_t *dst,
91 u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
92 u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
93 u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
94 u_int16_t cpi, bool encap, bool esn, bool inbound,
95 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
96 {
97 if (!this->ipsec)
98 {
99 return NOT_SUPPORTED;
100 }
101 return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
102 mark, tfc, lifetime, enc_alg, enc_key, int_alg, int_key, mode,
103 ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts);
104 }
105
106 METHOD(kernel_interface_t, update_sa, status_t,
107 private_kernel_interface_t *this, u_int32_t spi, u_int8_t protocol,
108 u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst,
109 bool encap, bool new_encap, mark_t mark)
110 {
111 if (!this->ipsec)
112 {
113 return NOT_SUPPORTED;
114 }
115 return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst,
116 new_src, new_dst, encap, new_encap, mark);
117 }
118
119 METHOD(kernel_interface_t, query_sa, status_t,
120 private_kernel_interface_t *this, host_t *src, host_t *dst,
121 u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes)
122 {
123 if (!this->ipsec)
124 {
125 return NOT_SUPPORTED;
126 }
127 return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, bytes);
128 }
129
130 METHOD(kernel_interface_t, del_sa, status_t,
131 private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi,
132 u_int8_t protocol, u_int16_t cpi, mark_t mark)
133 {
134 if (!this->ipsec)
135 {
136 return NOT_SUPPORTED;
137 }
138 return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark);
139 }
140
141 METHOD(kernel_interface_t, flush_sas, status_t,
142 private_kernel_interface_t *this)
143 {
144 if (!this->ipsec)
145 {
146 return NOT_SUPPORTED;
147 }
148 return this->ipsec->flush_sas(this->ipsec);
149 }
150
151 METHOD(kernel_interface_t, add_policy, status_t,
152 private_kernel_interface_t *this, host_t *src, host_t *dst,
153 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
154 policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
155 mark_t mark, policy_priority_t priority)
156 {
157 if (!this->ipsec)
158 {
159 return NOT_SUPPORTED;
160 }
161 return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
162 direction, type, sa, mark, priority);
163 }
164
165 METHOD(kernel_interface_t, query_policy, status_t,
166 private_kernel_interface_t *this, traffic_selector_t *src_ts,
167 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
168 u_int32_t *use_time)
169 {
170 if (!this->ipsec)
171 {
172 return NOT_SUPPORTED;
173 }
174 return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
175 direction, mark, use_time);
176 }
177
178 METHOD(kernel_interface_t, del_policy, status_t,
179 private_kernel_interface_t *this, traffic_selector_t *src_ts,
180 traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
181 mark_t mark, policy_priority_t priority)
182 {
183 if (!this->ipsec)
184 {
185 return NOT_SUPPORTED;
186 }
187 return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
188 direction, reqid, mark, priority);
189 }
190
191 METHOD(kernel_interface_t, flush_policies, status_t,
192 private_kernel_interface_t *this)
193 {
194 if (!this->ipsec)
195 {
196 return NOT_SUPPORTED;
197 }
198 return this->ipsec->flush_policies(this->ipsec);
199 }
200
201 METHOD(kernel_interface_t, get_source_addr, host_t*,
202 private_kernel_interface_t *this, host_t *dest, host_t *src)
203 {
204 if (!this->net)
205 {
206 return NULL;
207 }
208 return this->net->get_source_addr(this->net, dest, src);
209 }
210
211 METHOD(kernel_interface_t, get_nexthop, host_t*,
212 private_kernel_interface_t *this, host_t *dest)
213 {
214 if (!this->net)
215 {
216 return NULL;
217 }
218 return this->net->get_nexthop(this->net, dest);
219 }
220
221 METHOD(kernel_interface_t, get_interface, char*,
222 private_kernel_interface_t *this, host_t *host)
223 {
224 if (!this->net)
225 {
226 return NULL;
227 }
228 return this->net->get_interface(this->net, host);
229 }
230
231 METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
232 private_kernel_interface_t *this, bool include_down_ifaces,
233 bool include_virtual_ips)
234 {
235 if (!this->net)
236 {
237 return enumerator_create_empty();
238 }
239 return this->net->create_address_enumerator(this->net, include_down_ifaces,
240 include_virtual_ips);
241 }
242
243 METHOD(kernel_interface_t, add_ip, status_t,
244 private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip)
245 {
246 if (!this->net)
247 {
248 return NOT_SUPPORTED;
249 }
250 return this->net->add_ip(this->net, virtual_ip, iface_ip);
251 }
252
253 METHOD(kernel_interface_t, del_ip, status_t,
254 private_kernel_interface_t *this, host_t *virtual_ip)
255 {
256 if (!this->net)
257 {
258 return NOT_SUPPORTED;
259 }
260 return this->net->del_ip(this->net, virtual_ip);
261 }
262
263 METHOD(kernel_interface_t, add_route, status_t,
264 private_kernel_interface_t *this, chunk_t dst_net,
265 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
266 {
267 if (!this->net)
268 {
269 return NOT_SUPPORTED;
270 }
271 return this->net->add_route(this->net, dst_net, prefixlen, gateway,
272 src_ip, if_name);
273 }
274
275 METHOD(kernel_interface_t, del_route, status_t,
276 private_kernel_interface_t *this, chunk_t dst_net,
277 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
278 {
279 if (!this->net)
280 {
281 return NOT_SUPPORTED;
282 }
283 return this->net->del_route(this->net, dst_net, prefixlen, gateway,
284 src_ip, if_name);
285 }
286
287 METHOD(kernel_interface_t, bypass_socket, bool,
288 private_kernel_interface_t *this, int fd, int family)
289 {
290 if (!this->ipsec)
291 {
292 return FALSE;
293 }
294 return this->ipsec->bypass_socket(this->ipsec, fd, family);
295 }
296
297 METHOD(kernel_interface_t, enable_udp_decap, bool,
298 private_kernel_interface_t *this, int fd, int family, u_int16_t port)
299 {
300 if (!this->ipsec)
301 {
302 return FALSE;
303 }
304 return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port);
305 }
306
307 METHOD(kernel_interface_t, get_address_by_ts, status_t,
308 private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
309 {
310 enumerator_t *addrs;
311 host_t *host;
312 int family;
313 bool found = FALSE;
314
315 DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
316
317 /* if we have a family which includes localhost, we do not
318 * search for an IP, we use the default */
319 family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
320
321 if (family == AF_INET)
322 {
323 host = host_create_from_string("127.0.0.1", 0);
324 }
325 else
326 {
327 host = host_create_from_string("::1", 0);
328 }
329
330 if (ts->includes(ts, host))
331 {
332 *ip = host_create_any(family);
333 host->destroy(host);
334 DBG2(DBG_KNL, "using host %H", *ip);
335 return SUCCESS;
336 }
337 host->destroy(host);
338
339 addrs = create_address_enumerator(this, TRUE, TRUE);
340 while (addrs->enumerate(addrs, (void**)&host))
341 {
342 if (ts->includes(ts, host))
343 {
344 found = TRUE;
345 *ip = host->clone(host);
346 break;
347 }
348 }
349 addrs->destroy(addrs);
350
351 if (!found)
352 {
353 DBG2(DBG_KNL, "no local address found in traffic selector %R", ts);
354 return FAILED;
355 }
356
357 DBG2(DBG_KNL, "using host %H", *ip);
358 return SUCCESS;
359 }
360
361
362 METHOD(kernel_interface_t, add_ipsec_interface, void,
363 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
364 {
365 if (!this->ipsec)
366 {
367 this->ipsec_constructor = constructor;
368 this->ipsec = constructor();
369 }
370 }
371
372 METHOD(kernel_interface_t, remove_ipsec_interface, void,
373 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
374 {
375 if (constructor == this->ipsec_constructor && this->ipsec)
376 {
377 this->ipsec->destroy(this->ipsec);
378 this->ipsec = NULL;
379 }
380 }
381
382 METHOD(kernel_interface_t, add_net_interface, void,
383 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
384 {
385 if (!this->net)
386 {
387 this->net_constructor = constructor;
388 this->net = constructor();
389 }
390 }
391
392 METHOD(kernel_interface_t, remove_net_interface, void,
393 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
394 {
395 if (constructor == this->net_constructor && this->net)
396 {
397 this->net->destroy(this->net);
398 this->net = NULL;
399 }
400 }
401
402 METHOD(kernel_interface_t, add_listener, void,
403 private_kernel_interface_t *this, kernel_listener_t *listener)
404 {
405 this->mutex->lock(this->mutex);
406 this->listeners->insert_last(this->listeners, listener);
407 this->mutex->unlock(this->mutex);
408 }
409
410 METHOD(kernel_interface_t, remove_listener, void,
411 private_kernel_interface_t *this, kernel_listener_t *listener)
412 {
413 this->mutex->lock(this->mutex);
414 this->listeners->remove(this->listeners, listener, NULL);
415 this->mutex->unlock(this->mutex);
416 }
417
418 METHOD(kernel_interface_t, acquire, void,
419 private_kernel_interface_t *this, u_int32_t reqid,
420 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
421 {
422 kernel_listener_t *listener;
423 enumerator_t *enumerator;
424 this->mutex->lock(this->mutex);
425 enumerator = this->listeners->create_enumerator(this->listeners);
426 while (enumerator->enumerate(enumerator, &listener))
427 {
428 if (listener->acquire &&
429 !listener->acquire(listener, reqid, src_ts, dst_ts))
430 {
431 this->listeners->remove_at(this->listeners, enumerator);
432 }
433 }
434 enumerator->destroy(enumerator);
435 this->mutex->unlock(this->mutex);
436 }
437
438 METHOD(kernel_interface_t, expire, void,
439 private_kernel_interface_t *this, u_int32_t reqid, u_int8_t protocol,
440 u_int32_t spi, bool hard)
441 {
442 kernel_listener_t *listener;
443 enumerator_t *enumerator;
444 this->mutex->lock(this->mutex);
445 enumerator = this->listeners->create_enumerator(this->listeners);
446 while (enumerator->enumerate(enumerator, &listener))
447 {
448 if (listener->expire &&
449 !listener->expire(listener, reqid, protocol, spi, hard))
450 {
451 this->listeners->remove_at(this->listeners, enumerator);
452 }
453 }
454 enumerator->destroy(enumerator);
455 this->mutex->unlock(this->mutex);
456 }
457
458 METHOD(kernel_interface_t, mapping, void,
459 private_kernel_interface_t *this, u_int32_t reqid, u_int32_t spi,
460 host_t *remote)
461 {
462 kernel_listener_t *listener;
463 enumerator_t *enumerator;
464 this->mutex->lock(this->mutex);
465 enumerator = this->listeners->create_enumerator(this->listeners);
466 while (enumerator->enumerate(enumerator, &listener))
467 {
468 if (listener->mapping &&
469 !listener->mapping(listener, reqid, spi, remote))
470 {
471 this->listeners->remove_at(this->listeners, enumerator);
472 }
473 }
474 enumerator->destroy(enumerator);
475 this->mutex->unlock(this->mutex);
476 }
477
478 METHOD(kernel_interface_t, migrate, void,
479 private_kernel_interface_t *this, u_int32_t reqid,
480 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
481 policy_dir_t direction, host_t *local, host_t *remote)
482 {
483 kernel_listener_t *listener;
484 enumerator_t *enumerator;
485 this->mutex->lock(this->mutex);
486 enumerator = this->listeners->create_enumerator(this->listeners);
487 while (enumerator->enumerate(enumerator, &listener))
488 {
489 if (listener->migrate &&
490 !listener->migrate(listener, reqid, src_ts, dst_ts, direction,
491 local, remote))
492 {
493 this->listeners->remove_at(this->listeners, enumerator);
494 }
495 }
496 enumerator->destroy(enumerator);
497 this->mutex->unlock(this->mutex);
498 }
499
500 static bool call_roam(kernel_listener_t *listener, bool *roam)
501 {
502 return listener->roam && !listener->roam(listener, *roam);
503 }
504
505 METHOD(kernel_interface_t, roam, void,
506 private_kernel_interface_t *this, bool address)
507 {
508 this->mutex->lock(this->mutex);
509 this->listeners->remove(this->listeners, &address, (void*)call_roam);
510 this->mutex->unlock(this->mutex);
511 }
512
513 METHOD(kernel_interface_t, destroy, void,
514 private_kernel_interface_t *this)
515 {
516 DESTROY_IF(this->ipsec);
517 DESTROY_IF(this->net);
518 this->mutex->destroy(this->mutex);
519 this->listeners->destroy(this->listeners);
520 free(this);
521 }
522
523 /*
524 * Described in header-file
525 */
526 kernel_interface_t *kernel_interface_create()
527 {
528 private_kernel_interface_t *this;
529
530 INIT(this,
531 .public = {
532 .get_spi = _get_spi,
533 .get_cpi = _get_cpi,
534 .add_sa = _add_sa,
535 .update_sa = _update_sa,
536 .query_sa = _query_sa,
537 .del_sa = _del_sa,
538 .flush_sas = _flush_sas,
539 .add_policy = _add_policy,
540 .query_policy = _query_policy,
541 .del_policy = _del_policy,
542 .flush_policies = _flush_policies,
543 .get_source_addr = _get_source_addr,
544 .get_nexthop = _get_nexthop,
545 .get_interface = _get_interface,
546 .create_address_enumerator = _create_address_enumerator,
547 .add_ip = _add_ip,
548 .del_ip = _del_ip,
549 .add_route = _add_route,
550 .del_route = _del_route,
551 .bypass_socket = _bypass_socket,
552 .enable_udp_decap = _enable_udp_decap,
553
554 .get_address_by_ts = _get_address_by_ts,
555 .add_ipsec_interface = _add_ipsec_interface,
556 .remove_ipsec_interface = _remove_ipsec_interface,
557 .add_net_interface = _add_net_interface,
558 .remove_net_interface = _remove_net_interface,
559
560 .add_listener = _add_listener,
561 .remove_listener = _remove_listener,
562 .acquire = _acquire,
563 .expire = _expire,
564 .mapping = _mapping,
565 .migrate = _migrate,
566 .roam = _roam,
567 .destroy = _destroy,
568 },
569 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
570 .listeners = linked_list_create(),
571 );
572
573 return &this->public;
574 }
575