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
253 * Add an address map entry
255 static void addr_map_entry_add(private_kernel_pfroute_net_t
*this,
256 addr_entry_t
*addr
, iface_entry_t
*iface
)
258 addr_map_entry_t
*entry
;
261 { /* don't map virtual IPs */
269 entry
= this->addrs
->put(this->addrs
, entry
, entry
);
274 * Remove an address map entry (the argument order is a bit strange because
275 * it is also used with linked_list_t.invoke_function)
277 static void addr_map_entry_remove(addr_entry_t
*addr
, iface_entry_t
*iface
,
278 private_kernel_pfroute_net_t
*this)
280 addr_map_entry_t
*entry
, lookup
= {
286 { /* these are never mapped, but this check avoid problems if a virtual IP
287 * equals a regular one */
290 entry
= this->addrs
->remove(this->addrs
, &lookup
);
295 * callback function that raises the delayed roam event
297 static job_requeue_t
roam_event(uintptr_t address
)
299 hydra
->kernel_interface
->roam(hydra
->kernel_interface
, address
!= 0);
300 return JOB_REQUEUE_NONE
;
304 * fire a roaming event. we delay it for a bit and fire only one event
305 * for multiple calls. otherwise we would create too many events.
307 static void fire_roam_event(private_kernel_pfroute_net_t
*this, bool address
)
312 time_monotonic(&now
);
313 if (timercmp(&now
, &this->last_roam
, >))
315 timeval_add_ms(&now
, ROAM_DELAY
);
316 this->last_roam
= now
;
318 job
= (job_t
*)callback_job_create((callback_job_cb_t
)roam_event
,
319 (void*)(uintptr_t)(address ?
1 : 0),
321 lib
->scheduler
->schedule_job_ms(lib
->scheduler
, job
, ROAM_DELAY
);
326 * Data for enumerator over rtmsg sockaddrs
329 /** implements enumerator */
331 /** copy of attribute bitfield */
333 /** bytes remaining in buffer */
335 /** next sockaddr to enumerate */
336 struct sockaddr
*addr
;
339 METHOD(enumerator_t
, rt_enumerate
, bool,
340 rt_enumerator_t
*this, int *xtype
, struct sockaddr
**addr
)
344 if (this->remaining
< sizeof(this->addr
->sa_len
) ||
345 this->remaining
< this->addr
->sa_len
)
349 for (i
= 0; i
< RTAX_MAX
; i
++)
352 if (this->types
& type
)
354 this->types
&= ~type
;
357 this->remaining
-= SA_LEN(this->addr
->sa_len
);
358 this->addr
= (struct sockaddr
*)((char*)this->addr
+
359 SA_LEN(this->addr
->sa_len
));
367 * Create a safe enumerator over sockaddrs in ifa/ifam/rt_msg
369 static enumerator_t
*create_rtmsg_enumerator(void *hdr
, size_t hdrlen
)
371 struct rt_msghdr
*rthdr
= hdr
;
372 rt_enumerator_t
*this;
376 .enumerate
= (void*)_rt_enumerate
,
377 .destroy
= (void*)free
,
379 .types
= rthdr
->rtm_addrs
,
380 .remaining
= rthdr
->rtm_msglen
- hdrlen
,
381 .addr
= hdr
+ hdrlen
,
383 return &this->public;
387 * Process an RTM_*ADDR message from the kernel
389 static void process_addr(private_kernel_pfroute_net_t
*this,
390 struct ifa_msghdr
*ifa
)
392 struct sockaddr
*sockaddr
;
394 enumerator_t
*ifaces
, *addrs
;
395 iface_entry_t
*iface
;
397 bool found
= FALSE
, changed
= FALSE
, roam
= FALSE
;
398 enumerator_t
*enumerator
;
401 enumerator
= create_rtmsg_enumerator(ifa
, sizeof(*ifa
));
402 while (enumerator
->enumerate(enumerator
, &type
, &sockaddr
))
404 if (type
== RTAX_IFA
)
406 host
= host_create_from_sockaddr(sockaddr
);
410 enumerator
->destroy(enumerator
);
417 this->lock
->write_lock(this->lock
);
418 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
419 while (ifaces
->enumerate(ifaces
, &iface
))
421 if (iface
->ifindex
== ifa
->ifam_index
)
423 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
424 while (addrs
->enumerate(addrs
, &addr
))
426 if (host
->ip_equals(host
, addr
->ip
))
429 if (ifa
->ifam_type
== RTM_DELADDR
)
431 iface
->addrs
->remove_at(iface
->addrs
, addrs
);
432 if (!addr
->virtual && iface
->usable
)
435 DBG1(DBG_KNL
, "%H disappeared from %s",
436 host
, iface
->ifname
);
438 addr_map_entry_remove(addr
, iface
, this);
439 addr_entry_destroy(addr
);
443 addrs
->destroy(addrs
);
445 if (!found
&& ifa
->ifam_type
== RTM_NEWADDR
)
448 .ip
= host
->clone(host
),
451 iface
->addrs
->insert_last(iface
->addrs
, addr
);
452 addr_map_entry_add(this, addr
, iface
);
455 DBG1(DBG_KNL
, "%H appeared on %s", host
, iface
->ifname
);
459 if (changed
&& iface_entry_up_and_usable(iface
))
466 ifaces
->destroy(ifaces
);
467 this->lock
->unlock(this->lock
);
472 fire_roam_event(this, TRUE
);
477 * Re-initialize address list of an interface if it changes state
479 static void repopulate_iface(private_kernel_pfroute_net_t
*this,
480 iface_entry_t
*iface
)
482 struct ifaddrs
*ifap
, *ifa
;
485 while (iface
->addrs
->remove_last(iface
->addrs
, (void**)&addr
) == SUCCESS
)
487 addr_map_entry_remove(addr
, iface
, this);
488 addr_entry_destroy(addr
);
491 if (getifaddrs(&ifap
) == 0)
493 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
495 if (ifa
->ifa_addr
&& streq(ifa
->ifa_name
, iface
->ifname
))
497 switch (ifa
->ifa_addr
->sa_family
)
502 .ip
= host_create_from_sockaddr(ifa
->ifa_addr
),
504 iface
->addrs
->insert_last(iface
->addrs
, addr
);
505 addr_map_entry_add(this, addr
, iface
);
517 * Process an RTM_IFINFO message from the kernel
519 static void process_link(private_kernel_pfroute_net_t
*this,
520 struct if_msghdr
*msg
)
522 enumerator_t
*enumerator
;
523 iface_entry_t
*iface
;
524 bool roam
= FALSE
, found
= FALSE
;
526 this->lock
->write_lock(this->lock
);
527 enumerator
= this->ifaces
->create_enumerator(this->ifaces
);
528 while (enumerator
->enumerate(enumerator
, &iface
))
530 if (iface
->ifindex
== msg
->ifm_index
)
534 if (!(iface
->flags
& IFF_UP
) && (msg
->ifm_flags
& IFF_UP
))
537 DBG1(DBG_KNL
, "interface %s activated", iface
->ifname
);
539 else if ((iface
->flags
& IFF_UP
) && !(msg
->ifm_flags
& IFF_UP
))
542 DBG1(DBG_KNL
, "interface %s deactivated", iface
->ifname
);
545 iface
->flags
= msg
->ifm_flags
;
546 repopulate_iface(this, iface
);
551 enumerator
->destroy(enumerator
);
556 .ifindex
= msg
->ifm_index
,
557 .flags
= msg
->ifm_flags
,
558 .addrs
= linked_list_create(),
560 if (if_indextoname(iface
->ifindex
, iface
->ifname
))
562 DBG1(DBG_KNL
, "interface %s appeared", iface
->ifname
);
563 iface
->usable
= hydra
->kernel_interface
->is_interface_usable(
564 hydra
->kernel_interface
, iface
->ifname
);
565 repopulate_iface(this, iface
);
566 this->ifaces
->insert_last(this->ifaces
, iface
);
573 this->lock
->unlock(this->lock
);
577 fire_roam_event(this, TRUE
);
582 * Process an RTM_*ROUTE message from the kernel
584 static void process_route(private_kernel_pfroute_net_t
*this,
585 struct rt_msghdr
*msg
)
591 * Receives PF_ROUTE messages from kernel
593 static job_requeue_t
receive_events(private_kernel_pfroute_net_t
*this)
597 struct rt_msghdr rtm
;
598 struct if_msghdr ifm
;
599 struct ifa_msghdr ifam
;
601 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
606 oldstate
= thread_cancelability(TRUE
);
607 len
= recv(this->socket
, &msg
, sizeof(msg
), 0);
608 thread_cancelability(oldstate
);
616 return JOB_REQUEUE_DIRECT
;
618 DBG1(DBG_KNL
, "unable to receive from PF_ROUTE event socket");
620 return JOB_REQUEUE_FAIR
;
624 if (len
< offsetof(struct rt_msghdr
, rtm_flags
) || len
< msg
.rtm
.rtm_msglen
)
626 DBG1(DBG_KNL
, "received invalid PF_ROUTE message");
627 return JOB_REQUEUE_DIRECT
;
629 if (msg
.rtm
.rtm_version
!= RTM_VERSION
)
631 DBG1(DBG_KNL
, "received PF_ROUTE message with unsupported version: %d",
632 msg
.rtm
.rtm_version
);
633 return JOB_REQUEUE_DIRECT
;
635 switch (msg
.rtm
.rtm_type
)
639 hdrlen
= sizeof(msg
.ifam
);
642 hdrlen
= sizeof(msg
.ifm
);
647 hdrlen
= sizeof(msg
.rtm
);
650 return JOB_REQUEUE_DIRECT
;
652 if (msg
.rtm
.rtm_msglen
< hdrlen
)
654 DBG1(DBG_KNL
, "ignoring short PF_ROUTE message");
655 return JOB_REQUEUE_DIRECT
;
657 switch (msg
.rtm
.rtm_type
)
661 process_addr(this, &msg
.ifam
);
664 process_link(this, &msg
.ifm
);
668 process_route(this, &msg
.rtm
);
674 this->mutex
->lock(this->mutex
);
675 if (msg
.rtm
.rtm_pid
== this->pid
&& msg
.rtm
.rtm_seq
== this->waiting_seq
)
677 /* seems like the message someone is waiting for, deliver */
678 this->reply
= realloc(this->reply
, msg
.rtm
.rtm_msglen
);
679 memcpy(this->reply
, &msg
, msg
.rtm
.rtm_msglen
);
681 /* signal on any event, add_ip()/del_ip() might wait for it */
682 this->condvar
->broadcast(this->condvar
);
683 this->mutex
->unlock(this->mutex
);
685 return JOB_REQUEUE_DIRECT
;
689 /** enumerator over addresses */
691 private_kernel_pfroute_net_t
* this;
692 /** which addresses to enumerate */
693 kernel_address_type_t which
;
694 } address_enumerator_t
;
697 * cleanup function for address enumerator
699 static void address_enumerator_destroy(address_enumerator_t
*data
)
701 data
->this->lock
->unlock(data
->this->lock
);
706 * filter for addresses
708 static bool filter_addresses(address_enumerator_t
*data
,
709 addr_entry_t
** in
, host_t
** out
)
712 if (!(data
->which
& ADDR_TYPE_VIRTUAL
) && (*in
)->virtual)
713 { /* skip virtual interfaces added by us */
716 if (!(data
->which
& ADDR_TYPE_REGULAR
) && !(*in
)->virtual)
717 { /* address is regular, but not requested */
721 if (ip
->get_family(ip
) == AF_INET6
)
723 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ip
->get_sockaddr(ip
);
724 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
725 { /* skip addresses with a unusable scope */
734 * enumerator constructor for interfaces
736 static enumerator_t
*create_iface_enumerator(iface_entry_t
*iface
,
737 address_enumerator_t
*data
)
739 return enumerator_create_filter(iface
->addrs
->create_enumerator(iface
->addrs
),
740 (void*)filter_addresses
, data
, NULL
);
744 * filter for interfaces
746 static bool filter_interfaces(address_enumerator_t
*data
, iface_entry_t
** in
,
749 if (!(data
->which
& ADDR_TYPE_IGNORED
) && !(*in
)->usable
)
750 { /* skip interfaces excluded by config */
753 if (!(data
->which
& ADDR_TYPE_LOOPBACK
) && ((*in
)->flags
& IFF_LOOPBACK
))
754 { /* ignore loopback devices */
757 if (!(data
->which
& ADDR_TYPE_DOWN
) && !((*in
)->flags
& IFF_UP
))
758 { /* skip interfaces not up */
765 METHOD(kernel_net_t
, create_address_enumerator
, enumerator_t
*,
766 private_kernel_pfroute_net_t
*this, kernel_address_type_t which
)
768 address_enumerator_t
*data
;
775 this->lock
->read_lock(this->lock
);
776 return enumerator_create_nested(
777 enumerator_create_filter(
778 this->ifaces
->create_enumerator(this->ifaces
),
779 (void*)filter_interfaces
, data
, NULL
),
780 (void*)create_iface_enumerator
, data
,
781 (void*)address_enumerator_destroy
);
784 METHOD(kernel_net_t
, get_features
, kernel_feature_t
,
785 private_kernel_pfroute_net_t
*this)
787 return KERNEL_REQUIRE_EXCLUDE_ROUTE
;
790 METHOD(kernel_net_t
, get_interface_name
, bool,
791 private_kernel_pfroute_net_t
*this, host_t
* ip
, char **name
)
793 addr_map_entry_t
*entry
, lookup
= {
797 if (ip
->is_anyaddr(ip
))
801 this->lock
->read_lock(this->lock
);
802 /* first try to find it on an up and usable interface */
803 entry
= this->addrs
->get_match(this->addrs
, &lookup
,
804 (void*)addr_map_entry_match_up_and_usable
);
809 *name
= strdup(entry
->iface
->ifname
);
810 DBG2(DBG_KNL
, "%H is on interface %s", ip
, *name
);
812 this->lock
->unlock(this->lock
);
815 /* maybe it is installed on an ignored interface */
816 entry
= this->addrs
->get_match(this->addrs
, &lookup
,
817 (void*)addr_map_entry_match_up
);
819 { /* the address does not exist, is on a down interface */
820 DBG2(DBG_KNL
, "%H is not a local address or the interface is down", ip
);
822 this->lock
->unlock(this->lock
);
826 METHOD(kernel_net_t
, add_ip
, status_t
,
827 private_kernel_pfroute_net_t
*this, host_t
*vip
, int prefix
,
830 enumerator_t
*ifaces
, *addrs
;
831 iface_entry_t
*iface
;
834 bool timeout
= FALSE
;
836 tun
= tun_device_create(NULL
);
843 prefix
= vip
->get_address(vip
).len
* 8;
845 if (!tun
->up(tun
) || !tun
->set_address(tun
, vip
, prefix
))
851 /* wait until address appears */
852 this->mutex
->lock(this->mutex
);
853 while (!timeout
&& !get_interface_name(this, vip
, NULL
))
855 timeout
= this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000);
857 this->mutex
->unlock(this->mutex
);
860 DBG1(DBG_KNL
, "virtual IP %H did not appear on %s",
861 vip
, tun
->get_name(tun
));
866 this->lock
->write_lock(this->lock
);
867 this->tuns
->insert_last(this->tuns
, tun
);
869 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
870 while (ifaces
->enumerate(ifaces
, &iface
))
872 if (streq(iface
->ifname
, tun
->get_name(tun
)))
874 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
875 while (addrs
->enumerate(addrs
, &addr
))
877 if (addr
->ip
->ip_equals(addr
->ip
, vip
))
879 addr
->virtual = TRUE
;
882 addrs
->destroy(addrs
);
885 ifaces
->destroy(ifaces
);
886 /* lets do this while holding the lock, thus preventing another thread
887 * from deleting the TUN device concurrently, hopefully listeneres are quick
888 * and cause no deadlocks */
889 hydra
->kernel_interface
->tun(hydra
->kernel_interface
, tun
, TRUE
);
890 this->lock
->unlock(this->lock
);
895 METHOD(kernel_net_t
, del_ip
, status_t
,
896 private_kernel_pfroute_net_t
*this, host_t
*vip
, int prefix
,
899 enumerator_t
*enumerator
;
902 bool timeout
= FALSE
, found
= FALSE
;
904 this->lock
->write_lock(this->lock
);
905 enumerator
= this->tuns
->create_enumerator(this->tuns
);
906 while (enumerator
->enumerate(enumerator
, &tun
))
908 addr
= tun
->get_address(tun
, NULL
);
909 if (addr
&& addr
->ip_equals(addr
, vip
))
911 this->tuns
->remove_at(this->tuns
, enumerator
);
912 hydra
->kernel_interface
->tun(hydra
->kernel_interface
, tun
,
919 enumerator
->destroy(enumerator
);
920 this->lock
->unlock(this->lock
);
926 /* wait until address disappears */
929 this->mutex
->lock(this->mutex
);
930 while (!timeout
&& get_interface_name(this, vip
, NULL
))
932 timeout
= this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000);
934 this->mutex
->unlock(this->mutex
);
937 DBG1(DBG_KNL
, "virtual IP %H did not disappear from tun", vip
);
945 * Append a sockaddr_in/in6 of given type to routing message
947 static void add_rt_addr(struct rt_msghdr
*hdr
, int type
, host_t
*addr
)
953 len
= *addr
->get_sockaddr_len(addr
);
954 memcpy((char*)hdr
+ hdr
->rtm_msglen
, addr
->get_sockaddr(addr
), len
);
955 hdr
->rtm_msglen
+= SA_LEN(len
);
956 hdr
->rtm_addrs
|= type
;
961 * Append a subnet mask sockaddr using the given prefix to routing message
963 static void add_rt_mask(struct rt_msghdr
*hdr
, int type
, int family
, int prefix
)
967 mask
= host_create_netmask(family
, prefix
);
970 add_rt_addr(hdr
, type
, mask
);
976 * Append an interface name sockaddr_dl to routing message
978 static void add_rt_ifname(struct rt_msghdr
*hdr
, int type
, char *name
)
980 struct sockaddr_dl sdl
= {
981 .sdl_len
= sizeof(struct sockaddr_dl
),
982 .sdl_family
= AF_LINK
,
983 .sdl_nlen
= strlen(name
),
986 if (strlen(name
) <= sizeof(sdl
.sdl_data
))
988 memcpy(sdl
.sdl_data
, name
, sdl
.sdl_nlen
);
989 memcpy((char*)hdr
+ hdr
->rtm_msglen
, &sdl
, sdl
.sdl_len
);
990 hdr
->rtm_msglen
+= SA_LEN(sdl
.sdl_len
);
991 hdr
->rtm_addrs
|= type
;
996 * Add or remove a route
998 static status_t
manage_route(private_kernel_pfroute_net_t
*this, int op
,
999 chunk_t dst_net
, u_int8_t prefixlen
,
1000 host_t
*gateway
, char *if_name
)
1003 struct rt_msghdr hdr
;
1004 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
1007 .rtm_version
= RTM_VERSION
,
1009 .rtm_flags
= RTF_UP
| RTF_STATIC
,
1010 .rtm_pid
= this->pid
,
1011 .rtm_seq
= ++this->seq
,
1017 if (prefixlen
== 0 && dst_net
.len
)
1022 half
= chunk_clonea(dst_net
);
1023 half
.ptr
[0] |= 0x80;
1025 status
= manage_route(this, op
, half
, prefixlen
, gateway
, if_name
);
1026 if (status
!= SUCCESS
)
1032 dst
= host_create_from_chunk(AF_UNSPEC
, dst_net
, 0);
1038 if ((dst
->get_family(dst
) == AF_INET
&& prefixlen
== 32) ||
1039 (dst
->get_family(dst
) == AF_INET6
&& prefixlen
== 128))
1041 msg
.hdr
.rtm_flags
|= RTF_HOST
| RTF_GATEWAY
;
1044 msg
.hdr
.rtm_msglen
= sizeof(struct rt_msghdr
);
1045 for (type
= 0; type
< RTAX_MAX
; type
++)
1050 add_rt_addr(&msg
.hdr
, RTA_DST
, dst
);
1053 if (!(msg
.hdr
.rtm_flags
& RTF_HOST
))
1055 add_rt_mask(&msg
.hdr
, RTA_NETMASK
,
1056 dst
->get_family(dst
), prefixlen
);
1062 add_rt_ifname(&msg
.hdr
, RTA_IFP
, if_name
);
1068 add_rt_addr(&msg
.hdr
, RTA_GATEWAY
, gateway
);
1077 if (send(this->socket
, &msg
, msg
.hdr
.rtm_msglen
, 0) != msg
.hdr
.rtm_msglen
)
1079 DBG1(DBG_KNL
, "%s PF_ROUTE route failed: %s",
1080 op
== RTM_ADD ?
"adding" : "deleting", strerror(errno
));
1086 METHOD(kernel_net_t
, add_route
, status_t
,
1087 private_kernel_pfroute_net_t
*this, chunk_t dst_net
, u_int8_t prefixlen
,
1088 host_t
*gateway
, host_t
*src_ip
, char *if_name
)
1090 return manage_route(this, RTM_ADD
, dst_net
, prefixlen
, gateway
, if_name
);
1093 METHOD(kernel_net_t
, del_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_DELETE
, dst_net
, prefixlen
, gateway
, if_name
);
1101 * Do a route lookup for dest and return either the nexthop or the source
1104 static host_t
*get_route(private_kernel_pfroute_net_t
*this, bool nexthop
,
1105 host_t
*dest
, host_t
*src
)
1108 struct rt_msghdr hdr
;
1109 char buf
[sizeof(struct sockaddr_storage
) * RTAX_MAX
];
1112 .rtm_version
= RTM_VERSION
,
1113 .rtm_type
= RTM_GET
,
1114 .rtm_pid
= this->pid
,
1115 .rtm_seq
= ++this->seq
,
1118 host_t
*host
= NULL
;
1119 enumerator_t
*enumerator
;
1120 struct sockaddr
*addr
;
1123 msg
.hdr
.rtm_msglen
= sizeof(struct rt_msghdr
);
1124 for (type
= 0; type
< RTAX_MAX
; type
++)
1129 add_rt_addr(&msg
.hdr
, RTA_DST
, dest
);
1132 add_rt_addr(&msg
.hdr
, RTA_IFA
, src
);
1136 { /* add an empty IFP to ensure we get a source address */
1137 add_rt_ifname(&msg
.hdr
, RTA_IFP
, "");
1144 this->mutex
->lock(this->mutex
);
1146 while (this->waiting_seq
)
1148 this->condvar
->wait(this->condvar
, this->mutex
);
1150 this->waiting_seq
= msg
.hdr
.rtm_seq
;
1151 if (send(this->socket
, &msg
, msg
.hdr
.rtm_msglen
, 0) == msg
.hdr
.rtm_msglen
)
1155 if (this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000))
1159 if (this->reply
->rtm_msglen
< sizeof(*this->reply
) ||
1160 msg
.hdr
.rtm_seq
!= this->reply
->rtm_seq
)
1164 enumerator
= create_rtmsg_enumerator(this->reply
,
1165 sizeof(*this->reply
));
1166 while (enumerator
->enumerate(enumerator
, &type
, &addr
))
1170 if (type
== RTAX_DST
&& this->reply
->rtm_flags
& RTF_HOST
)
1171 { /* probably a cloned/cached direct route, only use that
1172 * as fallback if no gateway is found */
1173 host
= host ?
: host_create_from_sockaddr(addr
);
1175 if (type
== RTAX_GATEWAY
)
1176 { /* could actually be a MAC address */
1177 host_t
*gtw
= host_create_from_sockaddr(addr
);
1187 if (type
== RTAX_IFA
)
1189 host
= host_create_from_sockaddr(addr
);
1193 enumerator
->destroy(enumerator
);
1199 DBG1(DBG_KNL
, "PF_ROUTE lookup failed: %s", strerror(errno
));
1201 /* signal completion of query to a waiting thread */
1202 this->waiting_seq
= 0;
1203 this->condvar
->signal(this->condvar
);
1204 this->mutex
->unlock(this->mutex
);
1208 DBG2(DBG_KNL
, "using %H as %s to reach %H", host
,
1209 nexthop ?
"nexthop" : "address", dest
);
1214 METHOD(kernel_net_t
, get_source_addr
, host_t
*,
1215 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
1217 return get_route(this, FALSE
, dest
, src
);
1220 METHOD(kernel_net_t
, get_nexthop
, host_t
*,
1221 private_kernel_pfroute_net_t
*this, host_t
*dest
, host_t
*src
)
1223 return get_route(this, TRUE
, dest
, src
);
1227 * Initialize a list of local addresses.
1229 static status_t
init_address_list(private_kernel_pfroute_net_t
*this)
1231 struct ifaddrs
*ifap
, *ifa
;
1232 iface_entry_t
*iface
, *current
;
1234 enumerator_t
*ifaces
, *addrs
;
1236 DBG2(DBG_KNL
, "known interfaces and IP addresses:");
1238 if (getifaddrs(&ifap
) < 0)
1240 DBG1(DBG_KNL
, " failed to get interfaces!");
1244 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
1246 if (ifa
->ifa_addr
== NULL
)
1250 switch(ifa
->ifa_addr
->sa_family
)
1257 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
1258 while (ifaces
->enumerate(ifaces
, ¤t
))
1260 if (streq(current
->ifname
, ifa
->ifa_name
))
1266 ifaces
->destroy(ifaces
);
1271 .ifindex
= if_nametoindex(ifa
->ifa_name
),
1272 .flags
= ifa
->ifa_flags
,
1273 .addrs
= linked_list_create(),
1274 .usable
= hydra
->kernel_interface
->is_interface_usable(
1275 hydra
->kernel_interface
, ifa
->ifa_name
),
1277 memcpy(iface
->ifname
, ifa
->ifa_name
, IFNAMSIZ
);
1278 this->ifaces
->insert_last(this->ifaces
, iface
);
1281 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
1284 .ip
= host_create_from_sockaddr(ifa
->ifa_addr
),
1286 iface
->addrs
->insert_last(iface
->addrs
, addr
);
1287 addr_map_entry_add(this, addr
, iface
);
1294 ifaces
= this->ifaces
->create_enumerator(this->ifaces
);
1295 while (ifaces
->enumerate(ifaces
, &iface
))
1297 if (iface
->usable
&& iface
->flags
& IFF_UP
)
1299 DBG2(DBG_KNL
, " %s", iface
->ifname
);
1300 addrs
= iface
->addrs
->create_enumerator(iface
->addrs
);
1301 while (addrs
->enumerate(addrs
, (void**)&addr
))
1303 DBG2(DBG_KNL
, " %H", addr
->ip
);
1305 addrs
->destroy(addrs
);
1308 ifaces
->destroy(ifaces
);
1313 METHOD(kernel_net_t
, destroy
, void,
1314 private_kernel_pfroute_net_t
*this)
1316 enumerator_t
*enumerator
;
1319 if (this->socket
!= -1)
1321 close(this->socket
);
1323 enumerator
= this->addrs
->create_enumerator(this->addrs
);
1324 while (enumerator
->enumerate(enumerator
, NULL
, (void**)&addr
))
1328 enumerator
->destroy(enumerator
);
1329 this->addrs
->destroy(this->addrs
);
1330 this->ifaces
->destroy_function(this->ifaces
, (void*)iface_entry_destroy
);
1331 this->tuns
->destroy(this->tuns
);
1332 this->lock
->destroy(this->lock
);
1333 this->mutex
->destroy(this->mutex
);
1334 this->condvar
->destroy(this->condvar
);
1340 * Described in header.
1342 kernel_pfroute_net_t
*kernel_pfroute_net_create()
1344 private_kernel_pfroute_net_t
*this;
1349 .get_features
= _get_features
,
1350 .get_interface
= _get_interface_name
,
1351 .create_address_enumerator
= _create_address_enumerator
,
1352 .get_source_addr
= _get_source_addr
,
1353 .get_nexthop
= _get_nexthop
,
1356 .add_route
= _add_route
,
1357 .del_route
= _del_route
,
1358 .destroy
= _destroy
,
1362 .ifaces
= linked_list_create(),
1363 .addrs
= hashtable_create(
1364 (hashtable_hash_t
)addr_map_entry_hash
,
1365 (hashtable_equals_t
)addr_map_entry_equals
, 16),
1366 .tuns
= linked_list_create(),
1367 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
1368 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
1369 .condvar
= condvar_create(CONDVAR_TYPE_DEFAULT
),
1372 /* create a PF_ROUTE socket to communicate with the kernel */
1373 this->socket
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
1374 if (this->socket
== -1)
1376 DBG1(DBG_KNL
, "unable to create PF_ROUTE socket");
1381 if (streq(hydra
->daemon
, "starter"))
1383 /* starter has no threads, so we do not register for kernel events */
1384 if (shutdown(this->socket
, SHUT_RD
) != 0)
1386 DBG1(DBG_KNL
, "closing read end of PF_ROUTE socket failed: %s",
1392 lib
->processor
->queue_job(lib
->processor
,
1393 (job_t
*)callback_job_create_with_prio(
1394 (callback_job_cb_t
)receive_events
, this, NULL
,
1395 (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
1397 if (init_address_list(this) != SUCCESS
)
1399 DBG1(DBG_KNL
, "unable to get interface list");
1404 return &this->public;