2 * Copyright (C) 2009 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 */
91 * destroy an interface entry
93 static void iface_entry_destroy(iface_entry_t
*this)
95 this->addrs
->destroy_function(this->addrs
, (void*)addr_entry_destroy
);
100 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t
;
103 * Private variables and functions of kernel_pfroute class.
105 struct private_kernel_pfroute_net_t
108 * Public part of the kernel_pfroute_t object.
110 kernel_pfroute_net_t
public;
113 * mutex to lock access to various lists
118 * Cached list of interfaces and their addresses (iface_entry_t)
120 linked_list_t
*ifaces
;
123 * job receiving PF_ROUTE events
128 * mutex to lock access to the PF_ROUTE socket
130 mutex_t
*mutex_pfroute
;
133 * PF_ROUTE socket to communicate with the kernel
138 * PF_ROUTE socket to receive events
143 * sequence number for messages sent to the kernel
148 * time of last roam event
154 * callback function that raises the delayed roam event
156 static job_requeue_t
roam_event(uintptr_t address
)
158 charon
->kernel_interface
->roam(charon
->kernel_interface
, address
!= 0);
159 return JOB_REQUEUE_NONE
;
163 * fire a roaming event. we delay it for a bit and fire only one event
164 * for multiple calls. otherwise we would create too many events.
166 static void fire_roam_event(private_kernel_pfroute_net_t
*this, bool address
)
171 time_monotonic(&now
);
172 if (timercmp(&now
, &this->last_roam
, >))
174 now
.tv_usec
+= ROAM_DELAY
* 1000;
175 while (now
.tv_usec
> 1000000)
178 now
.tv_usec
-= 1000000;
180 this->last_roam
= now
;
182 job
= (job_t
*)callback_job_create((callback_job_cb_t
)roam_event
,
183 (void*)(uintptr_t)(address ?
1 : 0),
185 hydra
->scheduler
->schedule_job_ms(hydra
->scheduler
, job
, ROAM_DELAY
);
190 * Process an RTM_*ADDR message from the kernel
192 static void process_addr(private_kernel_pfroute_net_t
*this,
193 struct rt_msghdr
*msg
)
195 struct ifa_msghdr
*ifa
= (struct ifa_msghdr
*)msg
;
196 sockaddr_t
*sockaddr
= (sockaddr_t
*)(ifa
+ 1);
198 enumerator_t
*ifaces
, *addrs
;
199 iface_entry_t
*iface
;
201 bool found
= FALSE
, changed
= FALSE
, roam
= FALSE
;
204 for (i
= 1; i
< (1 << RTAX_MAX
); i
<<= 1)
206 if (ifa
->ifam_addrs
& i
)
210 host
= host_create_from_sockaddr(sockaddr
);
213 sockaddr
= (sockaddr_t
*)((char*)sockaddr
+ sockaddr
->sa_len
);
222 this->mutex
->lock(this->mutex
);
223 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
224 while (ifaces
->enumerate(ifaces
, &iface
))
226 if (iface
->ifindex
== ifa
->ifam_index
)
228 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
229 while (addrs
->enumerate(addrs
, &addr
))
231 if (host
->ip_equals(host
, addr
->ip
))
234 if (ifa
->ifam_type
== RTM_DELADDR
)
236 iface
->addrs
->remove_at(iface
->addrs
, addrs
);
240 DBG1(DBG_KNL
, "%H disappeared from %s",
241 host
, iface
->ifname
);
243 addr_entry_destroy(addr
);
245 else if (ifa
->ifam_type
== RTM_NEWADDR
&& addr
->virtual)
251 addrs
->destroy(addrs
);
253 if (!found
&& ifa
->ifam_type
== RTM_NEWADDR
)
256 addr
= malloc_thing(addr_entry_t
);
257 addr
->ip
= host
->clone(host
);
258 addr
->virtual = FALSE
;
260 iface
->addrs
->insert_last(iface
->addrs
, addr
);
261 DBG1(DBG_KNL
, "%H appeared on %s", host
, iface
->ifname
);
264 if (changed
&& (iface
->flags
& IFF_UP
))
271 ifaces
->destroy(ifaces
);
272 this->mutex
->unlock(this->mutex
);
277 fire_roam_event(this, TRUE
);
282 * Process an RTM_IFINFO message from the kernel
284 static void process_link(private_kernel_pfroute_net_t
*this,
285 struct rt_msghdr
*hdr
)
287 struct if_msghdr
*msg
= (struct if_msghdr
*)hdr
;
288 enumerator_t
*enumerator
;
289 iface_entry_t
*iface
;
292 if (msg
->ifm_flags
& IFF_LOOPBACK
)
293 { /* ignore loopback interfaces */
297 this->mutex
->lock(this->mutex
);
298 enumerator
= this->ifaces
->create_enumerator(this->ifaces
);
299 while (enumerator
->enumerate(enumerator
, &iface
))
301 if (iface
->ifindex
== msg
->ifm_index
)
303 if (!(iface
->flags
& IFF_UP
) && (msg
->ifm_flags
& IFF_UP
))
306 DBG1(DBG_KNL
, "interface %s activated", iface
->ifname
);
308 else if ((iface
->flags
& IFF_UP
) && !(msg
->ifm_flags
& IFF_UP
))
311 DBG1(DBG_KNL
, "interface %s deactivated", iface
->ifname
);
313 iface
->flags
= msg
->ifm_flags
;
317 enumerator
->destroy(enumerator
);
318 this->mutex
->unlock(this->mutex
);
322 fire_roam_event(this, TRUE
);
327 * Process an RTM_*ROUTE message from the kernel
329 static void process_route(private_kernel_pfroute_net_t
*this,
330 struct rt_msghdr
*msg
)
336 * Receives events from kernel
338 static job_requeue_t
receive_events(private_kernel_pfroute_net_t
*this)
340 unsigned char buf
[PFROUTE_BUFFER_SIZE
];
341 struct rt_msghdr
*msg
= (struct rt_msghdr
*)buf
;
345 oldstate
= thread_cancelability(TRUE
);
346 len
= recvfrom(this->socket_events
, buf
, sizeof(buf
), 0, NULL
, 0);
347 thread_cancelability(oldstate
);
354 /* interrupted, try again */
355 return JOB_REQUEUE_DIRECT
;
357 /* no data ready, select again */
358 return JOB_REQUEUE_DIRECT
;
360 DBG1(DBG_KNL
, "unable to receive from PF_ROUTE event socket");
362 return JOB_REQUEUE_FAIR
;
366 if (len
< sizeof(msg
->rtm_msglen
) || len
< msg
->rtm_msglen
||
367 msg
->rtm_version
!= RTM_VERSION
)
369 DBG2(DBG_KNL
, "received corrupted PF_ROUTE message");
370 return JOB_REQUEUE_DIRECT
;
373 switch (msg
->rtm_type
)
377 process_addr(this, msg
);
380 /*case RTM_IFANNOUNCE <- what about this*/
381 process_link(this, msg
);
385 process_route(this, msg
);
390 return JOB_REQUEUE_DIRECT
;
394 /** enumerator over addresses */
396 private_kernel_pfroute_net_t
* this;
397 /** whether to enumerate down interfaces */
398 bool include_down_ifaces
;
399 /** whether to enumerate virtual ip addresses */
400 bool include_virtual_ips
;
401 } address_enumerator_t
;
404 * cleanup function for address enumerator
406 static void address_enumerator_destroy(address_enumerator_t
*data
)
408 data
->this->mutex
->unlock(data
->this->mutex
);
413 * filter for addresses
415 static bool filter_addresses(address_enumerator_t
*data
, addr_entry_t
** in
, host_t
** out
)
418 if (!data
->include_virtual_ips
&& (*in
)->virtual)
419 { /* skip virtual interfaces added by us */
423 if (ip
->get_family(ip
) == AF_INET6
)
425 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ip
->get_sockaddr(ip
);
426 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
427 { /* skip addresses with a unusable scope */
436 * enumerator constructor for interfaces
438 static enumerator_t
*create_iface_enumerator(iface_entry_t
*iface
, address_enumerator_t
*data
)
440 return enumerator_create_filter(iface
->addrs
->create_enumerator(iface
->addrs
),
441 (void*)filter_addresses
, data
, NULL
);
445 * filter for interfaces
447 static bool filter_interfaces(address_enumerator_t
*data
, iface_entry_t
** in
, iface_entry_t
** out
)
449 if (!data
->include_down_ifaces
&& !((*in
)->flags
& IFF_UP
))
450 { /* skip interfaces not up */
458 * implementation of kernel_net_t.create_address_enumerator
460 static enumerator_t
*create_address_enumerator(private_kernel_pfroute_net_t
*this,
461 bool include_down_ifaces
, bool include_virtual_ips
)
463 address_enumerator_t
*data
= malloc_thing(address_enumerator_t
);
465 data
->include_down_ifaces
= include_down_ifaces
;
466 data
->include_virtual_ips
= include_virtual_ips
;
468 this->mutex
->lock(this->mutex
);
469 return enumerator_create_nested(
470 enumerator_create_filter(this->ifaces
->create_enumerator(this->ifaces
),
471 (void*)filter_interfaces
, data
, NULL
),
472 (void*)create_iface_enumerator
, data
, (void*)address_enumerator_destroy
);
476 * implementation of kernel_net_t.get_interface_name
478 static char *get_interface_name(private_kernel_pfroute_net_t
*this, host_t
* ip
)
480 enumerator_t
*ifaces
, *addrs
;
481 iface_entry_t
*iface
;
485 DBG2(DBG_KNL
, "getting interface name for %H", ip
);
487 this->mutex
->lock(this->mutex
);
488 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
489 while (ifaces
->enumerate(ifaces
, &iface
))
491 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
492 while (addrs
->enumerate(addrs
, &addr
))
494 if (ip
->ip_equals(ip
, addr
->ip
))
496 name
= strdup(iface
->ifname
);
500 addrs
->destroy(addrs
);
506 ifaces
->destroy(ifaces
);
507 this->mutex
->unlock(this->mutex
);
511 DBG2(DBG_KNL
, "%H is on interface %s", ip
, name
);
515 DBG2(DBG_KNL
, "%H is not a local address", ip
);
521 * Implementation of kernel_net_t.get_source_addr.
523 static host_t
* get_source_addr(private_kernel_pfroute_net_t
*this,
524 host_t
*dest
, host_t
*src
)
530 * Implementation of kernel_net_t.get_nexthop.
532 static host_t
* get_nexthop(private_kernel_pfroute_net_t
*this, host_t
*dest
)
538 * Implementation of kernel_net_t.add_ip.
540 static status_t
add_ip(private_kernel_pfroute_net_t
*this,
541 host_t
*virtual_ip
, host_t
*iface_ip
)
547 * Implementation of kernel_net_t.del_ip.
549 static status_t
del_ip(private_kernel_pfroute_net_t
*this, host_t
*virtual_ip
)
555 * Implementation of kernel_net_t.add_route.
557 static status_t
add_route(private_kernel_pfroute_net_t
*this, chunk_t dst_net
,
558 u_int8_t prefixlen
, host_t
*gateway
, host_t
*src_ip
, char *if_name
)
564 * Implementation of kernel_net_t.del_route.
566 static status_t
del_route(private_kernel_pfroute_net_t
*this, chunk_t dst_net
,
567 u_int8_t prefixlen
, host_t
*gateway
, host_t
*src_ip
, char *if_name
)
573 * Initialize a list of local addresses.
575 static status_t
init_address_list(private_kernel_pfroute_net_t
*this)
577 struct ifaddrs
*ifap
, *ifa
;
578 iface_entry_t
*iface
, *current
;
580 enumerator_t
*ifaces
, *addrs
;
582 DBG1(DBG_KNL
, "listening on interfaces:");
584 if (getifaddrs(&ifap
) < 0)
586 DBG1(DBG_KNL
, " failed to get interfaces!");
590 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
592 if (ifa
->ifa_addr
== NULL
)
596 switch(ifa
->ifa_addr
->sa_family
)
602 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
603 { /* ignore loopback interfaces */
608 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
609 while (ifaces
->enumerate(ifaces
, ¤t
))
611 if (streq(current
->ifname
, ifa
->ifa_name
))
617 ifaces
->destroy(ifaces
);
621 iface
= malloc_thing(iface_entry_t
);
622 memcpy(iface
->ifname
, ifa
->ifa_name
, IFNAMSIZ
);
623 iface
->ifindex
= if_nametoindex(ifa
->ifa_name
);
624 iface
->flags
= ifa
->ifa_flags
;
625 iface
->addrs
= linked_list_create();
626 this->ifaces
->insert_last(this->ifaces
, iface
);
629 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
631 addr
= malloc_thing(addr_entry_t
);
632 addr
->ip
= host_create_from_sockaddr(ifa
->ifa_addr
);
633 addr
->virtual = FALSE
;
635 iface
->addrs
->insert_last(iface
->addrs
, addr
);
642 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
643 while (ifaces
->enumerate(ifaces
, &iface
))
645 if (iface
->flags
& IFF_UP
)
647 DBG1(DBG_KNL
, " %s", iface
->ifname
);
648 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
649 while (addrs
->enumerate(addrs
, (void**)&addr
))
651 DBG1(DBG_KNL
, " %H", addr
->ip
);
653 addrs
->destroy(addrs
);
656 ifaces
->destroy(ifaces
);
662 * Implementation of kernel_netlink_net_t.destroy.
664 static void destroy(private_kernel_pfroute_net_t
*this)
668 this->job
->cancel(this->job
);
670 if (this->socket
> 0)
674 if (this->socket_events
)
676 close(this->socket_events
);
678 this->ifaces
->destroy_function(this->ifaces
, (void*)iface_entry_destroy
);
679 this->mutex
->destroy(this->mutex
);
680 this->mutex_pfroute
->destroy(this->mutex_pfroute
);
685 * Described in header.
687 kernel_pfroute_net_t
*kernel_pfroute_net_create()
689 private_kernel_pfroute_net_t
*this = malloc_thing(private_kernel_pfroute_net_t
);
691 /* public functions */
692 this->public.interface
.get_interface
= (char*(*)(kernel_net_t
*,host_t
*))get_interface_name
;
693 this->public.interface
.create_address_enumerator
= (enumerator_t
*(*)(kernel_net_t
*,bool,bool))create_address_enumerator
;
694 this->public.interface
.get_source_addr
= (host_t
*(*)(kernel_net_t
*, host_t
*dest
, host_t
*src
))get_source_addr
;
695 this->public.interface
.get_nexthop
= (host_t
*(*)(kernel_net_t
*, host_t
*dest
))get_nexthop
;
696 this->public.interface
.add_ip
= (status_t(*)(kernel_net_t
*,host_t
*,host_t
*)) add_ip
;
697 this->public.interface
.del_ip
= (status_t(*)(kernel_net_t
*,host_t
*)) del_ip
;
698 this->public.interface
.add_route
= (status_t(*)(kernel_net_t
*,chunk_t
,u_int8_t
,host_t
*,host_t
*,char*)) add_route
;
699 this->public.interface
.del_route
= (status_t(*)(kernel_net_t
*,chunk_t
,u_int8_t
,host_t
*,host_t
*,char*)) del_route
;
701 this->public.interface
.destroy
= (void(*)(kernel_net_t
*)) destroy
;
703 /* private members */
704 this->ifaces
= linked_list_create();
705 this->mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
706 this->mutex_pfroute
= mutex_create(MUTEX_TYPE_DEFAULT
);
709 this->socket_events
= 0;
712 /* create a PF_ROUTE socket to communicate with the kernel */
713 this->socket
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
714 if (this->socket
< 0)
716 DBG1(DBG_KNL
, "unable to create PF_ROUTE socket");
721 /* create a PF_ROUTE socket to receive events */
722 this->socket_events
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
723 if (this->socket_events
< 0)
725 DBG1(DBG_KNL
, "unable to create PF_ROUTE event socket");
730 this->job
= callback_job_create((callback_job_cb_t
)receive_events
,
732 hydra
->processor
->queue_job(hydra
->processor
, (job_t
*)this->job
);
734 if (init_address_list(this) != SUCCESS
)
736 DBG1(DBG_KNL
, "unable to get interface list");
741 return &this->public;