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