Added listener handling to kernel interface.
[strongswan.git] / src / libcharon / 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 <daemon.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 protocol_id_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, protocol_id_t protocol, u_int32_t reqid,
82 mark_t mark, 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, lifetime, enc_alg, enc_key, int_alg, int_key, mode, ipcomp,
93 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, protocol_id_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, protocol_id_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 protocol_id_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, u_int32_t spi, protocol_id_t protocol,
135 u_int32_t reqid, mark_t mark, ipsec_mode_t mode, u_int16_t ipcomp,
136 u_int16_t cpi, bool routed)
137 {
138 if (!this->ipsec)
139 {
140 return NOT_SUPPORTED;
141 }
142 return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
143 direction, spi, protocol, reqid, mark, mode, ipcomp, cpi, routed);
144 }
145
146 METHOD(kernel_interface_t, query_policy, status_t,
147 private_kernel_interface_t *this, traffic_selector_t *src_ts,
148 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
149 u_int32_t *use_time)
150 {
151 if (!this->ipsec)
152 {
153 return NOT_SUPPORTED;
154 }
155 return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts,
156 direction, mark, use_time);
157 }
158
159 METHOD(kernel_interface_t, del_policy, status_t,
160 private_kernel_interface_t *this, traffic_selector_t *src_ts,
161 traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark,
162 bool unrouted)
163 {
164 if (!this->ipsec)
165 {
166 return NOT_SUPPORTED;
167 }
168 return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
169 direction, mark, unrouted);
170 }
171
172 METHOD(kernel_interface_t, get_source_addr, host_t*,
173 private_kernel_interface_t *this, host_t *dest, host_t *src)
174 {
175 if (!this->net)
176 {
177 return NULL;
178 }
179 return this->net->get_source_addr(this->net, dest, src);
180 }
181
182 METHOD(kernel_interface_t, get_nexthop, host_t*,
183 private_kernel_interface_t *this, host_t *dest)
184 {
185 if (!this->net)
186 {
187 return NULL;
188 }
189 return this->net->get_nexthop(this->net, dest);
190 }
191
192 METHOD(kernel_interface_t, get_interface, char*,
193 private_kernel_interface_t *this, host_t *host)
194 {
195 if (!this->net)
196 {
197 return NULL;
198 }
199 return this->net->get_interface(this->net, host);
200 }
201
202 METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*,
203 private_kernel_interface_t *this, bool include_down_ifaces,
204 bool include_virtual_ips)
205 {
206 if (!this->net)
207 {
208 return enumerator_create_empty();
209 }
210 return this->net->create_address_enumerator(this->net, include_down_ifaces,
211 include_virtual_ips);
212 }
213
214 METHOD(kernel_interface_t, add_ip, status_t,
215 private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip)
216 {
217 if (!this->net)
218 {
219 return NOT_SUPPORTED;
220 }
221 return this->net->add_ip(this->net, virtual_ip, iface_ip);
222 }
223
224 METHOD(kernel_interface_t, del_ip, status_t,
225 private_kernel_interface_t *this, host_t *virtual_ip)
226 {
227 if (!this->net)
228 {
229 return NOT_SUPPORTED;
230 }
231 return this->net->del_ip(this->net, virtual_ip);
232 }
233
234 METHOD(kernel_interface_t, add_route, status_t,
235 private_kernel_interface_t *this, chunk_t dst_net,
236 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
237 {
238 if (!this->net)
239 {
240 return NOT_SUPPORTED;
241 }
242 return this->net->add_route(this->net, dst_net, prefixlen, gateway,
243 src_ip, if_name);
244 }
245
246 METHOD(kernel_interface_t, del_route, status_t,
247 private_kernel_interface_t *this, chunk_t dst_net,
248 u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
249 {
250 if (!this->net)
251 {
252 return NOT_SUPPORTED;
253 }
254 return this->net->del_route(this->net, dst_net, prefixlen, gateway,
255 src_ip, if_name);
256 }
257
258 METHOD(kernel_interface_t, bypass_socket, bool,
259 private_kernel_interface_t *this, int fd, int family)
260 {
261 if (!this->ipsec)
262 {
263 return FALSE;
264 }
265 return this->ipsec->bypass_socket(this->ipsec, fd, family);
266 }
267
268 METHOD(kernel_interface_t, get_address_by_ts, status_t,
269 private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip)
270 {
271 enumerator_t *addrs;
272 host_t *host;
273 int family;
274 bool found = FALSE;
275
276 DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
277
278 /* if we have a family which includes localhost, we do not
279 * search for an IP, we use the default */
280 family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6;
281
282 if (family == AF_INET)
283 {
284 host = host_create_from_string("127.0.0.1", 0);
285 }
286 else
287 {
288 host = host_create_from_string("::1", 0);
289 }
290
291 if (ts->includes(ts, host))
292 {
293 *ip = host_create_any(family);
294 host->destroy(host);
295 DBG2(DBG_KNL, "using host %H", *ip);
296 return SUCCESS;
297 }
298 host->destroy(host);
299
300 addrs = create_address_enumerator(this, TRUE, TRUE);
301 while (addrs->enumerate(addrs, (void**)&host))
302 {
303 if (ts->includes(ts, host))
304 {
305 found = TRUE;
306 *ip = host->clone(host);
307 break;
308 }
309 }
310 addrs->destroy(addrs);
311
312 if (!found)
313 {
314 DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
315 return FAILED;
316 }
317
318 DBG2(DBG_KNL, "using host %H", *ip);
319 return SUCCESS;
320 }
321
322
323 METHOD(kernel_interface_t, add_ipsec_interface, void,
324 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
325 {
326 if (!this->ipsec)
327 {
328 this->ipsec = constructor();
329 }
330 }
331
332 METHOD(kernel_interface_t, remove_ipsec_interface, void,
333 private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor)
334 {
335 /* TODO: replace if interface currently in use */
336 }
337
338 METHOD(kernel_interface_t, add_net_interface, void,
339 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
340 {
341 if (!this->net)
342 {
343 this->net = constructor();
344 }
345 }
346
347 METHOD(kernel_interface_t, remove_net_interface, void,
348 private_kernel_interface_t *this, kernel_net_constructor_t constructor)
349 {
350 /* TODO: replace if interface currently in use */
351 }
352
353 METHOD(kernel_interface_t, add_listener, void,
354 private_kernel_interface_t *this, kernel_listener_t *listener)
355 {
356 this->mutex->lock(this->mutex);
357 this->listeners->insert_last(this->listeners, listener);
358 this->mutex->unlock(this->mutex);
359 }
360
361 METHOD(kernel_interface_t, remove_listener, void,
362 private_kernel_interface_t *this, kernel_listener_t *listener)
363 {
364 this->mutex->lock(this->mutex);
365 this->listeners->remove(this->listeners, listener, NULL);
366 this->mutex->unlock(this->mutex);
367 }
368
369 METHOD(kernel_interface_t, acquire, void,
370 private_kernel_interface_t *this, u_int32_t reqid,
371 traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
372 {
373 kernel_listener_t *listener;
374 enumerator_t *enumerator;
375 this->mutex->lock(this->mutex);
376 enumerator = this->listeners->create_enumerator(this->listeners);
377 while (enumerator->enumerate(enumerator, &listener))
378 {
379 if (!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, protocol_id_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(listener, reqid, protocol, spi, hard))
399 {
400 this->listeners->remove_at(this->listeners, enumerator);
401 }
402 }
403 enumerator->destroy(enumerator);
404 this->mutex->unlock(this->mutex);
405 }
406
407 METHOD(kernel_interface_t, mapping, void,
408 private_kernel_interface_t *this, u_int32_t reqid, u_int32_t spi,
409 host_t *remote)
410 {
411 kernel_listener_t *listener;
412 enumerator_t *enumerator;
413 this->mutex->lock(this->mutex);
414 enumerator = this->listeners->create_enumerator(this->listeners);
415 while (enumerator->enumerate(enumerator, &listener))
416 {
417 if (!listener->mapping(listener, reqid, spi, remote))
418 {
419 this->listeners->remove_at(this->listeners, enumerator);
420 }
421 }
422 enumerator->destroy(enumerator);
423 this->mutex->unlock(this->mutex);
424 }
425
426 METHOD(kernel_interface_t, migrate, void,
427 private_kernel_interface_t *this, u_int32_t reqid,
428 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
429 policy_dir_t direction, host_t *local, host_t *remote)
430 {
431 kernel_listener_t *listener;
432 enumerator_t *enumerator;
433 this->mutex->lock(this->mutex);
434 enumerator = this->listeners->create_enumerator(this->listeners);
435 while (enumerator->enumerate(enumerator, &listener))
436 {
437 if (!listener->migrate(listener, reqid, src_ts, dst_ts, direction,
438 local, remote))
439 {
440 this->listeners->remove_at(this->listeners, enumerator);
441 }
442 }
443 enumerator->destroy(enumerator);
444 this->mutex->unlock(this->mutex);
445 }
446
447 static bool call_roam(kernel_listener_t *listener, bool *roam)
448 {
449 return !listener->roam(listener, *roam);
450 }
451
452 METHOD(kernel_interface_t, roam, void,
453 private_kernel_interface_t *this, bool address)
454 {
455 this->mutex->lock(this->mutex);
456 this->listeners->remove(this->listeners, &address, (void*)call_roam);
457 this->mutex->unlock(this->mutex);
458 }
459
460 METHOD(kernel_interface_t, destroy, void,
461 private_kernel_interface_t *this)
462 {
463 DESTROY_IF(this->ipsec);
464 DESTROY_IF(this->net);
465 this->mutex->destroy(this->mutex);
466 this->listeners->destroy(this->listeners);
467 free(this);
468 }
469
470 /*
471 * Described in header-file
472 */
473 kernel_interface_t *kernel_interface_create()
474 {
475 private_kernel_interface_t *this;
476
477 INIT(this,
478 .public = {
479 .get_spi = _get_spi,
480 .get_cpi = _get_cpi,
481 .add_sa = _add_sa,
482 .update_sa = _update_sa,
483 .query_sa = _query_sa,
484 .del_sa = _del_sa,
485 .add_policy = _add_policy,
486 .query_policy = _query_policy,
487 .del_policy = _del_policy,
488 .get_source_addr = _get_source_addr,
489 .get_nexthop = _get_nexthop,
490 .get_interface = _get_interface,
491 .create_address_enumerator = _create_address_enumerator,
492 .add_ip = _add_ip,
493 .del_ip = _del_ip,
494 .add_route = _add_route,
495 .del_route = _del_route,
496 .bypass_socket = _bypass_socket,
497
498 .get_address_by_ts = _get_address_by_ts,
499 .add_ipsec_interface = _add_ipsec_interface,
500 .remove_ipsec_interface = _remove_ipsec_interface,
501 .add_net_interface = _add_net_interface,
502 .remove_net_interface = _remove_net_interface,
503
504 .add_listener = _add_listener,
505 .remove_listener = _remove_listener,
506 .acquire = _acquire,
507 .expire = _expire,
508 .mapping = _mapping,
509 .migrate = _migrate,
510 .roam = _roam,
511 .destroy = _destroy,
512 },
513 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
514 .listeners = linked_list_create(),
515 );
516
517 return &this->public;
518 }
519