]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c
kernel-pfroute: Make time that is waited for VIPs to appear configurable
[people/ms/strongswan.git] / src / libhydra / plugins / kernel_pfroute / kernel_pfroute_net.c
1 /*
2 * Copyright (C) 2009-2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <net/if.h>
19 #include <net/if_dl.h>
20 #include <ifaddrs.h>
21 #include <net/route.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #include "kernel_pfroute_net.h"
26
27 #include <hydra.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>
38
39 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
40 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
41 #endif
42
43 /** properly align sockaddrs */
44 #ifdef __APPLE__
45 /* Apple always uses 4 bytes */
46 #define SA_ALIGN 4
47 #else
48 /* while on other platforms like FreeBSD it depends on the architecture */
49 #define SA_ALIGN sizeof(long)
50 #endif
51 #define SA_LEN(len) ((len) > 0 ? (((len)+SA_ALIGN-1) & ~(SA_ALIGN-1)) : SA_ALIGN)
52
53 /** delay before firing roam events (ms) */
54 #define ROAM_DELAY 100
55
56 typedef struct addr_entry_t addr_entry_t;
57
58 /**
59 * IP address in an inface_entry_t
60 */
61 struct addr_entry_t {
62
63 /** The ip address */
64 host_t *ip;
65
66 /** virtual IP managed by us */
67 bool virtual;
68 };
69
70 /**
71 * destroy a addr_entry_t object
72 */
73 static void addr_entry_destroy(addr_entry_t *this)
74 {
75 this->ip->destroy(this->ip);
76 free(this);
77 }
78
79 typedef struct iface_entry_t iface_entry_t;
80
81 /**
82 * A network interface on this system, containing addr_entry_t's
83 */
84 struct iface_entry_t {
85
86 /** interface index */
87 int ifindex;
88
89 /** name of the interface */
90 char ifname[IFNAMSIZ];
91
92 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
93 u_int flags;
94
95 /** list of addresses as host_t */
96 linked_list_t *addrs;
97
98 /** TRUE if usable by config */
99 bool usable;
100 };
101
102 /**
103 * destroy an interface entry
104 */
105 static void iface_entry_destroy(iface_entry_t *this)
106 {
107 this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
108 free(this);
109 }
110
111 /**
112 * check if an interface is up
113 */
114 static inline bool iface_entry_up(iface_entry_t *iface)
115 {
116 return (iface->flags & IFF_UP) == IFF_UP;
117 }
118
119 /**
120 * check if an interface is up and usable
121 */
122 static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
123 {
124 return iface->usable && iface_entry_up(iface);
125 }
126
127 typedef struct addr_map_entry_t addr_map_entry_t;
128
129 /**
130 * Entry that maps an IP address to an interface entry
131 */
132 struct addr_map_entry_t {
133 /** The IP address */
134 host_t *ip;
135
136 /** The interface this address is installed on */
137 iface_entry_t *iface;
138 };
139
140 /**
141 * Hash a addr_map_entry_t object, all entries with the same IP address
142 * are stored in the same bucket
143 */
144 static u_int addr_map_entry_hash(addr_map_entry_t *this)
145 {
146 return chunk_hash(this->ip->get_address(this->ip));
147 }
148
149 /**
150 * Compare two addr_map_entry_t objects, two entries are equal if they are
151 * installed on the same interface
152 */
153 static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b)
154 {
155 return a->iface->ifindex == b->iface->ifindex &&
156 a->ip->ip_equals(a->ip, b->ip);
157 }
158
159 /**
160 * Used with get_match this finds an address entry if it is installed on
161 * an up and usable interface
162 */
163 static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a,
164 addr_map_entry_t *b)
165 {
166 return iface_entry_up_and_usable(b->iface) &&
167 a->ip->ip_equals(a->ip, b->ip);
168 }
169
170 /**
171 * Used with get_match this finds an address entry if it is installed on
172 * any active local interface
173 */
174 static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b)
175 {
176 return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip);
177 }
178
179 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t;
180
181 /**
182 * Private variables and functions of kernel_pfroute class.
183 */
184 struct private_kernel_pfroute_net_t
185 {
186 /**
187 * Public part of the kernel_pfroute_t object.
188 */
189 kernel_pfroute_net_t public;
190
191 /**
192 * lock to access lists and maps
193 */
194 rwlock_t *lock;
195
196 /**
197 * Cached list of interfaces and their addresses (iface_entry_t)
198 */
199 linked_list_t *ifaces;
200
201 /**
202 * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
203 */
204 hashtable_t *addrs;
205
206 /**
207 * List of tun devices we installed for virtual IPs
208 */
209 linked_list_t *tuns;
210
211 /**
212 * mutex to communicate exclusively with PF_KEY
213 */
214 mutex_t *mutex;
215
216 /**
217 * condvar to signal if PF_KEY query got a response
218 */
219 condvar_t *condvar;
220
221 /**
222 * pid to send PF_ROUTE messages with
223 */
224 pid_t pid;
225
226 /**
227 * PF_ROUTE socket to communicate with the kernel
228 */
229 int socket;
230
231 /**
232 * sequence number for messages sent to the kernel
233 */
234 int seq;
235
236 /**
237 * Sequence number a query is waiting for
238 */
239 int waiting_seq;
240
241 /**
242 * Allocated reply message from kernel
243 */
244 struct rt_msghdr *reply;
245
246 /**
247 * time of last roam event
248 */
249 timeval_t last_roam;
250
251 /**
252 * Time in ms to wait for IP addresses to appear/disappear
253 */
254 int vip_wait;
255 };
256
257 /**
258 * Add an address map entry
259 */
260 static void addr_map_entry_add(private_kernel_pfroute_net_t *this,
261 addr_entry_t *addr, iface_entry_t *iface)
262 {
263 addr_map_entry_t *entry;
264
265 if (addr->virtual)
266 { /* don't map virtual IPs */
267 return;
268 }
269
270 INIT(entry,
271 .ip = addr->ip,
272 .iface = iface,
273 );
274 entry = this->addrs->put(this->addrs, entry, entry);
275 free(entry);
276 }
277
278 /**
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)
281 */
282 static void addr_map_entry_remove(addr_entry_t *addr, iface_entry_t *iface,
283 private_kernel_pfroute_net_t *this)
284 {
285 addr_map_entry_t *entry, lookup = {
286 .ip = addr->ip,
287 .iface = iface,
288 };
289
290 if (addr->virtual)
291 { /* these are never mapped, but this check avoid problems if a virtual IP
292 * equals a regular one */
293 return;
294 }
295 entry = this->addrs->remove(this->addrs, &lookup);
296 free(entry);
297 }
298
299 /**
300 * callback function that raises the delayed roam event
301 */
302 static job_requeue_t roam_event(uintptr_t address)
303 {
304 hydra->kernel_interface->roam(hydra->kernel_interface, address != 0);
305 return JOB_REQUEUE_NONE;
306 }
307
308 /**
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.
311 */
312 static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
313 {
314 timeval_t now;
315 job_t *job;
316
317 time_monotonic(&now);
318 if (timercmp(&now, &this->last_roam, >))
319 {
320 timeval_add_ms(&now, ROAM_DELAY);
321 this->last_roam = now;
322
323 job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
324 (void*)(uintptr_t)(address ? 1 : 0),
325 NULL, NULL);
326 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
327 }
328 }
329
330 /**
331 * Data for enumerator over rtmsg sockaddrs
332 */
333 typedef struct {
334 /** implements enumerator */
335 enumerator_t public;
336 /** copy of attribute bitfield */
337 int types;
338 /** bytes remaining in buffer */
339 int remaining;
340 /** next sockaddr to enumerate */
341 struct sockaddr *addr;
342 } rt_enumerator_t;
343
344 METHOD(enumerator_t, rt_enumerate, bool,
345 rt_enumerator_t *this, int *xtype, struct sockaddr **addr)
346 {
347 int i, type;
348
349 if (this->remaining < sizeof(this->addr->sa_len) ||
350 this->remaining < this->addr->sa_len)
351 {
352 return FALSE;
353 }
354 for (i = 0; i < RTAX_MAX; i++)
355 {
356 type = (1 << i);
357 if (this->types & type)
358 {
359 this->types &= ~type;
360 *addr = this->addr;
361 *xtype = i;
362 this->remaining -= SA_LEN(this->addr->sa_len);
363 this->addr = (struct sockaddr*)((char*)this->addr +
364 SA_LEN(this->addr->sa_len));
365 return TRUE;
366 }
367 }
368 return FALSE;
369 }
370
371 /**
372 * Create a safe enumerator over sockaddrs in ifa/ifam/rt_msg
373 */
374 static enumerator_t *create_rtmsg_enumerator(void *hdr, size_t hdrlen)
375 {
376 struct rt_msghdr *rthdr = hdr;
377 rt_enumerator_t *this;
378
379 INIT(this,
380 .public = {
381 .enumerate = (void*)_rt_enumerate,
382 .destroy = (void*)free,
383 },
384 .types = rthdr->rtm_addrs,
385 .remaining = rthdr->rtm_msglen - hdrlen,
386 .addr = hdr + hdrlen,
387 );
388 return &this->public;
389 }
390
391 /**
392 * Process an RTM_*ADDR message from the kernel
393 */
394 static void process_addr(private_kernel_pfroute_net_t *this,
395 struct ifa_msghdr *ifa)
396 {
397 struct sockaddr *sockaddr;
398 host_t *host = NULL;
399 enumerator_t *ifaces, *addrs;
400 iface_entry_t *iface;
401 addr_entry_t *addr;
402 bool found = FALSE, changed = FALSE, roam = FALSE;
403 enumerator_t *enumerator;
404 int type;
405
406 enumerator = create_rtmsg_enumerator(ifa, sizeof(*ifa));
407 while (enumerator->enumerate(enumerator, &type, &sockaddr))
408 {
409 if (type == RTAX_IFA)
410 {
411 host = host_create_from_sockaddr(sockaddr);
412 break;
413 }
414 }
415 enumerator->destroy(enumerator);
416
417 if (!host)
418 {
419 return;
420 }
421
422 this->lock->write_lock(this->lock);
423 ifaces = this->ifaces->create_enumerator(this->ifaces);
424 while (ifaces->enumerate(ifaces, &iface))
425 {
426 if (iface->ifindex == ifa->ifam_index)
427 {
428 addrs = iface->addrs->create_enumerator(iface->addrs);
429 while (addrs->enumerate(addrs, &addr))
430 {
431 if (host->ip_equals(host, addr->ip))
432 {
433 found = TRUE;
434 if (ifa->ifam_type == RTM_DELADDR)
435 {
436 iface->addrs->remove_at(iface->addrs, addrs);
437 if (!addr->virtual && iface->usable)
438 {
439 changed = TRUE;
440 DBG1(DBG_KNL, "%H disappeared from %s",
441 host, iface->ifname);
442 }
443 addr_map_entry_remove(addr, iface, this);
444 addr_entry_destroy(addr);
445 }
446 }
447 }
448 addrs->destroy(addrs);
449
450 if (!found && ifa->ifam_type == RTM_NEWADDR)
451 {
452 INIT(addr,
453 .ip = host->clone(host),
454 );
455 changed = TRUE;
456 iface->addrs->insert_last(iface->addrs, addr);
457 addr_map_entry_add(this, addr, iface);
458 if (iface->usable)
459 {
460 DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
461 }
462 }
463
464 if (changed && iface_entry_up_and_usable(iface))
465 {
466 roam = TRUE;
467 }
468 break;
469 }
470 }
471 ifaces->destroy(ifaces);
472 this->lock->unlock(this->lock);
473 host->destroy(host);
474
475 if (roam)
476 {
477 fire_roam_event(this, TRUE);
478 }
479 }
480
481 /**
482 * Re-initialize address list of an interface if it changes state
483 */
484 static void repopulate_iface(private_kernel_pfroute_net_t *this,
485 iface_entry_t *iface)
486 {
487 struct ifaddrs *ifap, *ifa;
488 addr_entry_t *addr;
489
490 while (iface->addrs->remove_last(iface->addrs, (void**)&addr) == SUCCESS)
491 {
492 addr_map_entry_remove(addr, iface, this);
493 addr_entry_destroy(addr);
494 }
495
496 if (getifaddrs(&ifap) == 0)
497 {
498 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
499 {
500 if (ifa->ifa_addr && streq(ifa->ifa_name, iface->ifname))
501 {
502 switch (ifa->ifa_addr->sa_family)
503 {
504 case AF_INET:
505 case AF_INET6:
506 INIT(addr,
507 .ip = host_create_from_sockaddr(ifa->ifa_addr),
508 );
509 iface->addrs->insert_last(iface->addrs, addr);
510 addr_map_entry_add(this, addr, iface);
511 break;
512 default:
513 break;
514 }
515 }
516 }
517 freeifaddrs(ifap);
518 }
519 }
520
521 /**
522 * Process an RTM_IFINFO message from the kernel
523 */
524 static void process_link(private_kernel_pfroute_net_t *this,
525 struct if_msghdr *msg)
526 {
527 enumerator_t *enumerator;
528 iface_entry_t *iface;
529 bool roam = FALSE, found = FALSE;
530
531 this->lock->write_lock(this->lock);
532 enumerator = this->ifaces->create_enumerator(this->ifaces);
533 while (enumerator->enumerate(enumerator, &iface))
534 {
535 if (iface->ifindex == msg->ifm_index)
536 {
537 if (iface->usable)
538 {
539 if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP))
540 {
541 roam = TRUE;
542 DBG1(DBG_KNL, "interface %s activated", iface->ifname);
543 }
544 else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP))
545 {
546 roam = TRUE;
547 DBG1(DBG_KNL, "interface %s deactivated", iface->ifname);
548 }
549 }
550 iface->flags = msg->ifm_flags;
551 repopulate_iface(this, iface);
552 found = TRUE;
553 break;
554 }
555 }
556 enumerator->destroy(enumerator);
557
558 if (!found)
559 {
560 INIT(iface,
561 .ifindex = msg->ifm_index,
562 .flags = msg->ifm_flags,
563 .addrs = linked_list_create(),
564 );
565 if (if_indextoname(iface->ifindex, iface->ifname))
566 {
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);
572 }
573 else
574 {
575 free(iface);
576 }
577 }
578 this->lock->unlock(this->lock);
579
580 if (roam)
581 {
582 fire_roam_event(this, TRUE);
583 }
584 }
585
586 /**
587 * Process an RTM_*ROUTE message from the kernel
588 */
589 static void process_route(private_kernel_pfroute_net_t *this,
590 struct rt_msghdr *msg)
591 {
592
593 }
594
595 /**
596 * Receives PF_ROUTE messages from kernel
597 */
598 static job_requeue_t receive_events(private_kernel_pfroute_net_t *this)
599 {
600 struct {
601 union {
602 struct rt_msghdr rtm;
603 struct if_msghdr ifm;
604 struct ifa_msghdr ifam;
605 };
606 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
607 } msg;
608 int len, hdrlen;
609 bool oldstate;
610
611 oldstate = thread_cancelability(TRUE);
612 len = recv(this->socket, &msg, sizeof(msg), 0);
613 thread_cancelability(oldstate);
614
615 if (len < 0)
616 {
617 switch (errno)
618 {
619 case EINTR:
620 case EAGAIN:
621 return JOB_REQUEUE_DIRECT;
622 default:
623 DBG1(DBG_KNL, "unable to receive from PF_ROUTE event socket");
624 sleep(1);
625 return JOB_REQUEUE_FAIR;
626 }
627 }
628
629 if (len < offsetof(struct rt_msghdr, rtm_flags) || len < msg.rtm.rtm_msglen)
630 {
631 DBG1(DBG_KNL, "received invalid PF_ROUTE message");
632 return JOB_REQUEUE_DIRECT;
633 }
634 if (msg.rtm.rtm_version != RTM_VERSION)
635 {
636 DBG1(DBG_KNL, "received PF_ROUTE message with unsupported version: %d",
637 msg.rtm.rtm_version);
638 return JOB_REQUEUE_DIRECT;
639 }
640 switch (msg.rtm.rtm_type)
641 {
642 case RTM_NEWADDR:
643 case RTM_DELADDR:
644 hdrlen = sizeof(msg.ifam);
645 break;
646 case RTM_IFINFO:
647 hdrlen = sizeof(msg.ifm);
648 break;
649 case RTM_ADD:
650 case RTM_DELETE:
651 case RTM_GET:
652 hdrlen = sizeof(msg.rtm);
653 break;
654 default:
655 return JOB_REQUEUE_DIRECT;
656 }
657 if (msg.rtm.rtm_msglen < hdrlen)
658 {
659 DBG1(DBG_KNL, "ignoring short PF_ROUTE message");
660 return JOB_REQUEUE_DIRECT;
661 }
662 switch (msg.rtm.rtm_type)
663 {
664 case RTM_NEWADDR:
665 case RTM_DELADDR:
666 process_addr(this, &msg.ifam);
667 break;
668 case RTM_IFINFO:
669 process_link(this, &msg.ifm);
670 break;
671 case RTM_ADD:
672 case RTM_DELETE:
673 process_route(this, &msg.rtm);
674 break;
675 default:
676 break;
677 }
678
679 this->mutex->lock(this->mutex);
680 if (msg.rtm.rtm_pid == this->pid && msg.rtm.rtm_seq == this->waiting_seq)
681 {
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);
685 }
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);
689
690 return JOB_REQUEUE_DIRECT;
691 }
692
693
694 /** enumerator over addresses */
695 typedef struct {
696 private_kernel_pfroute_net_t* this;
697 /** which addresses to enumerate */
698 kernel_address_type_t which;
699 } address_enumerator_t;
700
701 /**
702 * cleanup function for address enumerator
703 */
704 static void address_enumerator_destroy(address_enumerator_t *data)
705 {
706 data->this->lock->unlock(data->this->lock);
707 free(data);
708 }
709
710 /**
711 * filter for addresses
712 */
713 static bool filter_addresses(address_enumerator_t *data,
714 addr_entry_t** in, host_t** out)
715 {
716 host_t *ip;
717 if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual)
718 { /* skip virtual interfaces added by us */
719 return FALSE;
720 }
721 if (!(data->which & ADDR_TYPE_REGULAR) && !(*in)->virtual)
722 { /* address is regular, but not requested */
723 return FALSE;
724 }
725 ip = (*in)->ip;
726 if (ip->get_family(ip) == AF_INET6)
727 {
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 */
731 return FALSE;
732 }
733 }
734 *out = ip;
735 return TRUE;
736 }
737
738 /**
739 * enumerator constructor for interfaces
740 */
741 static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
742 address_enumerator_t *data)
743 {
744 return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
745 (void*)filter_addresses, data, NULL);
746 }
747
748 /**
749 * filter for interfaces
750 */
751 static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
752 iface_entry_t** out)
753 {
754 if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
755 { /* skip interfaces excluded by config */
756 return FALSE;
757 }
758 if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
759 { /* ignore loopback devices */
760 return FALSE;
761 }
762 if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
763 { /* skip interfaces not up */
764 return FALSE;
765 }
766 *out = *in;
767 return TRUE;
768 }
769
770 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
771 private_kernel_pfroute_net_t *this, kernel_address_type_t which)
772 {
773 address_enumerator_t *data;
774
775 INIT(data,
776 .this = this,
777 .which = which,
778 );
779
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);
787 }
788
789 METHOD(kernel_net_t, get_features, kernel_feature_t,
790 private_kernel_pfroute_net_t *this)
791 {
792 return KERNEL_REQUIRE_EXCLUDE_ROUTE;
793 }
794
795 METHOD(kernel_net_t, get_interface_name, bool,
796 private_kernel_pfroute_net_t *this, host_t* ip, char **name)
797 {
798 addr_map_entry_t *entry, lookup = {
799 .ip = ip,
800 };
801
802 if (ip->is_anyaddr(ip))
803 {
804 return FALSE;
805 }
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);
810 if (entry)
811 {
812 if (name)
813 {
814 *name = strdup(entry->iface->ifname);
815 DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
816 }
817 this->lock->unlock(this->lock);
818 return TRUE;
819 }
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);
823 if (!entry)
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);
826 }
827 this->lock->unlock(this->lock);
828 return FALSE;
829 }
830
831 METHOD(kernel_net_t, add_ip, status_t,
832 private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
833 char *ifname)
834 {
835 enumerator_t *ifaces, *addrs;
836 iface_entry_t *iface;
837 addr_entry_t *addr;
838 tun_device_t *tun;
839 bool timeout = FALSE;
840
841 tun = tun_device_create(NULL);
842 if (!tun)
843 {
844 return FAILED;
845 }
846 if (prefix == -1)
847 {
848 prefix = vip->get_address(vip).len * 8;
849 }
850 if (!tun->up(tun) || !tun->set_address(tun, vip, prefix))
851 {
852 tun->destroy(tun);
853 return FAILED;
854 }
855
856 /* wait until address appears */
857 this->mutex->lock(this->mutex);
858 while (!timeout && !get_interface_name(this, vip, NULL))
859 {
860 timeout = this->condvar->timed_wait(this->condvar, this->mutex,
861 this->vip_wait);
862 }
863 this->mutex->unlock(this->mutex);
864 if (timeout)
865 {
866 DBG1(DBG_KNL, "virtual IP %H did not appear on %s",
867 vip, tun->get_name(tun));
868 tun->destroy(tun);
869 return FAILED;
870 }
871
872 this->lock->write_lock(this->lock);
873 this->tuns->insert_last(this->tuns, tun);
874
875 ifaces = this->ifaces->create_enumerator(this->ifaces);
876 while (ifaces->enumerate(ifaces, &iface))
877 {
878 if (streq(iface->ifname, tun->get_name(tun)))
879 {
880 addrs = iface->addrs->create_enumerator(iface->addrs);
881 while (addrs->enumerate(addrs, &addr))
882 {
883 if (addr->ip->ip_equals(addr->ip, vip))
884 {
885 addr->virtual = TRUE;
886 }
887 }
888 addrs->destroy(addrs);
889 }
890 }
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);
897
898 return SUCCESS;
899 }
900
901 METHOD(kernel_net_t, del_ip, status_t,
902 private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
903 bool wait)
904 {
905 enumerator_t *enumerator;
906 tun_device_t *tun;
907 host_t *addr;
908 bool timeout = FALSE, found = FALSE;
909
910 this->lock->write_lock(this->lock);
911 enumerator = this->tuns->create_enumerator(this->tuns);
912 while (enumerator->enumerate(enumerator, &tun))
913 {
914 addr = tun->get_address(tun, NULL);
915 if (addr && addr->ip_equals(addr, vip))
916 {
917 this->tuns->remove_at(this->tuns, enumerator);
918 hydra->kernel_interface->tun(hydra->kernel_interface, tun,
919 FALSE);
920 tun->destroy(tun);
921 found = TRUE;
922 break;
923 }
924 }
925 enumerator->destroy(enumerator);
926 this->lock->unlock(this->lock);
927
928 if (!found)
929 {
930 return NOT_FOUND;
931 }
932 /* wait until address disappears */
933 if (wait)
934 {
935 this->mutex->lock(this->mutex);
936 while (!timeout && get_interface_name(this, vip, NULL))
937 {
938 timeout = this->condvar->timed_wait(this->condvar, this->mutex,
939 this->vip_wait);
940 }
941 this->mutex->unlock(this->mutex);
942 if (timeout)
943 {
944 DBG1(DBG_KNL, "virtual IP %H did not disappear from tun", vip);
945 return FAILED;
946 }
947 }
948 return SUCCESS;
949 }
950
951 /**
952 * Append a sockaddr_in/in6 of given type to routing message
953 */
954 static void add_rt_addr(struct rt_msghdr *hdr, int type, host_t *addr)
955 {
956 if (addr)
957 {
958 int len;
959
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;
964 }
965 }
966
967 /**
968 * Append a subnet mask sockaddr using the given prefix to routing message
969 */
970 static void add_rt_mask(struct rt_msghdr *hdr, int type, int family, int prefix)
971 {
972 host_t *mask;
973
974 mask = host_create_netmask(family, prefix);
975 if (mask)
976 {
977 add_rt_addr(hdr, type, mask);
978 mask->destroy(mask);
979 }
980 }
981
982 /**
983 * Append an interface name sockaddr_dl to routing message
984 */
985 static void add_rt_ifname(struct rt_msghdr *hdr, int type, char *name)
986 {
987 struct sockaddr_dl sdl = {
988 .sdl_len = sizeof(struct sockaddr_dl),
989 .sdl_family = AF_LINK,
990 .sdl_nlen = strlen(name),
991 };
992
993 if (strlen(name) <= sizeof(sdl.sdl_data))
994 {
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;
999 }
1000 }
1001
1002 /**
1003 * Add or remove a route
1004 */
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)
1008 {
1009 struct {
1010 struct rt_msghdr hdr;
1011 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
1012 } msg = {
1013 .hdr = {
1014 .rtm_version = RTM_VERSION,
1015 .rtm_type = op,
1016 .rtm_flags = RTF_UP | RTF_STATIC,
1017 .rtm_pid = this->pid,
1018 .rtm_seq = ++this->seq,
1019 },
1020 };
1021 host_t *dst;
1022 int type;
1023
1024 if (prefixlen == 0 && dst_net.len)
1025 {
1026 status_t status;
1027 chunk_t half;
1028
1029 half = chunk_clonea(dst_net);
1030 half.ptr[0] |= 0x80;
1031 prefixlen = 1;
1032 status = manage_route(this, op, half, prefixlen, gateway, if_name);
1033 if (status != SUCCESS)
1034 {
1035 return status;
1036 }
1037 }
1038
1039 dst = host_create_from_chunk(AF_UNSPEC, dst_net, 0);
1040 if (!dst)
1041 {
1042 return FAILED;
1043 }
1044
1045 if ((dst->get_family(dst) == AF_INET && prefixlen == 32) ||
1046 (dst->get_family(dst) == AF_INET6 && prefixlen == 128))
1047 {
1048 msg.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
1049 }
1050
1051 msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
1052 for (type = 0; type < RTAX_MAX; type++)
1053 {
1054 switch (type)
1055 {
1056 case RTAX_DST:
1057 add_rt_addr(&msg.hdr, RTA_DST, dst);
1058 break;
1059 case RTAX_NETMASK:
1060 if (!(msg.hdr.rtm_flags & RTF_HOST))
1061 {
1062 add_rt_mask(&msg.hdr, RTA_NETMASK,
1063 dst->get_family(dst), prefixlen);
1064 }
1065 break;
1066 case RTAX_IFP:
1067 if (if_name)
1068 {
1069 add_rt_ifname(&msg.hdr, RTA_IFP, if_name);
1070 }
1071 break;
1072 case RTAX_GATEWAY:
1073 if (gateway)
1074 {
1075 add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway);
1076 }
1077 break;
1078 default:
1079 break;
1080 }
1081 }
1082 dst->destroy(dst);
1083
1084 if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) != msg.hdr.rtm_msglen)
1085 {
1086 DBG1(DBG_KNL, "%s PF_ROUTE route failed: %s",
1087 op == RTM_ADD ? "adding" : "deleting", strerror(errno));
1088 return FAILED;
1089 }
1090 return SUCCESS;
1091 }
1092
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)
1096 {
1097 return manage_route(this, RTM_ADD, dst_net, prefixlen, gateway, if_name);
1098 }
1099
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)
1103 {
1104 return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name);
1105 }
1106
1107 /**
1108 * Do a route lookup for dest and return either the nexthop or the source
1109 * address.
1110 */
1111 static host_t *get_route(private_kernel_pfroute_net_t *this, bool nexthop,
1112 host_t *dest, host_t *src)
1113 {
1114 struct {
1115 struct rt_msghdr hdr;
1116 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
1117 } msg = {
1118 .hdr = {
1119 .rtm_version = RTM_VERSION,
1120 .rtm_type = RTM_GET,
1121 .rtm_pid = this->pid,
1122 .rtm_seq = ++this->seq,
1123 },
1124 };
1125 host_t *host = NULL;
1126 enumerator_t *enumerator;
1127 struct sockaddr *addr;
1128 bool failed = FALSE;
1129 int type;
1130
1131 retry:
1132 msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
1133 for (type = 0; type < RTAX_MAX; type++)
1134 {
1135 switch (type)
1136 {
1137 case RTAX_DST:
1138 add_rt_addr(&msg.hdr, RTA_DST, dest);
1139 break;
1140 case RTAX_IFA:
1141 add_rt_addr(&msg.hdr, RTA_IFA, src);
1142 break;
1143 case RTAX_IFP:
1144 if (!nexthop)
1145 { /* add an empty IFP to ensure we get a source address */
1146 add_rt_ifname(&msg.hdr, RTA_IFP, "");
1147 }
1148 break;
1149 default:
1150 break;
1151 }
1152 }
1153 this->mutex->lock(this->mutex);
1154
1155 while (this->waiting_seq)
1156 {
1157 this->condvar->wait(this->condvar, this->mutex);
1158 }
1159 this->waiting_seq = msg.hdr.rtm_seq;
1160 if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) == msg.hdr.rtm_msglen)
1161 {
1162 while (TRUE)
1163 {
1164 if (this->condvar->timed_wait(this->condvar, this->mutex, 1000))
1165 { /* timed out? */
1166 break;
1167 }
1168 if (this->reply->rtm_msglen < sizeof(*this->reply) ||
1169 msg.hdr.rtm_seq != this->reply->rtm_seq)
1170 {
1171 continue;
1172 }
1173 enumerator = create_rtmsg_enumerator(this->reply,
1174 sizeof(*this->reply));
1175 while (enumerator->enumerate(enumerator, &type, &addr))
1176 {
1177 if (nexthop)
1178 {
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);
1183 }
1184 if (type == RTAX_GATEWAY)
1185 { /* could actually be a MAC address */
1186 host_t *gtw = host_create_from_sockaddr(addr);
1187 if (gtw)
1188 {
1189 DESTROY_IF(host);
1190 host = gtw;
1191 }
1192 }
1193 }
1194 else
1195 {
1196 if (type == RTAX_IFA)
1197 {
1198 host = host_create_from_sockaddr(addr);
1199 }
1200 }
1201 }
1202 enumerator->destroy(enumerator);
1203 break;
1204 }
1205 }
1206 else
1207 {
1208 failed = TRUE;
1209 }
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);
1214
1215 if (failed)
1216 {
1217 if (src)
1218 { /* the given source address might be gone, try again without */
1219 src = NULL;
1220 msg.hdr.rtm_seq = ++this->seq;
1221 msg.hdr.rtm_addrs = 0;
1222 memset(msg.buf, sizeof(msg.buf), 0);
1223 goto retry;
1224 }
1225 DBG1(DBG_KNL, "PF_ROUTE lookup failed: %s", strerror(errno));
1226 }
1227
1228 if (host)
1229 {
1230 DBG2(DBG_KNL, "using %H as %s to reach %H", host,
1231 nexthop ? "nexthop" : "address", dest);
1232 }
1233 return host;
1234 }
1235
1236 METHOD(kernel_net_t, get_source_addr, host_t*,
1237 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
1238 {
1239 return get_route(this, FALSE, dest, src);
1240 }
1241
1242 METHOD(kernel_net_t, get_nexthop, host_t*,
1243 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
1244 {
1245 return get_route(this, TRUE, dest, src);
1246 }
1247
1248 /**
1249 * Initialize a list of local addresses.
1250 */
1251 static status_t init_address_list(private_kernel_pfroute_net_t *this)
1252 {
1253 struct ifaddrs *ifap, *ifa;
1254 iface_entry_t *iface, *current;
1255 addr_entry_t *addr;
1256 enumerator_t *ifaces, *addrs;
1257
1258 DBG2(DBG_KNL, "known interfaces and IP addresses:");
1259
1260 if (getifaddrs(&ifap) < 0)
1261 {
1262 DBG1(DBG_KNL, " failed to get interfaces!");
1263 return FAILED;
1264 }
1265
1266 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
1267 {
1268 if (ifa->ifa_addr == NULL)
1269 {
1270 continue;
1271 }
1272 switch(ifa->ifa_addr->sa_family)
1273 {
1274 case AF_LINK:
1275 case AF_INET:
1276 case AF_INET6:
1277 {
1278 iface = NULL;
1279 ifaces = this->ifaces->create_enumerator(this->ifaces);
1280 while (ifaces->enumerate(ifaces, &current))
1281 {
1282 if (streq(current->ifname, ifa->ifa_name))
1283 {
1284 iface = current;
1285 break;
1286 }
1287 }
1288 ifaces->destroy(ifaces);
1289
1290 if (!iface)
1291 {
1292 INIT(iface,
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),
1298 );
1299 memcpy(iface->ifname, ifa->ifa_name, IFNAMSIZ);
1300 this->ifaces->insert_last(this->ifaces, iface);
1301 }
1302
1303 if (ifa->ifa_addr->sa_family != AF_LINK)
1304 {
1305 INIT(addr,
1306 .ip = host_create_from_sockaddr(ifa->ifa_addr),
1307 );
1308 iface->addrs->insert_last(iface->addrs, addr);
1309 addr_map_entry_add(this, addr, iface);
1310 }
1311 }
1312 }
1313 }
1314 freeifaddrs(ifap);
1315
1316 ifaces = this->ifaces->create_enumerator(this->ifaces);
1317 while (ifaces->enumerate(ifaces, &iface))
1318 {
1319 if (iface->usable && iface->flags & IFF_UP)
1320 {
1321 DBG2(DBG_KNL, " %s", iface->ifname);
1322 addrs = iface->addrs->create_enumerator(iface->addrs);
1323 while (addrs->enumerate(addrs, (void**)&addr))
1324 {
1325 DBG2(DBG_KNL, " %H", addr->ip);
1326 }
1327 addrs->destroy(addrs);
1328 }
1329 }
1330 ifaces->destroy(ifaces);
1331
1332 return SUCCESS;
1333 }
1334
1335 METHOD(kernel_net_t, destroy, void,
1336 private_kernel_pfroute_net_t *this)
1337 {
1338 enumerator_t *enumerator;
1339 addr_entry_t *addr;
1340
1341 if (this->socket != -1)
1342 {
1343 close(this->socket);
1344 }
1345 enumerator = this->addrs->create_enumerator(this->addrs);
1346 while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
1347 {
1348 free(addr);
1349 }
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);
1357 free(this->reply);
1358 free(this);
1359 }
1360
1361 /*
1362 * Described in header.
1363 */
1364 kernel_pfroute_net_t *kernel_pfroute_net_create()
1365 {
1366 private_kernel_pfroute_net_t *this;
1367
1368 INIT(this,
1369 .public = {
1370 .interface = {
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,
1376 .add_ip = _add_ip,
1377 .del_ip = _del_ip,
1378 .add_route = _add_route,
1379 .del_route = _del_route,
1380 .destroy = _destroy,
1381 },
1382 },
1383 .pid = getpid(),
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),
1394 );
1395
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)
1399 {
1400 DBG1(DBG_KNL, "unable to create PF_ROUTE socket");
1401 destroy(this);
1402 return NULL;
1403 }
1404
1405 if (streq(hydra->daemon, "starter"))
1406 {
1407 /* starter has no threads, so we do not register for kernel events */
1408 if (shutdown(this->socket, SHUT_RD) != 0)
1409 {
1410 DBG1(DBG_KNL, "closing read end of PF_ROUTE socket failed: %s",
1411 strerror(errno));
1412 }
1413 }
1414 else
1415 {
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));
1420 }
1421 if (init_address_list(this) != SUCCESS)
1422 {
1423 DBG1(DBG_KNL, "unable to get interface list");
1424 destroy(this);
1425 return NULL;
1426 }
1427
1428 return &this->public;
1429 }