kernel-pfroute: install and uninstall routes
[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 <threading/thread.h>
31 #include <threading/mutex.h>
32 #include <threading/condvar.h>
33 #include <threading/rwlock.h>
34 #include <collections/hashtable.h>
35 #include <collections/linked_list.h>
36 #include <processing/jobs/callback_job.h>
37
38 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
39 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
40 #endif
41
42 /** delay before firing roam events (ms) */
43 #define ROAM_DELAY 100
44
45 typedef struct addr_entry_t addr_entry_t;
46
47 /**
48 * IP address in an inface_entry_t
49 */
50 struct addr_entry_t {
51
52 /** The ip address */
53 host_t *ip;
54
55 /** virtual IP managed by us */
56 bool virtual;
57
58 /** Number of times this IP is used, if virtual */
59 u_int refcount;
60 };
61
62 /**
63 * destroy a addr_entry_t object
64 */
65 static void addr_entry_destroy(addr_entry_t *this)
66 {
67 this->ip->destroy(this->ip);
68 free(this);
69 }
70
71 typedef struct iface_entry_t iface_entry_t;
72
73 /**
74 * A network interface on this system, containing addr_entry_t's
75 */
76 struct iface_entry_t {
77
78 /** interface index */
79 int ifindex;
80
81 /** name of the interface */
82 char ifname[IFNAMSIZ];
83
84 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
85 u_int flags;
86
87 /** list of addresses as host_t */
88 linked_list_t *addrs;
89
90 /** TRUE if usable by config */
91 bool usable;
92 };
93
94 /**
95 * destroy an interface entry
96 */
97 static void iface_entry_destroy(iface_entry_t *this)
98 {
99 this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
100 free(this);
101 }
102
103 /**
104 * check if an interface is up
105 */
106 static inline bool iface_entry_up(iface_entry_t *iface)
107 {
108 return (iface->flags & IFF_UP) == IFF_UP;
109 }
110
111 /**
112 * check if an interface is up and usable
113 */
114 static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
115 {
116 return iface->usable && iface_entry_up(iface);
117 }
118
119 typedef struct addr_map_entry_t addr_map_entry_t;
120
121 /**
122 * Entry that maps an IP address to an interface entry
123 */
124 struct addr_map_entry_t {
125 /** The IP address */
126 host_t *ip;
127
128 /** The interface this address is installed on */
129 iface_entry_t *iface;
130 };
131
132 /**
133 * Hash a addr_map_entry_t object, all entries with the same IP address
134 * are stored in the same bucket
135 */
136 static u_int addr_map_entry_hash(addr_map_entry_t *this)
137 {
138 return chunk_hash(this->ip->get_address(this->ip));
139 }
140
141 /**
142 * Compare two addr_map_entry_t objects, two entries are equal if they are
143 * installed on the same interface
144 */
145 static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b)
146 {
147 return a->iface->ifindex == b->iface->ifindex &&
148 a->ip->ip_equals(a->ip, b->ip);
149 }
150
151 /**
152 * Used with get_match this finds an address entry if it is installed on
153 * an up and usable interface
154 */
155 static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a,
156 addr_map_entry_t *b)
157 {
158 return iface_entry_up_and_usable(b->iface) &&
159 a->ip->ip_equals(a->ip, b->ip);
160 }
161
162 /**
163 * Used with get_match this finds an address entry if it is installed on
164 * any active local interface
165 */
166 static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b)
167 {
168 return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip);
169 }
170
171 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t;
172
173 /**
174 * Private variables and functions of kernel_pfroute class.
175 */
176 struct private_kernel_pfroute_net_t
177 {
178 /**
179 * Public part of the kernel_pfroute_t object.
180 */
181 kernel_pfroute_net_t public;
182
183 /**
184 * lock to access lists and maps
185 */
186 rwlock_t *lock;
187
188 /**
189 * Cached list of interfaces and their addresses (iface_entry_t)
190 */
191 linked_list_t *ifaces;
192
193 /**
194 * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
195 */
196 hashtable_t *addrs;
197
198 /**
199 * mutex to communicate exclusively with PF_KEY
200 */
201 mutex_t *mutex;
202
203 /**
204 * condvar to signal if PF_KEY query got a response
205 */
206 condvar_t *condvar;
207
208 /**
209 * pid to send PF_ROUTE messages with
210 */
211 pid_t pid;
212
213 /**
214 * PF_ROUTE socket to communicate with the kernel
215 */
216 int socket;
217
218 /**
219 * sequence number for messages sent to the kernel
220 */
221 int seq;
222
223 /**
224 * Sequence number a query is waiting for
225 */
226 int waiting_seq;
227
228 /**
229 * Allocated reply message from kernel
230 */
231 struct rt_msghdr *reply;
232
233 /**
234 * time of last roam event
235 */
236 timeval_t last_roam;
237 };
238
239 /**
240 * Add an address map entry
241 */
242 static void addr_map_entry_add(private_kernel_pfroute_net_t *this,
243 addr_entry_t *addr, iface_entry_t *iface)
244 {
245 addr_map_entry_t *entry;
246
247 if (addr->virtual)
248 { /* don't map virtual IPs */
249 return;
250 }
251
252 INIT(entry,
253 .ip = addr->ip,
254 .iface = iface,
255 );
256 entry = this->addrs->put(this->addrs, entry, entry);
257 free(entry);
258 }
259
260 /**
261 * Remove an address map entry (the argument order is a bit strange because
262 * it is also used with linked_list_t.invoke_function)
263 */
264 static void addr_map_entry_remove(addr_entry_t *addr, iface_entry_t *iface,
265 private_kernel_pfroute_net_t *this)
266 {
267 addr_map_entry_t *entry, lookup = {
268 .ip = addr->ip,
269 .iface = iface,
270 };
271
272 if (addr->virtual)
273 { /* these are never mapped, but this check avoid problems if a virtual IP
274 * equals a regular one */
275 return;
276 }
277 entry = this->addrs->remove(this->addrs, &lookup);
278 free(entry);
279 }
280
281 /**
282 * callback function that raises the delayed roam event
283 */
284 static job_requeue_t roam_event(uintptr_t address)
285 {
286 hydra->kernel_interface->roam(hydra->kernel_interface, address != 0);
287 return JOB_REQUEUE_NONE;
288 }
289
290 /**
291 * fire a roaming event. we delay it for a bit and fire only one event
292 * for multiple calls. otherwise we would create too many events.
293 */
294 static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
295 {
296 timeval_t now;
297 job_t *job;
298
299 time_monotonic(&now);
300 if (timercmp(&now, &this->last_roam, >))
301 {
302 timeval_add_ms(&now, ROAM_DELAY);
303 this->last_roam = now;
304
305 job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
306 (void*)(uintptr_t)(address ? 1 : 0),
307 NULL, NULL);
308 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
309 }
310 }
311
312 /**
313 * Data for enumerator over rtmsg sockaddrs
314 */
315 typedef struct {
316 /** implements enumerator */
317 enumerator_t public;
318 /** copy of attribute bitfield */
319 int types;
320 /** bytes remaining in buffer */
321 int remaining;
322 /** next sockaddr to enumerate */
323 struct sockaddr *addr;
324 } rt_enumerator_t;
325
326 METHOD(enumerator_t, rt_enumerate, bool,
327 rt_enumerator_t *this, int *xtype, struct sockaddr **addr)
328 {
329 int i, type;
330
331 if (this->remaining < sizeof(this->addr->sa_len) ||
332 this->remaining < this->addr->sa_len)
333 {
334 return FALSE;
335 }
336 for (i = 0; i < RTAX_MAX; i++)
337 {
338 type = (1 << i);
339 if (this->types & type)
340 {
341 this->types &= ~type;
342 *addr = this->addr;
343 *xtype = i;
344 this->remaining -= this->addr->sa_len;
345 this->addr = (void*)this->addr + this->addr->sa_len;
346 return TRUE;
347 }
348 }
349 return FALSE;
350 }
351
352 /**
353 * Create a safe enumerator over sockaddrs in ifa/ifam/rt_msg
354 */
355 static enumerator_t *create_rtmsg_enumerator(void *hdr, size_t hdrlen)
356 {
357 struct rt_msghdr *rthdr = hdr;
358 rt_enumerator_t *this;
359
360 INIT(this,
361 .public = {
362 .enumerate = (void*)_rt_enumerate,
363 .destroy = (void*)free,
364 },
365 .types = rthdr->rtm_addrs,
366 .remaining = rthdr->rtm_msglen - hdrlen,
367 .addr = hdr + hdrlen,
368 );
369 return &this->public;
370 }
371
372 /**
373 * Process an RTM_*ADDR message from the kernel
374 */
375 static void process_addr(private_kernel_pfroute_net_t *this,
376 struct ifa_msghdr *ifa)
377 {
378 struct sockaddr *sockaddr;
379 host_t *host = NULL;
380 enumerator_t *ifaces, *addrs;
381 iface_entry_t *iface;
382 addr_entry_t *addr;
383 bool found = FALSE, changed = FALSE, roam = FALSE;
384 enumerator_t *enumerator;
385 int type;
386
387 enumerator = create_rtmsg_enumerator(ifa, sizeof(*ifa));
388 while (enumerator->enumerate(enumerator, &type, &sockaddr))
389 {
390 if (type == RTAX_IFA)
391 {
392 host = host_create_from_sockaddr(sockaddr);
393 break;
394 }
395 }
396 enumerator->destroy(enumerator);
397
398 if (!host)
399 {
400 return;
401 }
402
403 this->lock->write_lock(this->lock);
404 ifaces = this->ifaces->create_enumerator(this->ifaces);
405 while (ifaces->enumerate(ifaces, &iface))
406 {
407 if (iface->ifindex == ifa->ifam_index)
408 {
409 addrs = iface->addrs->create_enumerator(iface->addrs);
410 while (addrs->enumerate(addrs, &addr))
411 {
412 if (host->ip_equals(host, addr->ip))
413 {
414 found = TRUE;
415 if (ifa->ifam_type == RTM_DELADDR)
416 {
417 iface->addrs->remove_at(iface->addrs, addrs);
418 if (!addr->virtual && iface->usable)
419 {
420 changed = TRUE;
421 DBG1(DBG_KNL, "%H disappeared from %s",
422 host, iface->ifname);
423 }
424 addr_map_entry_remove(addr, iface, this);
425 addr_entry_destroy(addr);
426 }
427 else if (ifa->ifam_type == RTM_NEWADDR && addr->virtual)
428 {
429 addr->refcount = 1;
430 }
431 }
432 }
433 addrs->destroy(addrs);
434
435 if (!found && ifa->ifam_type == RTM_NEWADDR)
436 {
437 INIT(addr,
438 .ip = host->clone(host),
439 .refcount = 1,
440 );
441 changed = TRUE;
442 iface->addrs->insert_last(iface->addrs, addr);
443 addr_map_entry_add(this, addr, iface);
444 if (iface->usable)
445 {
446 DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
447 }
448 }
449
450 if (changed && iface_entry_up_and_usable(iface))
451 {
452 roam = TRUE;
453 }
454 break;
455 }
456 }
457 ifaces->destroy(ifaces);
458 this->lock->unlock(this->lock);
459 host->destroy(host);
460
461 if (roam)
462 {
463 fire_roam_event(this, TRUE);
464 }
465 }
466
467 /**
468 * Process an RTM_IFINFO message from the kernel
469 */
470 static void process_link(private_kernel_pfroute_net_t *this,
471 struct if_msghdr *msg)
472 {
473 enumerator_t *enumerator;
474 iface_entry_t *iface;
475 bool roam = FALSE;
476
477 this->lock->write_lock(this->lock);
478 enumerator = this->ifaces->create_enumerator(this->ifaces);
479 while (enumerator->enumerate(enumerator, &iface))
480 {
481 if (iface->ifindex == msg->ifm_index)
482 {
483 if (iface->usable)
484 {
485 if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP))
486 {
487 roam = TRUE;
488 DBG1(DBG_KNL, "interface %s activated", iface->ifname);
489 }
490 else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP))
491 {
492 roam = TRUE;
493 DBG1(DBG_KNL, "interface %s deactivated", iface->ifname);
494 }
495 }
496 iface->flags = msg->ifm_flags;
497 break;
498 }
499 }
500 enumerator->destroy(enumerator);
501 this->lock->unlock(this->lock);
502
503 if (roam)
504 {
505 fire_roam_event(this, TRUE);
506 }
507 }
508
509 /**
510 * Process an RTM_*ROUTE message from the kernel
511 */
512 static void process_route(private_kernel_pfroute_net_t *this,
513 struct rt_msghdr *msg)
514 {
515
516 }
517
518 /**
519 * Receives PF_ROUTE messages from kernel
520 */
521 static job_requeue_t receive_events(private_kernel_pfroute_net_t *this)
522 {
523 struct {
524 union {
525 struct rt_msghdr rtm;
526 struct if_msghdr ifm;
527 struct ifa_msghdr ifam;
528 };
529 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
530 } msg;
531 int len, hdrlen;
532 bool oldstate;
533
534 oldstate = thread_cancelability(TRUE);
535 len = recv(this->socket, &msg, sizeof(msg), 0);
536 thread_cancelability(oldstate);
537
538 if (len < 0)
539 {
540 switch (errno)
541 {
542 case EINTR:
543 case EAGAIN:
544 return JOB_REQUEUE_DIRECT;
545 default:
546 DBG1(DBG_KNL, "unable to receive from PF_ROUTE event socket");
547 sleep(1);
548 return JOB_REQUEUE_FAIR;
549 }
550 }
551
552 if (len < offsetof(struct rt_msghdr, rtm_flags) || len < msg.rtm.rtm_msglen)
553 {
554 DBG1(DBG_KNL, "received invalid PF_ROUTE message");
555 return JOB_REQUEUE_DIRECT;
556 }
557 if (msg.rtm.rtm_version != RTM_VERSION)
558 {
559 DBG1(DBG_KNL, "received PF_ROUTE message with unsupported version: %d",
560 msg.rtm.rtm_version);
561 return JOB_REQUEUE_DIRECT;
562 }
563 switch (msg.rtm.rtm_type)
564 {
565 case RTM_NEWADDR:
566 case RTM_DELADDR:
567 hdrlen = sizeof(msg.ifam);
568 break;
569 case RTM_IFINFO:
570 hdrlen = sizeof(msg.ifm);
571 break;
572 case RTM_ADD:
573 case RTM_DELETE:
574 case RTM_GET:
575 hdrlen = sizeof(msg.rtm);
576 break;
577 default:
578 return JOB_REQUEUE_DIRECT;
579 }
580 if (msg.rtm.rtm_msglen < hdrlen)
581 {
582 DBG1(DBG_KNL, "ignoring short PF_ROUTE message");
583 return JOB_REQUEUE_DIRECT;
584 }
585 switch (msg.rtm.rtm_type)
586 {
587 case RTM_NEWADDR:
588 case RTM_DELADDR:
589 process_addr(this, &msg.ifam);
590 break;
591 case RTM_IFINFO:
592 process_link(this, &msg.ifm);
593 break;
594 case RTM_ADD:
595 case RTM_DELETE:
596 process_route(this, &msg.rtm);
597 break;
598 default:
599 break;
600 }
601
602 this->mutex->lock(this->mutex);
603 if (msg.rtm.rtm_pid == this->pid && msg.rtm.rtm_seq == this->waiting_seq)
604 {
605 /* seems like the message someone is waiting for, deliver */
606 this->reply = realloc(this->reply, msg.rtm.rtm_msglen);
607 memcpy(this->reply, &msg, msg.rtm.rtm_msglen);
608 this->condvar->signal(this->condvar);
609 }
610 this->mutex->unlock(this->mutex);
611
612 return JOB_REQUEUE_DIRECT;
613 }
614
615
616 /** enumerator over addresses */
617 typedef struct {
618 private_kernel_pfroute_net_t* this;
619 /** which addresses to enumerate */
620 kernel_address_type_t which;
621 } address_enumerator_t;
622
623 /**
624 * cleanup function for address enumerator
625 */
626 static void address_enumerator_destroy(address_enumerator_t *data)
627 {
628 data->this->lock->unlock(data->this->lock);
629 free(data);
630 }
631
632 /**
633 * filter for addresses
634 */
635 static bool filter_addresses(address_enumerator_t *data,
636 addr_entry_t** in, host_t** out)
637 {
638 host_t *ip;
639 if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual)
640 { /* skip virtual interfaces added by us */
641 return FALSE;
642 }
643 ip = (*in)->ip;
644 if (ip->get_family(ip) == AF_INET6)
645 {
646 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
647 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
648 { /* skip addresses with a unusable scope */
649 return FALSE;
650 }
651 }
652 *out = ip;
653 return TRUE;
654 }
655
656 /**
657 * enumerator constructor for interfaces
658 */
659 static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
660 address_enumerator_t *data)
661 {
662 return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
663 (void*)filter_addresses, data, NULL);
664 }
665
666 /**
667 * filter for interfaces
668 */
669 static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
670 iface_entry_t** out)
671 {
672 if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
673 { /* skip interfaces excluded by config */
674 return FALSE;
675 }
676 if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
677 { /* ignore loopback devices */
678 return FALSE;
679 }
680 if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
681 { /* skip interfaces not up */
682 return FALSE;
683 }
684 *out = *in;
685 return TRUE;
686 }
687
688 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
689 private_kernel_pfroute_net_t *this, kernel_address_type_t which)
690 {
691 address_enumerator_t *data;
692
693 INIT(data,
694 .this = this,
695 .which = which,
696 );
697
698 this->lock->read_lock(this->lock);
699 return enumerator_create_nested(
700 enumerator_create_filter(
701 this->ifaces->create_enumerator(this->ifaces),
702 (void*)filter_interfaces, data, NULL),
703 (void*)create_iface_enumerator, data,
704 (void*)address_enumerator_destroy);
705 }
706
707 METHOD(kernel_net_t, get_interface_name, bool,
708 private_kernel_pfroute_net_t *this, host_t* ip, char **name)
709 {
710 addr_map_entry_t *entry, lookup = {
711 .ip = ip,
712 };
713
714 if (ip->is_anyaddr(ip))
715 {
716 return FALSE;
717 }
718 this->lock->read_lock(this->lock);
719 /* first try to find it on an up and usable interface */
720 entry = this->addrs->get_match(this->addrs, &lookup,
721 (void*)addr_map_entry_match_up_and_usable);
722 if (entry)
723 {
724 if (name)
725 {
726 *name = strdup(entry->iface->ifname);
727 DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
728 }
729 this->lock->unlock(this->lock);
730 return TRUE;
731 }
732 /* maybe it is installed on an ignored interface */
733 entry = this->addrs->get_match(this->addrs, &lookup,
734 (void*)addr_map_entry_match_up);
735 if (!entry)
736 { /* the address does not exist, is on a down interface */
737 DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip);
738 }
739 this->lock->unlock(this->lock);
740 return FALSE;
741 }
742
743 METHOD(kernel_net_t, get_source_addr, host_t*,
744 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
745 {
746 return NULL;
747 }
748
749 METHOD(kernel_net_t, get_nexthop, host_t*,
750 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
751 {
752 return NULL;
753 }
754
755 METHOD(kernel_net_t, add_ip, status_t,
756 private_kernel_pfroute_net_t *this, host_t *virtual_ip, int prefix,
757 char *iface)
758 {
759 return FAILED;
760 }
761
762 METHOD(kernel_net_t, del_ip, status_t,
763 private_kernel_pfroute_net_t *this, host_t *virtual_ip, int prefix,
764 bool wait)
765 {
766 return FAILED;
767 }
768
769 /**
770 * Append a sockaddr_in/in6 of given type to routing message
771 */
772 static void add_rt_addr(struct rt_msghdr *hdr, int type, host_t *addr)
773 {
774 if (addr)
775 {
776 int len;
777
778 len = *addr->get_sockaddr_len(addr);
779 memcpy((char*)hdr + hdr->rtm_msglen, addr->get_sockaddr(addr), len);
780 hdr->rtm_msglen += len;
781 hdr->rtm_addrs |= type;
782 }
783 }
784
785 /**
786 * Append a subnet mask sockaddr using the given prefix to routing message
787 */
788 static void add_rt_mask(struct rt_msghdr *hdr, int type, int family, int prefix)
789 {
790 host_t *mask;
791
792 mask = host_create_netmask(family, prefix);
793 if (mask)
794 {
795 add_rt_addr(hdr, type, mask);
796 mask->destroy(mask);
797 }
798 }
799
800 /**
801 * Append an interface name sockaddr_dl to routing message
802 */
803 static void add_rt_ifname(struct rt_msghdr *hdr, int type, char *name)
804 {
805 struct sockaddr_dl sdl = {
806 .sdl_len = sizeof(struct sockaddr_dl),
807 .sdl_family = AF_LINK,
808 .sdl_nlen = strlen(name),
809 };
810
811 if (strlen(name) <= sizeof(sdl.sdl_data))
812 {
813 memcpy(sdl.sdl_data, name, sdl.sdl_nlen);
814 memcpy((char*)hdr + hdr->rtm_msglen, &sdl, sdl.sdl_len);
815 hdr->rtm_msglen += sdl.sdl_len;
816 hdr->rtm_addrs |= type;
817 }
818 }
819
820 /**
821 * Add or remove a route
822 */
823 static status_t manage_route(private_kernel_pfroute_net_t *this, int op,
824 chunk_t dst_net, u_int8_t prefixlen,
825 host_t *gateway, char *if_name)
826 {
827 struct {
828 struct rt_msghdr hdr;
829 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
830 } msg = {
831 .hdr = {
832 .rtm_version = RTM_VERSION,
833 .rtm_type = op,
834 .rtm_flags = RTF_UP | RTF_STATIC,
835 .rtm_pid = this->pid,
836 .rtm_seq = ++this->seq,
837 },
838 };
839 host_t *dst;
840 int type;
841
842 dst = host_create_from_chunk(AF_UNSPEC, dst_net, 0);
843 if (!dst)
844 {
845 return FAILED;
846 }
847
848 if ((dst->get_family(dst) == AF_INET && prefixlen == 32) ||
849 (dst->get_family(dst) == AF_INET6 && prefixlen == 128))
850 {
851 msg.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
852 }
853
854 msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
855 for (type = 0; type < RTAX_MAX; type++)
856 {
857 switch (type)
858 {
859 case RTAX_DST:
860 add_rt_addr(&msg.hdr, RTA_DST, dst);
861 break;
862 case RTAX_NETMASK:
863 if (!(msg.hdr.rtm_flags & RTF_HOST))
864 {
865 add_rt_mask(&msg.hdr, RTA_NETMASK,
866 dst->get_family(dst), prefixlen);
867 }
868 break;
869 case RTAX_GATEWAY:
870 /* interface name seems to replace gateway on OS X */
871 if (if_name)
872 {
873 add_rt_ifname(&msg.hdr, RTA_GATEWAY, if_name);
874 }
875 else if (gateway)
876 {
877 add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway);
878 }
879 break;
880 default:
881 break;
882 }
883 }
884 dst->destroy(dst);
885
886 if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) != msg.hdr.rtm_msglen)
887 {
888 DBG1(DBG_KNL, "%s PF_ROUTE route failed: %s",
889 op == RTM_ADD ? "adding" : "deleting", strerror(errno));
890 return FAILED;
891 }
892 return SUCCESS;
893 }
894
895 METHOD(kernel_net_t, add_route, status_t,
896 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
897 host_t *gateway, host_t *src_ip, char *if_name)
898 {
899 return manage_route(this, RTM_ADD, dst_net, prefixlen, gateway, if_name);
900 }
901
902 METHOD(kernel_net_t, del_route, status_t,
903 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
904 host_t *gateway, host_t *src_ip, char *if_name)
905 {
906 return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name);
907 }
908
909 /**
910 * Initialize a list of local addresses.
911 */
912 static status_t init_address_list(private_kernel_pfroute_net_t *this)
913 {
914 struct ifaddrs *ifap, *ifa;
915 iface_entry_t *iface, *current;
916 addr_entry_t *addr;
917 enumerator_t *ifaces, *addrs;
918
919 DBG2(DBG_KNL, "known interfaces and IP addresses:");
920
921 if (getifaddrs(&ifap) < 0)
922 {
923 DBG1(DBG_KNL, " failed to get interfaces!");
924 return FAILED;
925 }
926
927 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
928 {
929 if (ifa->ifa_addr == NULL)
930 {
931 continue;
932 }
933 switch(ifa->ifa_addr->sa_family)
934 {
935 case AF_LINK:
936 case AF_INET:
937 case AF_INET6:
938 {
939 iface = NULL;
940 ifaces = this->ifaces->create_enumerator(this->ifaces);
941 while (ifaces->enumerate(ifaces, &current))
942 {
943 if (streq(current->ifname, ifa->ifa_name))
944 {
945 iface = current;
946 break;
947 }
948 }
949 ifaces->destroy(ifaces);
950
951 if (!iface)
952 {
953 INIT(iface,
954 .ifindex = if_nametoindex(ifa->ifa_name),
955 .flags = ifa->ifa_flags,
956 .addrs = linked_list_create(),
957 .usable = hydra->kernel_interface->is_interface_usable(
958 hydra->kernel_interface, ifa->ifa_name),
959 );
960 memcpy(iface->ifname, ifa->ifa_name, IFNAMSIZ);
961 this->ifaces->insert_last(this->ifaces, iface);
962 }
963
964 if (ifa->ifa_addr->sa_family != AF_LINK)
965 {
966 INIT(addr,
967 .ip = host_create_from_sockaddr(ifa->ifa_addr),
968 .refcount = 1,
969 );
970 iface->addrs->insert_last(iface->addrs, addr);
971 addr_map_entry_add(this, addr, iface);
972 }
973 }
974 }
975 }
976 freeifaddrs(ifap);
977
978 ifaces = this->ifaces->create_enumerator(this->ifaces);
979 while (ifaces->enumerate(ifaces, &iface))
980 {
981 if (iface->usable && iface->flags & IFF_UP)
982 {
983 DBG2(DBG_KNL, " %s", iface->ifname);
984 addrs = iface->addrs->create_enumerator(iface->addrs);
985 while (addrs->enumerate(addrs, (void**)&addr))
986 {
987 DBG2(DBG_KNL, " %H", addr->ip);
988 }
989 addrs->destroy(addrs);
990 }
991 }
992 ifaces->destroy(ifaces);
993
994 return SUCCESS;
995 }
996
997 METHOD(kernel_net_t, destroy, void,
998 private_kernel_pfroute_net_t *this)
999 {
1000 enumerator_t *enumerator;
1001 addr_entry_t *addr;
1002
1003 if (this->socket != -1)
1004 {
1005 close(this->socket);
1006 }
1007 enumerator = this->addrs->create_enumerator(this->addrs);
1008 while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
1009 {
1010 free(addr);
1011 }
1012 enumerator->destroy(enumerator);
1013 this->addrs->destroy(this->addrs);
1014 this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
1015 this->lock->destroy(this->lock);
1016 this->mutex->destroy(this->mutex);
1017 this->condvar->destroy(this->condvar);
1018 free(this->reply);
1019 free(this);
1020 }
1021
1022 /*
1023 * Described in header.
1024 */
1025 kernel_pfroute_net_t *kernel_pfroute_net_create()
1026 {
1027 private_kernel_pfroute_net_t *this;
1028
1029 INIT(this,
1030 .public = {
1031 .interface = {
1032 .get_interface = _get_interface_name,
1033 .create_address_enumerator = _create_address_enumerator,
1034 .get_source_addr = _get_source_addr,
1035 .get_nexthop = _get_nexthop,
1036 .add_ip = _add_ip,
1037 .del_ip = _del_ip,
1038 .add_route = _add_route,
1039 .del_route = _del_route,
1040 .destroy = _destroy,
1041 },
1042 },
1043 .pid = getpid(),
1044 .ifaces = linked_list_create(),
1045 .addrs = hashtable_create(
1046 (hashtable_hash_t)addr_map_entry_hash,
1047 (hashtable_equals_t)addr_map_entry_equals, 16),
1048 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
1049 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
1050 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
1051 );
1052
1053 /* create a PF_ROUTE socket to communicate with the kernel */
1054 this->socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
1055 if (this->socket == -1)
1056 {
1057 DBG1(DBG_KNL, "unable to create PF_ROUTE socket");
1058 destroy(this);
1059 return NULL;
1060 }
1061
1062 if (streq(hydra->daemon, "starter"))
1063 {
1064 /* starter has no threads, so we do not register for kernel events */
1065 if (shutdown(this->socket, SHUT_RD) != 0)
1066 {
1067 DBG1(DBG_KNL, "closing read end of PF_ROUTE socket failed: %s",
1068 strerror(errno));
1069 }
1070 }
1071 else
1072 {
1073 lib->processor->queue_job(lib->processor,
1074 (job_t*)callback_job_create_with_prio(
1075 (callback_job_cb_t)receive_events, this, NULL,
1076 (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
1077 }
1078 if (init_address_list(this) != SUCCESS)
1079 {
1080 DBG1(DBG_KNL, "unable to get interface list");
1081 destroy(this);
1082 return NULL;
1083 }
1084
1085 return &this->public;
1086 }