Filter ignored interfaces in kernel interfaces (for events, address enumeration,...
[strongswan.git] / src / libhydra / plugins / kernel_pfroute / kernel_pfroute_net.c
1 /*
2 * Copyright (C) 2009-2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <net/if.h>
19 #include <ifaddrs.h>
20 #include <net/route.h>
21 #include <unistd.h>
22 #include <errno.h>
23
24 #include "kernel_pfroute_net.h"
25
26 #include <hydra.h>
27 #include <debug.h>
28 #include <utils/host.h>
29 #include <threading/thread.h>
30 #include <threading/mutex.h>
31 #include <utils/linked_list.h>
32 #include <processing/jobs/callback_job.h>
33
34 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
35 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
36 #endif
37
38 /** delay before firing roam events (ms) */
39 #define ROAM_DELAY 100
40
41 /** buffer size for PF_ROUTE messages */
42 #define PFROUTE_BUFFER_SIZE 4096
43
44 typedef struct addr_entry_t addr_entry_t;
45
46 /**
47 * IP address in an inface_entry_t
48 */
49 struct addr_entry_t {
50
51 /** The ip address */
52 host_t *ip;
53
54 /** virtual IP managed by us */
55 bool virtual;
56
57 /** Number of times this IP is used, if virtual */
58 u_int refcount;
59 };
60
61 /**
62 * destroy a addr_entry_t object
63 */
64 static void addr_entry_destroy(addr_entry_t *this)
65 {
66 this->ip->destroy(this->ip);
67 free(this);
68 }
69
70 typedef struct iface_entry_t iface_entry_t;
71
72 /**
73 * A network interface on this system, containing addr_entry_t's
74 */
75 struct iface_entry_t {
76
77 /** interface index */
78 int ifindex;
79
80 /** name of the interface */
81 char ifname[IFNAMSIZ];
82
83 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
84 u_int flags;
85
86 /** list of addresses as host_t */
87 linked_list_t *addrs;
88
89 /** TRUE if usable by config */
90 bool usable;
91 };
92
93 /**
94 * destroy an interface entry
95 */
96 static void iface_entry_destroy(iface_entry_t *this)
97 {
98 this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
99 free(this);
100 }
101
102 /**
103 * check if an interface is up and usable
104 */
105 static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
106 {
107 return iface->usable && (iface->flags & IFF_UP) == IFF_UP;
108 }
109
110
111 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t;
112
113 /**
114 * Private variables and functions of kernel_pfroute class.
115 */
116 struct private_kernel_pfroute_net_t
117 {
118 /**
119 * Public part of the kernel_pfroute_t object.
120 */
121 kernel_pfroute_net_t public;
122
123 /**
124 * mutex to lock access to various lists
125 */
126 mutex_t *mutex;
127
128 /**
129 * Cached list of interfaces and their addresses (iface_entry_t)
130 */
131 linked_list_t *ifaces;
132
133 /**
134 * mutex to lock access to the PF_ROUTE socket
135 */
136 mutex_t *mutex_pfroute;
137
138 /**
139 * PF_ROUTE socket to communicate with the kernel
140 */
141 int socket;
142
143 /**
144 * PF_ROUTE socket to receive events
145 */
146 int socket_events;
147
148 /**
149 * sequence number for messages sent to the kernel
150 */
151 int seq;
152
153 /**
154 * time of last roam event
155 */
156 timeval_t last_roam;
157 };
158
159 /**
160 * callback function that raises the delayed roam event
161 */
162 static job_requeue_t roam_event(uintptr_t address)
163 {
164 hydra->kernel_interface->roam(hydra->kernel_interface, address != 0);
165 return JOB_REQUEUE_NONE;
166 }
167
168 /**
169 * fire a roaming event. we delay it for a bit and fire only one event
170 * for multiple calls. otherwise we would create too many events.
171 */
172 static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
173 {
174 timeval_t now;
175 job_t *job;
176
177 time_monotonic(&now);
178 if (timercmp(&now, &this->last_roam, >))
179 {
180 now.tv_usec += ROAM_DELAY * 1000;
181 while (now.tv_usec > 1000000)
182 {
183 now.tv_sec++;
184 now.tv_usec -= 1000000;
185 }
186 this->last_roam = now;
187
188 job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
189 (void*)(uintptr_t)(address ? 1 : 0),
190 NULL, NULL);
191 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
192 }
193 }
194
195 /**
196 * Process an RTM_*ADDR message from the kernel
197 */
198 static void process_addr(private_kernel_pfroute_net_t *this,
199 struct rt_msghdr *msg)
200 {
201 struct ifa_msghdr *ifa = (struct ifa_msghdr*)msg;
202 sockaddr_t *sockaddr = (sockaddr_t*)(ifa + 1);
203 host_t *host = NULL;
204 enumerator_t *ifaces, *addrs;
205 iface_entry_t *iface;
206 addr_entry_t *addr;
207 bool found = FALSE, changed = FALSE, roam = FALSE;
208 int i;
209
210 for (i = 1; i < (1 << RTAX_MAX); i <<= 1)
211 {
212 if (ifa->ifam_addrs & i)
213 {
214 if (RTA_IFA & i)
215 {
216 host = host_create_from_sockaddr(sockaddr);
217 break;
218 }
219 sockaddr = (sockaddr_t*)((char*)sockaddr + sockaddr->sa_len);
220 }
221 }
222
223 if (!host)
224 {
225 return;
226 }
227
228 this->mutex->lock(this->mutex);
229 ifaces = this->ifaces->create_enumerator(this->ifaces);
230 while (ifaces->enumerate(ifaces, &iface))
231 {
232 if (iface->ifindex == ifa->ifam_index)
233 {
234 addrs = iface->addrs->create_enumerator(iface->addrs);
235 while (addrs->enumerate(addrs, &addr))
236 {
237 if (host->ip_equals(host, addr->ip))
238 {
239 found = TRUE;
240 if (ifa->ifam_type == RTM_DELADDR)
241 {
242 iface->addrs->remove_at(iface->addrs, addrs);
243 if (!addr->virtual && iface->usable)
244 {
245 changed = TRUE;
246 DBG1(DBG_KNL, "%H disappeared from %s",
247 host, iface->ifname);
248 }
249 addr_entry_destroy(addr);
250 }
251 else if (ifa->ifam_type == RTM_NEWADDR && addr->virtual)
252 {
253 addr->refcount = 1;
254 }
255 }
256 }
257 addrs->destroy(addrs);
258
259 if (!found && ifa->ifam_type == RTM_NEWADDR)
260 {
261 changed = TRUE;
262 addr = malloc_thing(addr_entry_t);
263 addr->ip = host->clone(host);
264 addr->virtual = FALSE;
265 addr->refcount = 1;
266 iface->addrs->insert_last(iface->addrs, addr);
267 if (iface->usable)
268 {
269 DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
270 }
271 }
272
273 if (changed && iface_entry_up_and_usable(iface))
274 {
275 roam = TRUE;
276 }
277 break;
278 }
279 }
280 ifaces->destroy(ifaces);
281 this->mutex->unlock(this->mutex);
282 host->destroy(host);
283
284 if (roam)
285 {
286 fire_roam_event(this, TRUE);
287 }
288 }
289
290 /**
291 * Process an RTM_IFINFO message from the kernel
292 */
293 static void process_link(private_kernel_pfroute_net_t *this,
294 struct rt_msghdr *hdr)
295 {
296 struct if_msghdr *msg = (struct if_msghdr*)hdr;
297 enumerator_t *enumerator;
298 iface_entry_t *iface;
299 bool roam = FALSE;
300
301 this->mutex->lock(this->mutex);
302 enumerator = this->ifaces->create_enumerator(this->ifaces);
303 while (enumerator->enumerate(enumerator, &iface))
304 {
305 if (iface->ifindex == msg->ifm_index)
306 {
307 if (iface->usable)
308 {
309 if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP))
310 {
311 roam = TRUE;
312 DBG1(DBG_KNL, "interface %s activated", iface->ifname);
313 }
314 else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP))
315 {
316 roam = TRUE;
317 DBG1(DBG_KNL, "interface %s deactivated", iface->ifname);
318 }
319 }
320 iface->flags = msg->ifm_flags;
321 break;
322 }
323 }
324 enumerator->destroy(enumerator);
325 this->mutex->unlock(this->mutex);
326
327 if (roam)
328 {
329 fire_roam_event(this, TRUE);
330 }
331 }
332
333 /**
334 * Process an RTM_*ROUTE message from the kernel
335 */
336 static void process_route(private_kernel_pfroute_net_t *this,
337 struct rt_msghdr *msg)
338 {
339
340 }
341
342 /**
343 * Receives events from kernel
344 */
345 static job_requeue_t receive_events(private_kernel_pfroute_net_t *this)
346 {
347 unsigned char buf[PFROUTE_BUFFER_SIZE];
348 struct rt_msghdr *msg = (struct rt_msghdr*)buf;
349 int len;
350 bool oldstate;
351
352 oldstate = thread_cancelability(TRUE);
353 len = recvfrom(this->socket_events, buf, sizeof(buf), 0, NULL, 0);
354 thread_cancelability(oldstate);
355
356 if (len < 0)
357 {
358 switch (errno)
359 {
360 case EINTR:
361 /* interrupted, try again */
362 return JOB_REQUEUE_DIRECT;
363 case EAGAIN:
364 /* no data ready, select again */
365 return JOB_REQUEUE_DIRECT;
366 default:
367 DBG1(DBG_KNL, "unable to receive from PF_ROUTE event socket");
368 sleep(1);
369 return JOB_REQUEUE_FAIR;
370 }
371 }
372
373 if (len < sizeof(msg->rtm_msglen) || len < msg->rtm_msglen ||
374 msg->rtm_version != RTM_VERSION)
375 {
376 DBG2(DBG_KNL, "received corrupted PF_ROUTE message");
377 return JOB_REQUEUE_DIRECT;
378 }
379
380 switch (msg->rtm_type)
381 {
382 case RTM_NEWADDR:
383 case RTM_DELADDR:
384 process_addr(this, msg);
385 break;
386 case RTM_IFINFO:
387 /*case RTM_IFANNOUNCE <- what about this*/
388 process_link(this, msg);
389 break;
390 case RTM_ADD:
391 case RTM_DELETE:
392 process_route(this, msg);
393 default:
394 break;
395 }
396
397 return JOB_REQUEUE_DIRECT;
398 }
399
400
401 /** enumerator over addresses */
402 typedef struct {
403 private_kernel_pfroute_net_t* this;
404 /** whether to enumerate down interfaces */
405 bool include_down_ifaces;
406 /** whether to enumerate virtual ip addresses */
407 bool include_virtual_ips;
408 /** whether to enumerate loopback interfaces */
409 bool include_loopback;
410 } address_enumerator_t;
411
412 /**
413 * cleanup function for address enumerator
414 */
415 static void address_enumerator_destroy(address_enumerator_t *data)
416 {
417 data->this->mutex->unlock(data->this->mutex);
418 free(data);
419 }
420
421 /**
422 * filter for addresses
423 */
424 static bool filter_addresses(address_enumerator_t *data,
425 addr_entry_t** in, host_t** out)
426 {
427 host_t *ip;
428 if (!data->include_virtual_ips && (*in)->virtual)
429 { /* skip virtual interfaces added by us */
430 return FALSE;
431 }
432 ip = (*in)->ip;
433 if (ip->get_family(ip) == AF_INET6)
434 {
435 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
436 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
437 { /* skip addresses with a unusable scope */
438 return FALSE;
439 }
440 }
441 *out = ip;
442 return TRUE;
443 }
444
445 /**
446 * enumerator constructor for interfaces
447 */
448 static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
449 address_enumerator_t *data)
450 {
451 return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
452 (void*)filter_addresses, data, NULL);
453 }
454
455 /**
456 * filter for interfaces
457 */
458 static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
459 iface_entry_t** out)
460 {
461 if (!(*in)->usable)
462 { /* skip interfaces excluded by config */
463 return FALSE;
464 }
465 if (!data->include_loopback && ((*in)->flags & IFF_LOOPBACK))
466 { /* ignore loopback devices */
467 return FALSE;
468 }
469 if (!data->include_down_ifaces && !((*in)->flags & IFF_UP))
470 { /* skip interfaces not up */
471 return FALSE;
472 }
473 *out = *in;
474 return TRUE;
475 }
476
477 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
478 private_kernel_pfroute_net_t *this,
479 bool include_down_ifaces, bool include_virtual_ips, bool include_loopback)
480 {
481 address_enumerator_t *data = malloc_thing(address_enumerator_t);
482 data->this = this;
483 data->include_down_ifaces = include_down_ifaces;
484 data->include_virtual_ips = include_virtual_ips;
485 data->include_loopback = include_loopback;
486
487 this->mutex->lock(this->mutex);
488 return enumerator_create_nested(
489 enumerator_create_filter(
490 this->ifaces->create_enumerator(this->ifaces),
491 (void*)filter_interfaces, data, NULL),
492 (void*)create_iface_enumerator, data,
493 (void*)address_enumerator_destroy);
494 }
495
496 METHOD(kernel_net_t, get_interface_name, bool,
497 private_kernel_pfroute_net_t *this, host_t* ip, char **name)
498 {
499 enumerator_t *ifaces, *addrs;
500 iface_entry_t *iface;
501 addr_entry_t *addr;
502 bool found = FALSE, ignored = FALSE;
503
504 if (ip->is_anyaddr(ip))
505 {
506 return FALSE;
507 }
508
509 this->mutex->lock(this->mutex);
510 ifaces = this->ifaces->create_enumerator(this->ifaces);
511 while (ifaces->enumerate(ifaces, &iface))
512 {
513 addrs = iface->addrs->create_enumerator(iface->addrs);
514 while (addrs->enumerate(addrs, &addr))
515 {
516 if (ip->ip_equals(ip, addr->ip))
517 {
518 found = TRUE;
519 if (!iface->usable)
520 {
521 ignored = TRUE;
522 break;
523 }
524 if (name)
525 {
526 *name = strdup(iface->ifname);
527 }
528 break;
529 }
530 }
531 addrs->destroy(addrs);
532 if (found)
533 {
534 break;
535 }
536 }
537 ifaces->destroy(ifaces);
538 this->mutex->unlock(this->mutex);
539
540 if (!ignored)
541 {
542 if (!found)
543 {
544 DBG2(DBG_KNL, "%H is not a local address", ip);
545 }
546 else if (name)
547 {
548 DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
549 }
550 }
551 return found && !ignored;
552 }
553
554 METHOD(kernel_net_t, get_source_addr, host_t*,
555 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
556 {
557 return NULL;
558 }
559
560 METHOD(kernel_net_t, get_nexthop, host_t*,
561 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
562 {
563 return NULL;
564 }
565
566 METHOD(kernel_net_t, add_ip, status_t,
567 private_kernel_pfroute_net_t *this, host_t *virtual_ip, host_t *iface_ip)
568 {
569 return FAILED;
570 }
571
572 METHOD(kernel_net_t, del_ip, status_t,
573 private_kernel_pfroute_net_t *this, host_t *virtual_ip)
574 {
575 return FAILED;
576 }
577
578 METHOD(kernel_net_t, add_route, status_t,
579 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
580 host_t *gateway, host_t *src_ip, char *if_name)
581 {
582 return FAILED;
583 }
584
585 METHOD(kernel_net_t, del_route, status_t,
586 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
587 host_t *gateway, host_t *src_ip, char *if_name)
588 {
589 return FAILED;
590 }
591
592 /**
593 * Initialize a list of local addresses.
594 */
595 static status_t init_address_list(private_kernel_pfroute_net_t *this)
596 {
597 struct ifaddrs *ifap, *ifa;
598 iface_entry_t *iface, *current;
599 addr_entry_t *addr;
600 enumerator_t *ifaces, *addrs;
601
602 DBG2(DBG_KNL, "known interfaces and IP addresses:");
603
604 if (getifaddrs(&ifap) < 0)
605 {
606 DBG1(DBG_KNL, " failed to get interfaces!");
607 return FAILED;
608 }
609
610 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
611 {
612 if (ifa->ifa_addr == NULL)
613 {
614 continue;
615 }
616 switch(ifa->ifa_addr->sa_family)
617 {
618 case AF_LINK:
619 case AF_INET:
620 case AF_INET6:
621 {
622 iface = NULL;
623 ifaces = this->ifaces->create_enumerator(this->ifaces);
624 while (ifaces->enumerate(ifaces, &current))
625 {
626 if (streq(current->ifname, ifa->ifa_name))
627 {
628 iface = current;
629 break;
630 }
631 }
632 ifaces->destroy(ifaces);
633
634 if (!iface)
635 {
636 iface = malloc_thing(iface_entry_t);
637 memcpy(iface->ifname, ifa->ifa_name, IFNAMSIZ);
638 iface->ifindex = if_nametoindex(ifa->ifa_name);
639 iface->flags = ifa->ifa_flags;
640 iface->addrs = linked_list_create();
641 iface->usable = hydra->kernel_interface->is_interface_usable(
642 hydra->kernel_interface, ifa->ifa_name);
643 this->ifaces->insert_last(this->ifaces, iface);
644 }
645
646 if (ifa->ifa_addr->sa_family != AF_LINK)
647 {
648 addr = malloc_thing(addr_entry_t);
649 addr->ip = host_create_from_sockaddr(ifa->ifa_addr);
650 addr->virtual = FALSE;
651 addr->refcount = 1;
652 iface->addrs->insert_last(iface->addrs, addr);
653 }
654 }
655 }
656 }
657 freeifaddrs(ifap);
658
659 ifaces = this->ifaces->create_enumerator(this->ifaces);
660 while (ifaces->enumerate(ifaces, &iface))
661 {
662 if (iface->usable && iface->flags & IFF_UP)
663 {
664 DBG2(DBG_KNL, " %s", iface->ifname);
665 addrs = iface->addrs->create_enumerator(iface->addrs);
666 while (addrs->enumerate(addrs, (void**)&addr))
667 {
668 DBG2(DBG_KNL, " %H", addr->ip);
669 }
670 addrs->destroy(addrs);
671 }
672 }
673 ifaces->destroy(ifaces);
674
675 return SUCCESS;
676 }
677
678 METHOD(kernel_net_t, destroy, void,
679 private_kernel_pfroute_net_t *this)
680 {
681 if (this->socket > 0)
682 {
683 close(this->socket);
684 }
685 if (this->socket_events)
686 {
687 close(this->socket_events);
688 }
689 this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
690 this->mutex->destroy(this->mutex);
691 this->mutex_pfroute->destroy(this->mutex_pfroute);
692 free(this);
693 }
694
695 /*
696 * Described in header.
697 */
698 kernel_pfroute_net_t *kernel_pfroute_net_create()
699 {
700 private_kernel_pfroute_net_t *this;
701 bool register_for_events = TRUE;
702
703 INIT(this,
704 .public = {
705 .interface = {
706 .get_interface = _get_interface_name,
707 .create_address_enumerator = _create_address_enumerator,
708 .get_source_addr = _get_source_addr,
709 .get_nexthop = _get_nexthop,
710 .add_ip = _add_ip,
711 .del_ip = _del_ip,
712 .add_route = _add_route,
713 .del_route = _del_route,
714 .destroy = _destroy,
715 },
716 },
717 .ifaces = linked_list_create(),
718 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
719 .mutex_pfroute = mutex_create(MUTEX_TYPE_DEFAULT),
720 );
721
722 if (streq(hydra->daemon, "starter"))
723 { /* starter has no threads, so we do not register for kernel events */
724 register_for_events = FALSE;
725 }
726
727 /* create a PF_ROUTE socket to communicate with the kernel */
728 this->socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
729 if (this->socket < 0)
730 {
731 DBG1(DBG_KNL, "unable to create PF_ROUTE socket");
732 destroy(this);
733 return NULL;
734 }
735
736 if (register_for_events)
737 {
738 /* create a PF_ROUTE socket to receive events */
739 this->socket_events = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
740 if (this->socket_events < 0)
741 {
742 DBG1(DBG_KNL, "unable to create PF_ROUTE event socket");
743 destroy(this);
744 return NULL;
745 }
746
747 lib->processor->queue_job(lib->processor,
748 (job_t*)callback_job_create_with_prio(
749 (callback_job_cb_t)receive_events, this, NULL,
750 (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
751 }
752
753 if (init_address_list(this) != SUCCESS)
754 {
755 DBG1(DBG_KNL, "unable to get interface list");
756 destroy(this);
757 return NULL;
758 }
759
760 return &this->public;
761 }