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>
33 #include <processing/jobs/roam_job.h>
35 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
36 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
39 /** delay before firing roam jobs (ms) */
40 #define ROAM_DELAY 100
42 /** buffer size for PF_ROUTE messages */
43 #define PFROUTE_BUFFER_SIZE 4096
45 typedef struct addr_entry_t addr_entry_t
;
48 * IP address in an inface_entry_t
55 /** virtual IP managed by us */
58 /** Number of times this IP is used, if virtual */
63 * destroy a addr_entry_t object
65 static void addr_entry_destroy(addr_entry_t
*this)
67 this->ip
->destroy(this->ip
);
71 typedef struct iface_entry_t iface_entry_t
;
74 * A network interface on this system, containing addr_entry_t's
76 struct iface_entry_t
{
78 /** interface index */
81 /** name of the interface */
82 char ifname
[IFNAMSIZ
];
84 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
87 /** list of addresses as host_t */
92 * destroy an interface entry
94 static void iface_entry_destroy(iface_entry_t
*this)
96 this->addrs
->destroy_function(this->addrs
, (void*)addr_entry_destroy
);
101 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t
;
104 * Private variables and functions of kernel_pfroute class.
106 struct private_kernel_pfroute_net_t
109 * Public part of the kernel_pfroute_t object.
111 kernel_pfroute_net_t
public;
114 * mutex to lock access to various lists
119 * Cached list of interfaces and their addresses (iface_entry_t)
121 linked_list_t
*ifaces
;
124 * job receiving PF_ROUTE events
129 * mutex to lock access to the PF_ROUTE socket
131 mutex_t
*mutex_pfroute
;
134 * PF_ROUTE socket to communicate with the kernel
139 * PF_ROUTE socket to receive events
144 * sequence number for messages sent to the kernel
149 * time of last roam job
155 * Start a roaming job. We delay it a bit and fire only one job
156 * for multiple events. Otherwise we would create too many jobs.
158 static void fire_roam_job(private_kernel_pfroute_net_t
*this, bool address
)
162 time_monotonic(&now
);
163 if (timercmp(&now
, &this->last_roam
, >))
165 now
.tv_usec
+= ROAM_DELAY
* 1000;
166 while (now
.tv_usec
> 1000000)
169 now
.tv_usec
-= 1000000;
171 this->last_roam
= now
;
172 charon
->scheduler
->schedule_job_ms(charon
->scheduler
,
173 (job_t
*)roam_job_create(address
), ROAM_DELAY
);
178 * Process an RTM_*ADDR message from the kernel
180 static void process_addr(private_kernel_pfroute_net_t
*this,
181 struct rt_msghdr
*msg
)
183 struct ifa_msghdr
*ifa
= (struct ifa_msghdr
*)msg
;
184 sockaddr_t
*sockaddr
= (sockaddr_t
*)(ifa
+ 1);
186 enumerator_t
*ifaces
, *addrs
;
187 iface_entry_t
*iface
;
189 bool found
= FALSE
, changed
= FALSE
, roam
= FALSE
;
192 for (i
= 1; i
< (1 << RTAX_MAX
); i
<<= 1)
194 if (ifa
->ifam_addrs
& i
)
198 host
= host_create_from_sockaddr(sockaddr
);
201 sockaddr
= (sockaddr_t
*)((char*)sockaddr
+ sockaddr
->sa_len
);
210 this->mutex
->lock(this->mutex
);
211 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
212 while (ifaces
->enumerate(ifaces
, &iface
))
214 if (iface
->ifindex
== ifa
->ifam_index
)
216 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
217 while (addrs
->enumerate(addrs
, &addr
))
219 if (host
->ip_equals(host
, addr
->ip
))
222 if (ifa
->ifam_type
== RTM_DELADDR
)
224 iface
->addrs
->remove_at(iface
->addrs
, addrs
);
228 DBG1(DBG_KNL
, "%H disappeared from %s",
229 host
, iface
->ifname
);
231 addr_entry_destroy(addr
);
233 else if (ifa
->ifam_type
== RTM_NEWADDR
&& addr
->virtual)
239 addrs
->destroy(addrs
);
241 if (!found
&& ifa
->ifam_type
== RTM_NEWADDR
)
244 addr
= malloc_thing(addr_entry_t
);
245 addr
->ip
= host
->clone(host
);
246 addr
->virtual = FALSE
;
248 iface
->addrs
->insert_last(iface
->addrs
, addr
);
249 DBG1(DBG_KNL
, "%H appeared on %s", host
, iface
->ifname
);
252 if (changed
&& (iface
->flags
& IFF_UP
))
259 ifaces
->destroy(ifaces
);
260 this->mutex
->unlock(this->mutex
);
265 fire_roam_job(this, TRUE
);
270 * Process an RTM_IFINFO message from the kernel
272 static void process_link(private_kernel_pfroute_net_t
*this,
273 struct rt_msghdr
*hdr
)
275 struct if_msghdr
*msg
= (struct if_msghdr
*)hdr
;
276 enumerator_t
*enumerator
;
277 iface_entry_t
*iface
;
280 if (msg
->ifm_flags
& IFF_LOOPBACK
)
281 { /* ignore loopback interfaces */
285 this->mutex
->lock(this->mutex
);
286 enumerator
= this->ifaces
->create_enumerator(this->ifaces
);
287 while (enumerator
->enumerate(enumerator
, &iface
))
289 if (iface
->ifindex
== msg
->ifm_index
)
291 if (!(iface
->flags
& IFF_UP
) && (msg
->ifm_flags
& IFF_UP
))
294 DBG1(DBG_KNL
, "interface %s activated", iface
->ifname
);
296 else if ((iface
->flags
& IFF_UP
) && !(msg
->ifm_flags
& IFF_UP
))
299 DBG1(DBG_KNL
, "interface %s deactivated", iface
->ifname
);
301 iface
->flags
= msg
->ifm_flags
;
305 enumerator
->destroy(enumerator
);
306 this->mutex
->unlock(this->mutex
);
310 fire_roam_job(this, TRUE
);
315 * Process an RTM_*ROUTE message from the kernel
317 static void process_route(private_kernel_pfroute_net_t
*this,
318 struct rt_msghdr
*msg
)
324 * Receives events from kernel
326 static job_requeue_t
receive_events(private_kernel_pfroute_net_t
*this)
328 unsigned char buf
[PFROUTE_BUFFER_SIZE
];
329 struct rt_msghdr
*msg
= (struct rt_msghdr
*)buf
;
333 oldstate
= thread_cancelability(TRUE
);
334 len
= recvfrom(this->socket_events
, buf
, sizeof(buf
), 0, NULL
, 0);
335 thread_cancelability(oldstate
);
342 /* interrupted, try again */
343 return JOB_REQUEUE_DIRECT
;
345 /* no data ready, select again */
346 return JOB_REQUEUE_DIRECT
;
348 DBG1(DBG_KNL
, "unable to receive from PF_ROUTE event socket");
350 return JOB_REQUEUE_FAIR
;
354 if (len
< sizeof(msg
->rtm_msglen
) || len
< msg
->rtm_msglen
||
355 msg
->rtm_version
!= RTM_VERSION
)
357 DBG2(DBG_KNL
, "received corrupted PF_ROUTE message");
358 return JOB_REQUEUE_DIRECT
;
361 switch (msg
->rtm_type
)
365 process_addr(this, msg
);
368 /*case RTM_IFANNOUNCE <- what about this*/
369 process_link(this, msg
);
373 process_route(this, msg
);
378 return JOB_REQUEUE_DIRECT
;
382 /** enumerator over addresses */
384 private_kernel_pfroute_net_t
* this;
385 /** whether to enumerate down interfaces */
386 bool include_down_ifaces
;
387 /** whether to enumerate virtual ip addresses */
388 bool include_virtual_ips
;
389 } address_enumerator_t
;
392 * cleanup function for address enumerator
394 static void address_enumerator_destroy(address_enumerator_t
*data
)
396 data
->this->mutex
->unlock(data
->this->mutex
);
401 * filter for addresses
403 static bool filter_addresses(address_enumerator_t
*data
, addr_entry_t
** in
, host_t
** out
)
406 if (!data
->include_virtual_ips
&& (*in
)->virtual)
407 { /* skip virtual interfaces added by us */
411 if (ip
->get_family(ip
) == AF_INET6
)
413 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ip
->get_sockaddr(ip
);
414 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
415 { /* skip addresses with a unusable scope */
424 * enumerator constructor for interfaces
426 static enumerator_t
*create_iface_enumerator(iface_entry_t
*iface
, address_enumerator_t
*data
)
428 return enumerator_create_filter(iface
->addrs
->create_enumerator(iface
->addrs
),
429 (void*)filter_addresses
, data
, NULL
);
433 * filter for interfaces
435 static bool filter_interfaces(address_enumerator_t
*data
, iface_entry_t
** in
, iface_entry_t
** out
)
437 if (!data
->include_down_ifaces
&& !((*in
)->flags
& IFF_UP
))
438 { /* skip interfaces not up */
446 * implementation of kernel_net_t.create_address_enumerator
448 static enumerator_t
*create_address_enumerator(private_kernel_pfroute_net_t
*this,
449 bool include_down_ifaces
, bool include_virtual_ips
)
451 address_enumerator_t
*data
= malloc_thing(address_enumerator_t
);
453 data
->include_down_ifaces
= include_down_ifaces
;
454 data
->include_virtual_ips
= include_virtual_ips
;
456 this->mutex
->lock(this->mutex
);
457 return enumerator_create_nested(
458 enumerator_create_filter(this->ifaces
->create_enumerator(this->ifaces
),
459 (void*)filter_interfaces
, data
, NULL
),
460 (void*)create_iface_enumerator
, data
, (void*)address_enumerator_destroy
);
464 * implementation of kernel_net_t.get_interface_name
466 static char *get_interface_name(private_kernel_pfroute_net_t
*this, host_t
* ip
)
468 enumerator_t
*ifaces
, *addrs
;
469 iface_entry_t
*iface
;
473 DBG2(DBG_KNL
, "getting interface name for %H", ip
);
475 this->mutex
->lock(this->mutex
);
476 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
477 while (ifaces
->enumerate(ifaces
, &iface
))
479 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
480 while (addrs
->enumerate(addrs
, &addr
))
482 if (ip
->ip_equals(ip
, addr
->ip
))
484 name
= strdup(iface
->ifname
);
488 addrs
->destroy(addrs
);
494 ifaces
->destroy(ifaces
);
495 this->mutex
->unlock(this->mutex
);
499 DBG2(DBG_KNL
, "%H is on interface %s", ip
, name
);
503 DBG2(DBG_KNL
, "%H is not a local address", ip
);
509 * Implementation of kernel_net_t.get_source_addr.
511 static host_t
* get_source_addr(private_kernel_pfroute_net_t
*this,
512 host_t
*dest
, host_t
*src
)
518 * Implementation of kernel_net_t.get_nexthop.
520 static host_t
* get_nexthop(private_kernel_pfroute_net_t
*this, host_t
*dest
)
526 * Implementation of kernel_net_t.add_ip.
528 static status_t
add_ip(private_kernel_pfroute_net_t
*this,
529 host_t
*virtual_ip
, host_t
*iface_ip
)
535 * Implementation of kernel_net_t.del_ip.
537 static status_t
del_ip(private_kernel_pfroute_net_t
*this, host_t
*virtual_ip
)
543 * Implementation of kernel_net_t.add_route.
545 static status_t
add_route(private_kernel_pfroute_net_t
*this, chunk_t dst_net
,
546 u_int8_t prefixlen
, host_t
*gateway
, host_t
*src_ip
, char *if_name
)
552 * Implementation of kernel_net_t.del_route.
554 static status_t
del_route(private_kernel_pfroute_net_t
*this, chunk_t dst_net
,
555 u_int8_t prefixlen
, host_t
*gateway
, host_t
*src_ip
, char *if_name
)
561 * Initialize a list of local addresses.
563 static status_t
init_address_list(private_kernel_pfroute_net_t
*this)
565 struct ifaddrs
*ifap
, *ifa
;
566 iface_entry_t
*iface
, *current
;
568 enumerator_t
*ifaces
, *addrs
;
570 DBG1(DBG_KNL
, "listening on interfaces:");
572 if (getifaddrs(&ifap
) < 0)
574 DBG1(DBG_KNL
, " failed to get interfaces!");
578 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
580 if (ifa
->ifa_addr
== NULL
)
584 switch(ifa
->ifa_addr
->sa_family
)
590 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
591 { /* ignore loopback interfaces */
596 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
597 while (ifaces
->enumerate(ifaces
, ¤t
))
599 if (streq(current
->ifname
, ifa
->ifa_name
))
605 ifaces
->destroy(ifaces
);
609 iface
= malloc_thing(iface_entry_t
);
610 memcpy(iface
->ifname
, ifa
->ifa_name
, IFNAMSIZ
);
611 iface
->ifindex
= if_nametoindex(ifa
->ifa_name
);
612 iface
->flags
= ifa
->ifa_flags
;
613 iface
->addrs
= linked_list_create();
614 this->ifaces
->insert_last(this->ifaces
, iface
);
617 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
619 addr
= malloc_thing(addr_entry_t
);
620 addr
->ip
= host_create_from_sockaddr(ifa
->ifa_addr
);
621 addr
->virtual = FALSE
;
623 iface
->addrs
->insert_last(iface
->addrs
, addr
);
630 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
631 while (ifaces
->enumerate(ifaces
, &iface
))
633 if (iface
->flags
& IFF_UP
)
635 DBG1(DBG_KNL
, " %s", iface
->ifname
);
636 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
637 while (addrs
->enumerate(addrs
, (void**)&addr
))
639 DBG1(DBG_KNL
, " %H", addr
->ip
);
641 addrs
->destroy(addrs
);
644 ifaces
->destroy(ifaces
);
650 * Implementation of kernel_netlink_net_t.destroy.
652 static void destroy(private_kernel_pfroute_net_t
*this)
656 this->job
->cancel(this->job
);
658 if (this->socket
> 0)
662 if (this->socket_events
)
664 close(this->socket_events
);
666 this->ifaces
->destroy_function(this->ifaces
, (void*)iface_entry_destroy
);
667 this->mutex
->destroy(this->mutex
);
668 this->mutex_pfroute
->destroy(this->mutex_pfroute
);
673 * Described in header.
675 kernel_pfroute_net_t
*kernel_pfroute_net_create()
677 private_kernel_pfroute_net_t
*this = malloc_thing(private_kernel_pfroute_net_t
);
679 /* public functions */
680 this->public.interface
.get_interface
= (char*(*)(kernel_net_t
*,host_t
*))get_interface_name
;
681 this->public.interface
.create_address_enumerator
= (enumerator_t
*(*)(kernel_net_t
*,bool,bool))create_address_enumerator
;
682 this->public.interface
.get_source_addr
= (host_t
*(*)(kernel_net_t
*, host_t
*dest
, host_t
*src
))get_source_addr
;
683 this->public.interface
.get_nexthop
= (host_t
*(*)(kernel_net_t
*, host_t
*dest
))get_nexthop
;
684 this->public.interface
.add_ip
= (status_t(*)(kernel_net_t
*,host_t
*,host_t
*)) add_ip
;
685 this->public.interface
.del_ip
= (status_t(*)(kernel_net_t
*,host_t
*)) del_ip
;
686 this->public.interface
.add_route
= (status_t(*)(kernel_net_t
*,chunk_t
,u_int8_t
,host_t
*,host_t
*,char*)) add_route
;
687 this->public.interface
.del_route
= (status_t(*)(kernel_net_t
*,chunk_t
,u_int8_t
,host_t
*,host_t
*,char*)) del_route
;
689 this->public.interface
.destroy
= (void(*)(kernel_net_t
*)) destroy
;
691 /* private members */
692 this->ifaces
= linked_list_create();
693 this->mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
694 this->mutex_pfroute
= mutex_create(MUTEX_TYPE_DEFAULT
);
697 this->socket_events
= 0;
700 /* create a PF_ROUTE socket to communicate with the kernel */
701 this->socket
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
702 if (this->socket
< 0)
704 DBG1(DBG_KNL
, "unable to create PF_ROUTE socket");
709 /* create a PF_ROUTE socket to receive events */
710 this->socket_events
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
711 if (this->socket_events
< 0)
713 DBG1(DBG_KNL
, "unable to create PF_ROUTE event socket");
718 this->job
= callback_job_create((callback_job_cb_t
)receive_events
,
720 hydra
->processor
->queue_job(hydra
->processor
, (job_t
*)this->job
);
722 if (init_address_list(this) != SUCCESS
)
724 DBG1(DBG_KNL
, "unable to get interface list");
729 return &this->public;