2 * Copyright (C) 2009-2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
16 #include <sys/types.h>
17 #include <sys/socket.h>
20 #include <net/route.h>
24 #include "kernel_pfroute_net.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>
34 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
35 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
38 /** delay before firing roam events (ms) */
39 #define ROAM_DELAY 100
41 /** buffer size for PF_ROUTE messages */
42 #define PFROUTE_BUFFER_SIZE 4096
44 typedef struct addr_entry_t addr_entry_t
;
47 * IP address in an inface_entry_t
54 /** virtual IP managed by us */
57 /** Number of times this IP is used, if virtual */
62 * destroy a addr_entry_t object
64 static void addr_entry_destroy(addr_entry_t
*this)
66 this->ip
->destroy(this->ip
);
70 typedef struct iface_entry_t iface_entry_t
;
73 * A network interface on this system, containing addr_entry_t's
75 struct iface_entry_t
{
77 /** interface index */
80 /** name of the interface */
81 char ifname
[IFNAMSIZ
];
83 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
86 /** list of addresses as host_t */
89 /** TRUE if usable by config */
94 * destroy an interface entry
96 static void iface_entry_destroy(iface_entry_t
*this)
98 this->addrs
->destroy_function(this->addrs
, (void*)addr_entry_destroy
);
103 * check if an interface is up and usable
105 static inline bool iface_entry_up_and_usable(iface_entry_t
*iface
)
107 return iface
->usable
&& (iface
->flags
& IFF_UP
) == IFF_UP
;
111 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t
;
114 * Private variables and functions of kernel_pfroute class.
116 struct private_kernel_pfroute_net_t
119 * Public part of the kernel_pfroute_t object.
121 kernel_pfroute_net_t
public;
124 * mutex to lock access to various lists
129 * Cached list of interfaces and their addresses (iface_entry_t)
131 linked_list_t
*ifaces
;
134 * mutex to lock access to the PF_ROUTE socket
136 mutex_t
*mutex_pfroute
;
139 * PF_ROUTE socket to communicate with the kernel
144 * PF_ROUTE socket to receive events
149 * sequence number for messages sent to the kernel
154 * time of last roam event
160 * callback function that raises the delayed roam event
162 static job_requeue_t
roam_event(uintptr_t address
)
164 hydra
->kernel_interface
->roam(hydra
->kernel_interface
, address
!= 0);
165 return JOB_REQUEUE_NONE
;
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.
172 static void fire_roam_event(private_kernel_pfroute_net_t
*this, bool address
)
177 time_monotonic(&now
);
178 if (timercmp(&now
, &this->last_roam
, >))
180 now
.tv_usec
+= ROAM_DELAY
* 1000;
181 while (now
.tv_usec
> 1000000)
184 now
.tv_usec
-= 1000000;
186 this->last_roam
= now
;
188 job
= (job_t
*)callback_job_create((callback_job_cb_t
)roam_event
,
189 (void*)(uintptr_t)(address ?
1 : 0),
191 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, job
, ROAM_DELAY
);
196 * Process an RTM_*ADDR message from the kernel
198 static void process_addr(private_kernel_pfroute_net_t
*this,
199 struct rt_msghdr
*msg
)
201 struct ifa_msghdr
*ifa
= (struct ifa_msghdr
*)msg
;
202 sockaddr_t
*sockaddr
= (sockaddr_t
*)(ifa
+ 1);
204 enumerator_t
*ifaces
, *addrs
;
205 iface_entry_t
*iface
;
207 bool found
= FALSE
, changed
= FALSE
, roam
= FALSE
;
210 for (i
= 1; i
< (1 << RTAX_MAX
); i
<<= 1)
212 if (ifa
->ifam_addrs
& i
)
216 host
= host_create_from_sockaddr(sockaddr
);
219 sockaddr
= (sockaddr_t
*)((char*)sockaddr
+ sockaddr
->sa_len
);
228 this->mutex
->lock(this->mutex
);
229 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
230 while (ifaces
->enumerate(ifaces
, &iface
))
232 if (iface
->ifindex
== ifa
->ifam_index
)
234 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
235 while (addrs
->enumerate(addrs
, &addr
))
237 if (host
->ip_equals(host
, addr
->ip
))
240 if (ifa
->ifam_type
== RTM_DELADDR
)
242 iface
->addrs
->remove_at(iface
->addrs
, addrs
);
243 if (!addr
->virtual && iface
->usable
)
246 DBG1(DBG_KNL
, "%H disappeared from %s",
247 host
, iface
->ifname
);
249 addr_entry_destroy(addr
);
251 else if (ifa
->ifam_type
== RTM_NEWADDR
&& addr
->virtual)
257 addrs
->destroy(addrs
);
259 if (!found
&& ifa
->ifam_type
== RTM_NEWADDR
)
262 addr
= malloc_thing(addr_entry_t
);
263 addr
->ip
= host
->clone(host
);
264 addr
->virtual = FALSE
;
266 iface
->addrs
->insert_last(iface
->addrs
, addr
);
269 DBG1(DBG_KNL
, "%H appeared on %s", host
, iface
->ifname
);
273 if (changed
&& iface_entry_up_and_usable(iface
))
280 ifaces
->destroy(ifaces
);
281 this->mutex
->unlock(this->mutex
);
286 fire_roam_event(this, TRUE
);
291 * Process an RTM_IFINFO message from the kernel
293 static void process_link(private_kernel_pfroute_net_t
*this,
294 struct rt_msghdr
*hdr
)
296 struct if_msghdr
*msg
= (struct if_msghdr
*)hdr
;
297 enumerator_t
*enumerator
;
298 iface_entry_t
*iface
;
301 this->mutex
->lock(this->mutex
);
302 enumerator
= this->ifaces
->create_enumerator(this->ifaces
);
303 while (enumerator
->enumerate(enumerator
, &iface
))
305 if (iface
->ifindex
== msg
->ifm_index
)
309 if (!(iface
->flags
& IFF_UP
) && (msg
->ifm_flags
& IFF_UP
))
312 DBG1(DBG_KNL
, "interface %s activated", iface
->ifname
);
314 else if ((iface
->flags
& IFF_UP
) && !(msg
->ifm_flags
& IFF_UP
))
317 DBG1(DBG_KNL
, "interface %s deactivated", iface
->ifname
);
320 iface
->flags
= msg
->ifm_flags
;
324 enumerator
->destroy(enumerator
);
325 this->mutex
->unlock(this->mutex
);
329 fire_roam_event(this, TRUE
);
334 * Process an RTM_*ROUTE message from the kernel
336 static void process_route(private_kernel_pfroute_net_t
*this,
337 struct rt_msghdr
*msg
)
343 * Receives events from kernel
345 static job_requeue_t
receive_events(private_kernel_pfroute_net_t
*this)
347 unsigned char buf
[PFROUTE_BUFFER_SIZE
];
348 struct rt_msghdr
*msg
= (struct rt_msghdr
*)buf
;
352 oldstate
= thread_cancelability(TRUE
);
353 len
= recvfrom(this->socket_events
, buf
, sizeof(buf
), 0, NULL
, 0);
354 thread_cancelability(oldstate
);
361 /* interrupted, try again */
362 return JOB_REQUEUE_DIRECT
;
364 /* no data ready, select again */
365 return JOB_REQUEUE_DIRECT
;
367 DBG1(DBG_KNL
, "unable to receive from PF_ROUTE event socket");
369 return JOB_REQUEUE_FAIR
;
373 if (len
< sizeof(msg
->rtm_msglen
) || len
< msg
->rtm_msglen
||
374 msg
->rtm_version
!= RTM_VERSION
)
376 DBG2(DBG_KNL
, "received corrupted PF_ROUTE message");
377 return JOB_REQUEUE_DIRECT
;
380 switch (msg
->rtm_type
)
384 process_addr(this, msg
);
387 /*case RTM_IFANNOUNCE <- what about this*/
388 process_link(this, msg
);
392 process_route(this, msg
);
397 return JOB_REQUEUE_DIRECT
;
401 /** enumerator over addresses */
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
;
413 * cleanup function for address enumerator
415 static void address_enumerator_destroy(address_enumerator_t
*data
)
417 data
->this->mutex
->unlock(data
->this->mutex
);
422 * filter for addresses
424 static bool filter_addresses(address_enumerator_t
*data
,
425 addr_entry_t
** in
, host_t
** out
)
428 if (!data
->include_virtual_ips
&& (*in
)->virtual)
429 { /* skip virtual interfaces added by us */
433 if (ip
->get_family(ip
) == AF_INET6
)
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 */
446 * enumerator constructor for interfaces
448 static enumerator_t
*create_iface_enumerator(iface_entry_t
*iface
,
449 address_enumerator_t
*data
)
451 return enumerator_create_filter(iface
->addrs
->create_enumerator(iface
->addrs
),
452 (void*)filter_addresses
, data
, NULL
);
456 * filter for interfaces
458 static bool filter_interfaces(address_enumerator_t
*data
, iface_entry_t
** in
,
462 { /* skip interfaces excluded by config */
465 if (!data
->include_loopback
&& ((*in
)->flags
& IFF_LOOPBACK
))
466 { /* ignore loopback devices */
469 if (!data
->include_down_ifaces
&& !((*in
)->flags
& IFF_UP
))
470 { /* skip interfaces not up */
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
)
481 address_enumerator_t
*data
= malloc_thing(address_enumerator_t
);
483 data
->include_down_ifaces
= include_down_ifaces
;
484 data
->include_virtual_ips
= include_virtual_ips
;
485 data
->include_loopback
= include_loopback
;
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
);
496 METHOD(kernel_net_t
, get_interface_name
, bool,
497 private_kernel_pfroute_net_t
*this, host_t
* ip
, char **name
)
499 enumerator_t
*ifaces
, *addrs
;
500 iface_entry_t
*iface
;
502 bool found
= FALSE
, ignored
= FALSE
;
504 if (ip
->is_anyaddr(ip
))
509 this->mutex
->lock(this->mutex
);
510 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
511 while (ifaces
->enumerate(ifaces
, &iface
))
513 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
514 while (addrs
->enumerate(addrs
, &addr
))
516 if (ip
->ip_equals(ip
, addr
->ip
))
526 *name
= strdup(iface
->ifname
);
531 addrs
->destroy(addrs
);
537 ifaces
->destroy(ifaces
);
538 this->mutex
->unlock(this->mutex
);
544 DBG2(DBG_KNL
, "%H is not a local address", ip
);
548 DBG2(DBG_KNL
, "%H is on interface %s", ip
, *name
);
551 return found
&& !ignored
;
554 METHOD(kernel_net_t
, get_source_addr
, host_t
*,
555 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
560 METHOD(kernel_net_t
, get_nexthop
, host_t
*,
561 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
566 METHOD(kernel_net_t
, add_ip
, status_t
,
567 private_kernel_pfroute_net_t
*this, host_t
*virtual_ip
, host_t
*iface_ip
)
572 METHOD(kernel_net_t
, del_ip
, status_t
,
573 private_kernel_pfroute_net_t
*this, host_t
*virtual_ip
)
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
)
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
)
593 * Initialize a list of local addresses.
595 static status_t
init_address_list(private_kernel_pfroute_net_t
*this)
597 struct ifaddrs
*ifap
, *ifa
;
598 iface_entry_t
*iface
, *current
;
600 enumerator_t
*ifaces
, *addrs
;
602 DBG2(DBG_KNL
, "known interfaces and IP addresses:");
604 if (getifaddrs(&ifap
) < 0)
606 DBG1(DBG_KNL
, " failed to get interfaces!");
610 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
612 if (ifa
->ifa_addr
== NULL
)
616 switch(ifa
->ifa_addr
->sa_family
)
623 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
624 while (ifaces
->enumerate(ifaces
, ¤t
))
626 if (streq(current
->ifname
, ifa
->ifa_name
))
632 ifaces
->destroy(ifaces
);
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
);
646 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
648 addr
= malloc_thing(addr_entry_t
);
649 addr
->ip
= host_create_from_sockaddr(ifa
->ifa_addr
);
650 addr
->virtual = FALSE
;
652 iface
->addrs
->insert_last(iface
->addrs
, addr
);
659 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
660 while (ifaces
->enumerate(ifaces
, &iface
))
662 if (iface
->usable
&& iface
->flags
& IFF_UP
)
664 DBG2(DBG_KNL
, " %s", iface
->ifname
);
665 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
666 while (addrs
->enumerate(addrs
, (void**)&addr
))
668 DBG2(DBG_KNL
, " %H", addr
->ip
);
670 addrs
->destroy(addrs
);
673 ifaces
->destroy(ifaces
);
678 METHOD(kernel_net_t
, destroy
, void,
679 private_kernel_pfroute_net_t
*this)
681 if (this->socket
> 0)
685 if (this->socket_events
)
687 close(this->socket_events
);
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
);
696 * Described in header.
698 kernel_pfroute_net_t
*kernel_pfroute_net_create()
700 private_kernel_pfroute_net_t
*this;
701 bool register_for_events
= TRUE
;
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
,
712 .add_route
= _add_route
,
713 .del_route
= _del_route
,
717 .ifaces
= linked_list_create(),
718 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
719 .mutex_pfroute
= mutex_create(MUTEX_TYPE_DEFAULT
),
722 if (streq(hydra
->daemon
, "starter"))
723 { /* starter has no threads, so we do not register for kernel events */
724 register_for_events
= FALSE
;
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)
731 DBG1(DBG_KNL
, "unable to create PF_ROUTE socket");
736 if (register_for_events
)
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)
742 DBG1(DBG_KNL
, "unable to create PF_ROUTE event socket");
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
));
753 if (init_address_list(this) != SUCCESS
)
755 DBG1(DBG_KNL
, "unable to get interface list");
760 return &this->public;