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>
19 #include <net/if_dl.h>
21 #include <net/route.h>
25 #include "kernel_pfroute_net.h"
28 #include <utils/debug.h>
29 #include <networking/host.h>
30 #include <networking/tun_device.h>
31 #include <threading/thread.h>
32 #include <threading/mutex.h>
33 #include <threading/condvar.h>
34 #include <threading/rwlock.h>
35 #include <collections/hashtable.h>
36 #include <collections/linked_list.h>
37 #include <processing/jobs/callback_job.h>
39 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
40 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
43 /** properly align sockaddrs */
45 /* Apple always uses 4 bytes */
48 /* while on other platforms like FreeBSD it depends on the architecture */
49 #define SA_ALIGN sizeof(long)
51 #define SA_LEN(len) ((len) > 0 ? (((len)+SA_ALIGN-1) & ~(SA_ALIGN-1)) : SA_ALIGN)
53 /** delay before firing roam events (ms) */
54 #define ROAM_DELAY 100
56 typedef struct addr_entry_t addr_entry_t
;
59 * IP address in an inface_entry_t
66 /** virtual IP managed by us */
71 * destroy a addr_entry_t object
73 static void addr_entry_destroy(addr_entry_t
*this)
75 this->ip
->destroy(this->ip
);
79 typedef struct iface_entry_t iface_entry_t
;
82 * A network interface on this system, containing addr_entry_t's
84 struct iface_entry_t
{
86 /** interface index */
89 /** name of the interface */
90 char ifname
[IFNAMSIZ
];
92 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
95 /** list of addresses as host_t */
98 /** TRUE if usable by config */
103 * destroy an interface entry
105 static void iface_entry_destroy(iface_entry_t
*this)
107 this->addrs
->destroy_function(this->addrs
, (void*)addr_entry_destroy
);
112 * check if an interface is up
114 static inline bool iface_entry_up(iface_entry_t
*iface
)
116 return (iface
->flags
& IFF_UP
) == IFF_UP
;
120 * check if an interface is up and usable
122 static inline bool iface_entry_up_and_usable(iface_entry_t
*iface
)
124 return iface
->usable
&& iface_entry_up(iface
);
127 typedef struct addr_map_entry_t addr_map_entry_t
;
130 * Entry that maps an IP address to an interface entry
132 struct addr_map_entry_t
{
133 /** The IP address */
136 /** The interface this address is installed on */
137 iface_entry_t
*iface
;
141 * Hash a addr_map_entry_t object, all entries with the same IP address
142 * are stored in the same bucket
144 static u_int
addr_map_entry_hash(addr_map_entry_t
*this)
146 return chunk_hash(this->ip
->get_address(this->ip
));
150 * Compare two addr_map_entry_t objects, two entries are equal if they are
151 * installed on the same interface
153 static bool addr_map_entry_equals(addr_map_entry_t
*a
, addr_map_entry_t
*b
)
155 return a
->iface
->ifindex
== b
->iface
->ifindex
&&
156 a
->ip
->ip_equals(a
->ip
, b
->ip
);
160 * Used with get_match this finds an address entry if it is installed on
161 * an up and usable interface
163 static bool addr_map_entry_match_up_and_usable(addr_map_entry_t
*a
,
166 return iface_entry_up_and_usable(b
->iface
) &&
167 a
->ip
->ip_equals(a
->ip
, b
->ip
);
171 * Used with get_match this finds an address entry if it is installed on
172 * any active local interface
174 static bool addr_map_entry_match_up(addr_map_entry_t
*a
, addr_map_entry_t
*b
)
176 return iface_entry_up(b
->iface
) && a
->ip
->ip_equals(a
->ip
, b
->ip
);
179 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t
;
182 * Private variables and functions of kernel_pfroute class.
184 struct private_kernel_pfroute_net_t
187 * Public part of the kernel_pfroute_t object.
189 kernel_pfroute_net_t
public;
192 * lock to access lists and maps
197 * Cached list of interfaces and their addresses (iface_entry_t)
199 linked_list_t
*ifaces
;
202 * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
207 * List of tun devices we installed for virtual IPs
212 * mutex to communicate exclusively with PF_KEY
217 * condvar to signal if PF_KEY query got a response
222 * pid to send PF_ROUTE messages with
227 * PF_ROUTE socket to communicate with the kernel
232 * sequence number for messages sent to the kernel
237 * Sequence number a query is waiting for
242 * Allocated reply message from kernel
244 struct rt_msghdr
*reply
;
247 * time of last roam event
252 * Time in ms to wait for IP addresses to appear/disappear
258 * Add an address map entry
260 static void addr_map_entry_add(private_kernel_pfroute_net_t
*this,
261 addr_entry_t
*addr
, iface_entry_t
*iface
)
263 addr_map_entry_t
*entry
;
266 { /* don't map virtual IPs */
274 entry
= this->addrs
->put(this->addrs
, entry
, entry
);
279 * Remove an address map entry (the argument order is a bit strange because
280 * it is also used with linked_list_t.invoke_function)
282 static void addr_map_entry_remove(addr_entry_t
*addr
, iface_entry_t
*iface
,
283 private_kernel_pfroute_net_t
*this)
285 addr_map_entry_t
*entry
, lookup
= {
291 { /* these are never mapped, but this check avoid problems if a virtual IP
292 * equals a regular one */
295 entry
= this->addrs
->remove(this->addrs
, &lookup
);
300 * callback function that raises the delayed roam event
302 static job_requeue_t
roam_event(uintptr_t address
)
304 hydra
->kernel_interface
->roam(hydra
->kernel_interface
, address
!= 0);
305 return JOB_REQUEUE_NONE
;
309 * fire a roaming event. we delay it for a bit and fire only one event
310 * for multiple calls. otherwise we would create too many events.
312 static void fire_roam_event(private_kernel_pfroute_net_t
*this, bool address
)
317 time_monotonic(&now
);
318 if (timercmp(&now
, &this->last_roam
, >))
320 timeval_add_ms(&now
, ROAM_DELAY
);
321 this->last_roam
= now
;
323 job
= (job_t
*)callback_job_create((callback_job_cb_t
)roam_event
,
324 (void*)(uintptr_t)(address
? 1 : 0),
326 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, job
, ROAM_DELAY
);
331 * Data for enumerator over rtmsg sockaddrs
334 /** implements enumerator */
336 /** copy of attribute bitfield */
338 /** bytes remaining in buffer */
340 /** next sockaddr to enumerate */
341 struct sockaddr
*addr
;
344 METHOD(enumerator_t
, rt_enumerate
, bool,
345 rt_enumerator_t
*this, int *xtype
, struct sockaddr
**addr
)
349 if (this->remaining
< sizeof(this->addr
->sa_len
) ||
350 this->remaining
< this->addr
->sa_len
)
354 for (i
= 0; i
< RTAX_MAX
; i
++)
357 if (this->types
& type
)
359 this->types
&= ~type
;
362 this->remaining
-= SA_LEN(this->addr
->sa_len
);
363 this->addr
= (struct sockaddr
*)((char*)this->addr
+
364 SA_LEN(this->addr
->sa_len
));
372 * Create a safe enumerator over sockaddrs in ifa/ifam/rt_msg
374 static enumerator_t
*create_rtmsg_enumerator(void *hdr
, size_t hdrlen
)
376 struct rt_msghdr
*rthdr
= hdr
;
377 rt_enumerator_t
*this;
381 .enumerate
= (void*)_rt_enumerate
,
382 .destroy
= (void*)free
,
384 .types
= rthdr
->rtm_addrs
,
385 .remaining
= rthdr
->rtm_msglen
- hdrlen
,
386 .addr
= hdr
+ hdrlen
,
388 return &this->public;
392 * Process an RTM_*ADDR message from the kernel
394 static void process_addr(private_kernel_pfroute_net_t
*this,
395 struct ifa_msghdr
*ifa
)
397 struct sockaddr
*sockaddr
;
399 enumerator_t
*ifaces
, *addrs
;
400 iface_entry_t
*iface
;
402 bool found
= FALSE
, changed
= FALSE
, roam
= FALSE
;
403 enumerator_t
*enumerator
;
406 enumerator
= create_rtmsg_enumerator(ifa
, sizeof(*ifa
));
407 while (enumerator
->enumerate(enumerator
, &type
, &sockaddr
))
409 if (type
== RTAX_IFA
)
411 host
= host_create_from_sockaddr(sockaddr
);
415 enumerator
->destroy(enumerator
);
422 this->lock
->write_lock(this->lock
);
423 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
424 while (ifaces
->enumerate(ifaces
, &iface
))
426 if (iface
->ifindex
== ifa
->ifam_index
)
428 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
429 while (addrs
->enumerate(addrs
, &addr
))
431 if (host
->ip_equals(host
, addr
->ip
))
434 if (ifa
->ifam_type
== RTM_DELADDR
)
436 iface
->addrs
->remove_at(iface
->addrs
, addrs
);
437 if (!addr
->virtual && iface
->usable
)
440 DBG1(DBG_KNL
, "%H disappeared from %s",
441 host
, iface
->ifname
);
443 addr_map_entry_remove(addr
, iface
, this);
444 addr_entry_destroy(addr
);
448 addrs
->destroy(addrs
);
450 if (!found
&& ifa
->ifam_type
== RTM_NEWADDR
)
453 .ip
= host
->clone(host
),
456 iface
->addrs
->insert_last(iface
->addrs
, addr
);
457 addr_map_entry_add(this, addr
, iface
);
460 DBG1(DBG_KNL
, "%H appeared on %s", host
, iface
->ifname
);
464 if (changed
&& iface_entry_up_and_usable(iface
))
471 ifaces
->destroy(ifaces
);
472 this->lock
->unlock(this->lock
);
477 fire_roam_event(this, TRUE
);
482 * Re-initialize address list of an interface if it changes state
484 static void repopulate_iface(private_kernel_pfroute_net_t
*this,
485 iface_entry_t
*iface
)
487 struct ifaddrs
*ifap
, *ifa
;
490 while (iface
->addrs
->remove_last(iface
->addrs
, (void**)&addr
) == SUCCESS
)
492 addr_map_entry_remove(addr
, iface
, this);
493 addr_entry_destroy(addr
);
496 if (getifaddrs(&ifap
) == 0)
498 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
500 if (ifa
->ifa_addr
&& streq(ifa
->ifa_name
, iface
->ifname
))
502 switch (ifa
->ifa_addr
->sa_family
)
507 .ip
= host_create_from_sockaddr(ifa
->ifa_addr
),
509 iface
->addrs
->insert_last(iface
->addrs
, addr
);
510 addr_map_entry_add(this, addr
, iface
);
522 * Process an RTM_IFINFO message from the kernel
524 static void process_link(private_kernel_pfroute_net_t
*this,
525 struct if_msghdr
*msg
)
527 enumerator_t
*enumerator
;
528 iface_entry_t
*iface
;
529 bool roam
= FALSE
, found
= FALSE
;
531 this->lock
->write_lock(this->lock
);
532 enumerator
= this->ifaces
->create_enumerator(this->ifaces
);
533 while (enumerator
->enumerate(enumerator
, &iface
))
535 if (iface
->ifindex
== msg
->ifm_index
)
539 if (!(iface
->flags
& IFF_UP
) && (msg
->ifm_flags
& IFF_UP
))
542 DBG1(DBG_KNL
, "interface %s activated", iface
->ifname
);
544 else if ((iface
->flags
& IFF_UP
) && !(msg
->ifm_flags
& IFF_UP
))
547 DBG1(DBG_KNL
, "interface %s deactivated", iface
->ifname
);
550 iface
->flags
= msg
->ifm_flags
;
551 repopulate_iface(this, iface
);
556 enumerator
->destroy(enumerator
);
561 .ifindex
= msg
->ifm_index
,
562 .flags
= msg
->ifm_flags
,
563 .addrs
= linked_list_create(),
565 if (if_indextoname(iface
->ifindex
, iface
->ifname
))
567 DBG1(DBG_KNL
, "interface %s appeared", iface
->ifname
);
568 iface
->usable
= hydra
->kernel_interface
->is_interface_usable(
569 hydra
->kernel_interface
, iface
->ifname
);
570 repopulate_iface(this, iface
);
571 this->ifaces
->insert_last(this->ifaces
, iface
);
578 this->lock
->unlock(this->lock
);
582 fire_roam_event(this, TRUE
);
587 * Process an RTM_*ROUTE message from the kernel
589 static void process_route(private_kernel_pfroute_net_t
*this,
590 struct rt_msghdr
*msg
)
596 * Receives PF_ROUTE messages from kernel
598 static job_requeue_t
receive_events(private_kernel_pfroute_net_t
*this)
602 struct rt_msghdr rtm
;
603 struct if_msghdr ifm
;
604 struct ifa_msghdr ifam
;
606 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
611 oldstate
= thread_cancelability(TRUE
);
612 len
= recv(this->socket
, &msg
, sizeof(msg
), 0);
613 thread_cancelability(oldstate
);
621 return JOB_REQUEUE_DIRECT
;
623 DBG1(DBG_KNL
, "unable to receive from PF_ROUTE event socket");
625 return JOB_REQUEUE_FAIR
;
629 if (len
< offsetof(struct rt_msghdr
, rtm_flags
) || len
< msg
.rtm
.rtm_msglen
)
631 DBG1(DBG_KNL
, "received invalid PF_ROUTE message");
632 return JOB_REQUEUE_DIRECT
;
634 if (msg
.rtm
.rtm_version
!= RTM_VERSION
)
636 DBG1(DBG_KNL
, "received PF_ROUTE message with unsupported version: %d",
637 msg
.rtm
.rtm_version
);
638 return JOB_REQUEUE_DIRECT
;
640 switch (msg
.rtm
.rtm_type
)
644 hdrlen
= sizeof(msg
.ifam
);
647 hdrlen
= sizeof(msg
.ifm
);
652 hdrlen
= sizeof(msg
.rtm
);
655 return JOB_REQUEUE_DIRECT
;
657 if (msg
.rtm
.rtm_msglen
< hdrlen
)
659 DBG1(DBG_KNL
, "ignoring short PF_ROUTE message");
660 return JOB_REQUEUE_DIRECT
;
662 switch (msg
.rtm
.rtm_type
)
666 process_addr(this, &msg
.ifam
);
669 process_link(this, &msg
.ifm
);
673 process_route(this, &msg
.rtm
);
679 this->mutex
->lock(this->mutex
);
680 if (msg
.rtm
.rtm_pid
== this->pid
&& msg
.rtm
.rtm_seq
== this->waiting_seq
)
682 /* seems like the message someone is waiting for, deliver */
683 this->reply
= realloc(this->reply
, msg
.rtm
.rtm_msglen
);
684 memcpy(this->reply
, &msg
, msg
.rtm
.rtm_msglen
);
686 /* signal on any event, add_ip()/del_ip() might wait for it */
687 this->condvar
->broadcast(this->condvar
);
688 this->mutex
->unlock(this->mutex
);
690 return JOB_REQUEUE_DIRECT
;
694 /** enumerator over addresses */
696 private_kernel_pfroute_net_t
* this;
697 /** which addresses to enumerate */
698 kernel_address_type_t which
;
699 } address_enumerator_t
;
702 * cleanup function for address enumerator
704 static void address_enumerator_destroy(address_enumerator_t
*data
)
706 data
->this->lock
->unlock(data
->this->lock
);
711 * filter for addresses
713 static bool filter_addresses(address_enumerator_t
*data
,
714 addr_entry_t
** in
, host_t
** out
)
717 if (!(data
->which
& ADDR_TYPE_VIRTUAL
) && (*in
)->virtual)
718 { /* skip virtual interfaces added by us */
721 if (!(data
->which
& ADDR_TYPE_REGULAR
) && !(*in
)->virtual)
722 { /* address is regular, but not requested */
726 if (ip
->get_family(ip
) == AF_INET6
)
728 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ip
->get_sockaddr(ip
);
729 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
730 { /* skip addresses with a unusable scope */
739 * enumerator constructor for interfaces
741 static enumerator_t
*create_iface_enumerator(iface_entry_t
*iface
,
742 address_enumerator_t
*data
)
744 return enumerator_create_filter(iface
->addrs
->create_enumerator(iface
->addrs
),
745 (void*)filter_addresses
, data
, NULL
);
749 * filter for interfaces
751 static bool filter_interfaces(address_enumerator_t
*data
, iface_entry_t
** in
,
754 if (!(data
->which
& ADDR_TYPE_IGNORED
) && !(*in
)->usable
)
755 { /* skip interfaces excluded by config */
758 if (!(data
->which
& ADDR_TYPE_LOOPBACK
) && ((*in
)->flags
& IFF_LOOPBACK
))
759 { /* ignore loopback devices */
762 if (!(data
->which
& ADDR_TYPE_DOWN
) && !((*in
)->flags
& IFF_UP
))
763 { /* skip interfaces not up */
770 METHOD(kernel_net_t
, create_address_enumerator
, enumerator_t
*,
771 private_kernel_pfroute_net_t
*this, kernel_address_type_t which
)
773 address_enumerator_t
*data
;
780 this->lock
->read_lock(this->lock
);
781 return enumerator_create_nested(
782 enumerator_create_filter(
783 this->ifaces
->create_enumerator(this->ifaces
),
784 (void*)filter_interfaces
, data
, NULL
),
785 (void*)create_iface_enumerator
, data
,
786 (void*)address_enumerator_destroy
);
789 METHOD(kernel_net_t
, get_features
, kernel_feature_t
,
790 private_kernel_pfroute_net_t
*this)
792 return KERNEL_REQUIRE_EXCLUDE_ROUTE
;
795 METHOD(kernel_net_t
, get_interface_name
, bool,
796 private_kernel_pfroute_net_t
*this, host_t
* ip
, char **name
)
798 addr_map_entry_t
*entry
, lookup
= {
802 if (ip
->is_anyaddr(ip
))
806 this->lock
->read_lock(this->lock
);
807 /* first try to find it on an up and usable interface */
808 entry
= this->addrs
->get_match(this->addrs
, &lookup
,
809 (void*)addr_map_entry_match_up_and_usable
);
814 *name
= strdup(entry
->iface
->ifname
);
815 DBG2(DBG_KNL
, "%H is on interface %s", ip
, *name
);
817 this->lock
->unlock(this->lock
);
820 /* maybe it is installed on an ignored interface */
821 entry
= this->addrs
->get_match(this->addrs
, &lookup
,
822 (void*)addr_map_entry_match_up
);
824 { /* the address does not exist, is on a down interface */
825 DBG2(DBG_KNL
, "%H is not a local address or the interface is down", ip
);
827 this->lock
->unlock(this->lock
);
831 METHOD(kernel_net_t
, add_ip
, status_t
,
832 private_kernel_pfroute_net_t
*this, host_t
*vip
, int prefix
,
835 enumerator_t
*ifaces
, *addrs
;
836 iface_entry_t
*iface
;
839 bool timeout
= FALSE
;
841 tun
= tun_device_create(NULL
);
848 prefix
= vip
->get_address(vip
).len
* 8;
850 if (!tun
->up(tun
) || !tun
->set_address(tun
, vip
, prefix
))
856 /* wait until address appears */
857 this->mutex
->lock(this->mutex
);
858 while (!timeout
&& !get_interface_name(this, vip
, NULL
))
860 timeout
= this->condvar
->timed_wait(this->condvar
, this->mutex
,
863 this->mutex
->unlock(this->mutex
);
866 DBG1(DBG_KNL
, "virtual IP %H did not appear on %s",
867 vip
, tun
->get_name(tun
));
872 this->lock
->write_lock(this->lock
);
873 this->tuns
->insert_last(this->tuns
, tun
);
875 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
876 while (ifaces
->enumerate(ifaces
, &iface
))
878 if (streq(iface
->ifname
, tun
->get_name(tun
)))
880 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
881 while (addrs
->enumerate(addrs
, &addr
))
883 if (addr
->ip
->ip_equals(addr
->ip
, vip
))
885 addr
->virtual = TRUE
;
888 addrs
->destroy(addrs
);
891 ifaces
->destroy(ifaces
);
892 /* lets do this while holding the lock, thus preventing another thread
893 * from deleting the TUN device concurrently, hopefully listeneres are quick
894 * and cause no deadlocks */
895 hydra
->kernel_interface
->tun(hydra
->kernel_interface
, tun
, TRUE
);
896 this->lock
->unlock(this->lock
);
901 METHOD(kernel_net_t
, del_ip
, status_t
,
902 private_kernel_pfroute_net_t
*this, host_t
*vip
, int prefix
,
905 enumerator_t
*enumerator
;
908 bool timeout
= FALSE
, found
= FALSE
;
910 this->lock
->write_lock(this->lock
);
911 enumerator
= this->tuns
->create_enumerator(this->tuns
);
912 while (enumerator
->enumerate(enumerator
, &tun
))
914 addr
= tun
->get_address(tun
, NULL
);
915 if (addr
&& addr
->ip_equals(addr
, vip
))
917 this->tuns
->remove_at(this->tuns
, enumerator
);
918 hydra
->kernel_interface
->tun(hydra
->kernel_interface
, tun
,
925 enumerator
->destroy(enumerator
);
926 this->lock
->unlock(this->lock
);
932 /* wait until address disappears */
935 this->mutex
->lock(this->mutex
);
936 while (!timeout
&& get_interface_name(this, vip
, NULL
))
938 timeout
= this->condvar
->timed_wait(this->condvar
, this->mutex
,
941 this->mutex
->unlock(this->mutex
);
944 DBG1(DBG_KNL
, "virtual IP %H did not disappear from tun", vip
);
952 * Append a sockaddr_in/in6 of given type to routing message
954 static void add_rt_addr(struct rt_msghdr
*hdr
, int type
, host_t
*addr
)
960 len
= *addr
->get_sockaddr_len(addr
);
961 memcpy((char*)hdr
+ hdr
->rtm_msglen
, addr
->get_sockaddr(addr
), len
);
962 hdr
->rtm_msglen
+= SA_LEN(len
);
963 hdr
->rtm_addrs
|= type
;
968 * Append a subnet mask sockaddr using the given prefix to routing message
970 static void add_rt_mask(struct rt_msghdr
*hdr
, int type
, int family
, int prefix
)
974 mask
= host_create_netmask(family
, prefix
);
977 add_rt_addr(hdr
, type
, mask
);
983 * Append an interface name sockaddr_dl to routing message
985 static void add_rt_ifname(struct rt_msghdr
*hdr
, int type
, char *name
)
987 struct sockaddr_dl sdl
= {
988 .sdl_len
= sizeof(struct sockaddr_dl
),
989 .sdl_family
= AF_LINK
,
990 .sdl_nlen
= strlen(name
),
993 if (strlen(name
) <= sizeof(sdl
.sdl_data
))
995 memcpy(sdl
.sdl_data
, name
, sdl
.sdl_nlen
);
996 memcpy((char*)hdr
+ hdr
->rtm_msglen
, &sdl
, sdl
.sdl_len
);
997 hdr
->rtm_msglen
+= SA_LEN(sdl
.sdl_len
);
998 hdr
->rtm_addrs
|= type
;
1003 * Add or remove a route
1005 static status_t
manage_route(private_kernel_pfroute_net_t
*this, int op
,
1006 chunk_t dst_net
, u_int8_t prefixlen
,
1007 host_t
*gateway
, char *if_name
)
1010 struct rt_msghdr hdr
;
1011 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
1014 .rtm_version
= RTM_VERSION
,
1016 .rtm_flags
= RTF_UP
| RTF_STATIC
,
1017 .rtm_pid
= this->pid
,
1018 .rtm_seq
= ++this->seq
,
1024 if (prefixlen
== 0 && dst_net
.len
)
1029 half
= chunk_clonea(dst_net
);
1030 half
.ptr
[0] |= 0x80;
1032 status
= manage_route(this, op
, half
, prefixlen
, gateway
, if_name
);
1033 if (status
!= SUCCESS
)
1039 dst
= host_create_from_chunk(AF_UNSPEC
, dst_net
, 0);
1045 if ((dst
->get_family(dst
) == AF_INET
&& prefixlen
== 32) ||
1046 (dst
->get_family(dst
) == AF_INET6
&& prefixlen
== 128))
1048 msg
.hdr
.rtm_flags
|= RTF_HOST
| RTF_GATEWAY
;
1051 msg
.hdr
.rtm_msglen
= sizeof(struct rt_msghdr
);
1052 for (type
= 0; type
< RTAX_MAX
; type
++)
1057 add_rt_addr(&msg
.hdr
, RTA_DST
, dst
);
1060 if (!(msg
.hdr
.rtm_flags
& RTF_HOST
))
1062 add_rt_mask(&msg
.hdr
, RTA_NETMASK
,
1063 dst
->get_family(dst
), prefixlen
);
1069 add_rt_ifname(&msg
.hdr
, RTA_IFP
, if_name
);
1075 add_rt_addr(&msg
.hdr
, RTA_GATEWAY
, gateway
);
1084 if (send(this->socket
, &msg
, msg
.hdr
.rtm_msglen
, 0) != msg
.hdr
.rtm_msglen
)
1086 DBG1(DBG_KNL
, "%s PF_ROUTE route failed: %s",
1087 op
== RTM_ADD
? "adding" : "deleting", strerror(errno
));
1093 METHOD(kernel_net_t
, add_route
, status_t
,
1094 private_kernel_pfroute_net_t
*this, chunk_t dst_net
, u_int8_t prefixlen
,
1095 host_t
*gateway
, host_t
*src_ip
, char *if_name
)
1097 return manage_route(this, RTM_ADD
, dst_net
, prefixlen
, gateway
, if_name
);
1100 METHOD(kernel_net_t
, del_route
, status_t
,
1101 private_kernel_pfroute_net_t
*this, chunk_t dst_net
, u_int8_t prefixlen
,
1102 host_t
*gateway
, host_t
*src_ip
, char *if_name
)
1104 return manage_route(this, RTM_DELETE
, dst_net
, prefixlen
, gateway
, if_name
);
1108 * Do a route lookup for dest and return either the nexthop or the source
1111 static host_t
*get_route(private_kernel_pfroute_net_t
*this, bool nexthop
,
1112 host_t
*dest
, host_t
*src
)
1115 struct rt_msghdr hdr
;
1116 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
1119 .rtm_version
= RTM_VERSION
,
1120 .rtm_type
= RTM_GET
,
1121 .rtm_pid
= this->pid
,
1122 .rtm_seq
= ++this->seq
,
1125 host_t
*host
= NULL
;
1126 enumerator_t
*enumerator
;
1127 struct sockaddr
*addr
;
1128 bool failed
= FALSE
;
1132 msg
.hdr
.rtm_msglen
= sizeof(struct rt_msghdr
);
1133 for (type
= 0; type
< RTAX_MAX
; type
++)
1138 add_rt_addr(&msg
.hdr
, RTA_DST
, dest
);
1141 add_rt_addr(&msg
.hdr
, RTA_IFA
, src
);
1145 { /* add an empty IFP to ensure we get a source address */
1146 add_rt_ifname(&msg
.hdr
, RTA_IFP
, "");
1153 this->mutex
->lock(this->mutex
);
1155 while (this->waiting_seq
)
1157 this->condvar
->wait(this->condvar
, this->mutex
);
1159 this->waiting_seq
= msg
.hdr
.rtm_seq
;
1160 if (send(this->socket
, &msg
, msg
.hdr
.rtm_msglen
, 0) == msg
.hdr
.rtm_msglen
)
1164 if (this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000))
1168 if (this->reply
->rtm_msglen
< sizeof(*this->reply
) ||
1169 msg
.hdr
.rtm_seq
!= this->reply
->rtm_seq
)
1173 enumerator
= create_rtmsg_enumerator(this->reply
,
1174 sizeof(*this->reply
));
1175 while (enumerator
->enumerate(enumerator
, &type
, &addr
))
1179 if (type
== RTAX_DST
&& this->reply
->rtm_flags
& RTF_HOST
)
1180 { /* probably a cloned/cached direct route, only use that
1181 * as fallback if no gateway is found */
1182 host
= host
?: host_create_from_sockaddr(addr
);
1184 if (type
== RTAX_GATEWAY
)
1185 { /* could actually be a MAC address */
1186 host_t
*gtw
= host_create_from_sockaddr(addr
);
1196 if (type
== RTAX_IFA
)
1198 host
= host_create_from_sockaddr(addr
);
1202 enumerator
->destroy(enumerator
);
1210 /* signal completion of query to a waiting thread */
1211 this->waiting_seq
= 0;
1212 this->condvar
->signal(this->condvar
);
1213 this->mutex
->unlock(this->mutex
);
1218 { /* the given source address might be gone, try again without */
1220 msg
.hdr
.rtm_seq
= ++this->seq
;
1221 msg
.hdr
.rtm_addrs
= 0;
1222 memset(msg
.buf
, sizeof(msg
.buf
), 0);
1225 DBG1(DBG_KNL
, "PF_ROUTE lookup failed: %s", strerror(errno
));
1230 DBG2(DBG_KNL
, "using %H as %s to reach %H", host
,
1231 nexthop
? "nexthop" : "address", dest
);
1236 METHOD(kernel_net_t
, get_source_addr
, host_t
*,
1237 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
1239 return get_route(this, FALSE
, dest
, src
);
1242 METHOD(kernel_net_t
, get_nexthop
, host_t
*,
1243 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
1245 return get_route(this, TRUE
, dest
, src
);
1249 * Initialize a list of local addresses.
1251 static status_t
init_address_list(private_kernel_pfroute_net_t
*this)
1253 struct ifaddrs
*ifap
, *ifa
;
1254 iface_entry_t
*iface
, *current
;
1256 enumerator_t
*ifaces
, *addrs
;
1258 DBG2(DBG_KNL
, "known interfaces and IP addresses:");
1260 if (getifaddrs(&ifap
) < 0)
1262 DBG1(DBG_KNL
, " failed to get interfaces!");
1266 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
1268 if (ifa
->ifa_addr
== NULL
)
1272 switch(ifa
->ifa_addr
->sa_family
)
1279 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
1280 while (ifaces
->enumerate(ifaces
, ¤t
))
1282 if (streq(current
->ifname
, ifa
->ifa_name
))
1288 ifaces
->destroy(ifaces
);
1293 .ifindex
= if_nametoindex(ifa
->ifa_name
),
1294 .flags
= ifa
->ifa_flags
,
1295 .addrs
= linked_list_create(),
1296 .usable
= hydra
->kernel_interface
->is_interface_usable(
1297 hydra
->kernel_interface
, ifa
->ifa_name
),
1299 memcpy(iface
->ifname
, ifa
->ifa_name
, IFNAMSIZ
);
1300 this->ifaces
->insert_last(this->ifaces
, iface
);
1303 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
1306 .ip
= host_create_from_sockaddr(ifa
->ifa_addr
),
1308 iface
->addrs
->insert_last(iface
->addrs
, addr
);
1309 addr_map_entry_add(this, addr
, iface
);
1316 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
1317 while (ifaces
->enumerate(ifaces
, &iface
))
1319 if (iface
->usable
&& iface
->flags
& IFF_UP
)
1321 DBG2(DBG_KNL
, " %s", iface
->ifname
);
1322 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
1323 while (addrs
->enumerate(addrs
, (void**)&addr
))
1325 DBG2(DBG_KNL
, " %H", addr
->ip
);
1327 addrs
->destroy(addrs
);
1330 ifaces
->destroy(ifaces
);
1335 METHOD(kernel_net_t
, destroy
, void,
1336 private_kernel_pfroute_net_t
*this)
1338 enumerator_t
*enumerator
;
1341 if (this->socket
!= -1)
1343 close(this->socket
);
1345 enumerator
= this->addrs
->create_enumerator(this->addrs
);
1346 while (enumerator
->enumerate(enumerator
, NULL
, (void**)&addr
))
1350 enumerator
->destroy(enumerator
);
1351 this->addrs
->destroy(this->addrs
);
1352 this->ifaces
->destroy_function(this->ifaces
, (void*)iface_entry_destroy
);
1353 this->tuns
->destroy(this->tuns
);
1354 this->lock
->destroy(this->lock
);
1355 this->mutex
->destroy(this->mutex
);
1356 this->condvar
->destroy(this->condvar
);
1362 * Described in header.
1364 kernel_pfroute_net_t
*kernel_pfroute_net_create()
1366 private_kernel_pfroute_net_t
*this;
1371 .get_features
= _get_features
,
1372 .get_interface
= _get_interface_name
,
1373 .create_address_enumerator
= _create_address_enumerator
,
1374 .get_source_addr
= _get_source_addr
,
1375 .get_nexthop
= _get_nexthop
,
1378 .add_route
= _add_route
,
1379 .del_route
= _del_route
,
1380 .destroy
= _destroy
,
1384 .ifaces
= linked_list_create(),
1385 .addrs
= hashtable_create(
1386 (hashtable_hash_t
)addr_map_entry_hash
,
1387 (hashtable_equals_t
)addr_map_entry_equals
, 16),
1388 .tuns
= linked_list_create(),
1389 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
1390 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
1391 .condvar
= condvar_create(CONDVAR_TYPE_DEFAULT
),
1392 .vip_wait
= lib
->settings
->get_int(lib
->settings
,
1393 "%s.plugins.kernel-pfroute.vip_wait", 1000, hydra
->daemon
),
1396 /* create a PF_ROUTE socket to communicate with the kernel */
1397 this->socket
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
1398 if (this->socket
== -1)
1400 DBG1(DBG_KNL
, "unable to create PF_ROUTE socket");
1405 if (streq(hydra
->daemon
, "starter"))
1407 /* starter has no threads, so we do not register for kernel events */
1408 if (shutdown(this->socket
, SHUT_RD
) != 0)
1410 DBG1(DBG_KNL
, "closing read end of PF_ROUTE socket failed: %s",
1416 lib
->processor
->queue_job(lib
->processor
,
1417 (job_t
*)callback_job_create_with_prio(
1418 (callback_job_cb_t
)receive_events
, this, NULL
,
1419 (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
1421 if (init_address_list(this) != SUCCESS
)
1423 DBG1(DBG_KNL
, "unable to get interface list");
1428 return &this->public;