Fixed compilation of kernel-pfroute plugin
[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 <ifaddrs.h>
20 #include <net/route.h>
21 #include <unistd.h>
22 #include <errno.h>
23
24 #include "kernel_pfroute_net.h"
25
26 #include <hydra.h>
27 #include <debug.h>
28 #include <utils/host.h>
29 #include <threading/thread.h>
30 #include <threading/mutex.h>
31 #include <threading/rwlock.h>
32 #include <utils/hashtable.h>
33 #include <utils/linked_list.h>
34 #include <processing/jobs/callback_job.h>
35
36 #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
37 #error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
38 #endif
39
40 /** delay before firing roam events (ms) */
41 #define ROAM_DELAY 100
42
43 /** buffer size for PF_ROUTE messages */
44 #define PFROUTE_BUFFER_SIZE 4096
45
46 typedef struct addr_entry_t addr_entry_t;
47
48 /**
49 * IP address in an inface_entry_t
50 */
51 struct addr_entry_t {
52
53 /** The ip address */
54 host_t *ip;
55
56 /** virtual IP managed by us */
57 bool virtual;
58
59 /** Number of times this IP is used, if virtual */
60 u_int refcount;
61 };
62
63 /**
64 * destroy a addr_entry_t object
65 */
66 static void addr_entry_destroy(addr_entry_t *this)
67 {
68 this->ip->destroy(this->ip);
69 free(this);
70 }
71
72 typedef struct iface_entry_t iface_entry_t;
73
74 /**
75 * A network interface on this system, containing addr_entry_t's
76 */
77 struct iface_entry_t {
78
79 /** interface index */
80 int ifindex;
81
82 /** name of the interface */
83 char ifname[IFNAMSIZ];
84
85 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
86 u_int flags;
87
88 /** list of addresses as host_t */
89 linked_list_t *addrs;
90
91 /** TRUE if usable by config */
92 bool usable;
93 };
94
95 /**
96 * destroy an interface entry
97 */
98 static void iface_entry_destroy(iface_entry_t *this)
99 {
100 this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
101 free(this);
102 }
103
104 /**
105 * check if an interface is up
106 */
107 static inline bool iface_entry_up(iface_entry_t *iface)
108 {
109 return (iface->flags & IFF_UP) == IFF_UP;
110 }
111
112 /**
113 * check if an interface is up and usable
114 */
115 static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
116 {
117 return iface->usable && iface_entry_up(iface);
118 }
119
120 typedef struct addr_map_entry_t addr_map_entry_t;
121
122 /**
123 * Entry that maps an IP address to an interface entry
124 */
125 struct addr_map_entry_t {
126 /** The IP address */
127 host_t *ip;
128
129 /** The interface this address is installed on */
130 iface_entry_t *iface;
131 };
132
133 /**
134 * Hash a addr_map_entry_t object, all entries with the same IP address
135 * are stored in the same bucket
136 */
137 static u_int addr_map_entry_hash(addr_map_entry_t *this)
138 {
139 return chunk_hash(this->ip->get_address(this->ip));
140 }
141
142 /**
143 * Compare two addr_map_entry_t objects, two entries are equal if they are
144 * installed on the same interface
145 */
146 static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b)
147 {
148 return a->iface->ifindex == b->iface->ifindex &&
149 a->ip->ip_equals(a->ip, b->ip);
150 }
151
152 /**
153 * Used with get_match this finds an address entry if it is installed on
154 * an up and usable interface
155 */
156 static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a,
157 addr_map_entry_t *b)
158 {
159 return iface_entry_up_and_usable(b->iface) &&
160 a->ip->ip_equals(a->ip, b->ip);
161 }
162
163 /**
164 * Used with get_match this finds an address entry if it is installed on
165 * any active local interface
166 */
167 static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b)
168 {
169 return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip);
170 }
171
172 typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t;
173
174 /**
175 * Private variables and functions of kernel_pfroute class.
176 */
177 struct private_kernel_pfroute_net_t
178 {
179 /**
180 * Public part of the kernel_pfroute_t object.
181 */
182 kernel_pfroute_net_t public;
183
184 /**
185 * lock to access lists and maps
186 */
187 rwlock_t *lock;
188
189 /**
190 * Cached list of interfaces and their addresses (iface_entry_t)
191 */
192 linked_list_t *ifaces;
193
194 /**
195 * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
196 */
197 hashtable_t *addrs;
198
199 /**
200 * mutex to lock access to the PF_ROUTE socket
201 */
202 mutex_t *mutex_pfroute;
203
204 /**
205 * PF_ROUTE socket to communicate with the kernel
206 */
207 int socket;
208
209 /**
210 * PF_ROUTE socket to receive events
211 */
212 int socket_events;
213
214 /**
215 * sequence number for messages sent to the kernel
216 */
217 int seq;
218
219 /**
220 * time of last roam event
221 */
222 timeval_t last_roam;
223 };
224
225 /**
226 * Add an address map entry
227 */
228 static void addr_map_entry_add(private_kernel_pfroute_net_t *this,
229 addr_entry_t *addr, iface_entry_t *iface)
230 {
231 addr_map_entry_t *entry;
232
233 if (addr->virtual)
234 { /* don't map virtual IPs */
235 return;
236 }
237
238 INIT(entry,
239 .ip = addr->ip,
240 .iface = iface,
241 );
242 entry = this->addrs->put(this->addrs, entry, entry);
243 free(entry);
244 }
245
246 /**
247 * Remove an address map entry (the argument order is a bit strange because
248 * it is also used with linked_list_t.invoke_function)
249 */
250 static void addr_map_entry_remove(addr_entry_t *addr, iface_entry_t *iface,
251 private_kernel_pfroute_net_t *this)
252 {
253 addr_map_entry_t *entry, lookup = {
254 .ip = addr->ip,
255 .iface = iface,
256 };
257
258 if (addr->virtual)
259 { /* these are never mapped, but this check avoid problems if a virtual IP
260 * equals a regular one */
261 return;
262 }
263 entry = this->addrs->remove(this->addrs, &lookup);
264 free(entry);
265 }
266
267 /**
268 * callback function that raises the delayed roam event
269 */
270 static job_requeue_t roam_event(uintptr_t address)
271 {
272 hydra->kernel_interface->roam(hydra->kernel_interface, address != 0);
273 return JOB_REQUEUE_NONE;
274 }
275
276 /**
277 * fire a roaming event. we delay it for a bit and fire only one event
278 * for multiple calls. otherwise we would create too many events.
279 */
280 static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
281 {
282 timeval_t now;
283 job_t *job;
284
285 time_monotonic(&now);
286 if (timercmp(&now, &this->last_roam, >))
287 {
288 now.tv_usec += ROAM_DELAY * 1000;
289 while (now.tv_usec > 1000000)
290 {
291 now.tv_sec++;
292 now.tv_usec -= 1000000;
293 }
294 this->last_roam = now;
295
296 job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
297 (void*)(uintptr_t)(address ? 1 : 0),
298 NULL, NULL);
299 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
300 }
301 }
302
303 /**
304 * Process an RTM_*ADDR message from the kernel
305 */
306 static void process_addr(private_kernel_pfroute_net_t *this,
307 struct rt_msghdr *msg)
308 {
309 struct ifa_msghdr *ifa = (struct ifa_msghdr*)msg;
310 sockaddr_t *sockaddr = (sockaddr_t*)(ifa + 1);
311 host_t *host = NULL;
312 enumerator_t *ifaces, *addrs;
313 iface_entry_t *iface;
314 addr_entry_t *addr;
315 bool found = FALSE, changed = FALSE, roam = FALSE;
316 int i;
317
318 for (i = 1; i < (1 << RTAX_MAX); i <<= 1)
319 {
320 if (ifa->ifam_addrs & i)
321 {
322 if (RTA_IFA & i)
323 {
324 host = host_create_from_sockaddr(sockaddr);
325 break;
326 }
327 sockaddr = (sockaddr_t*)((char*)sockaddr + sockaddr->sa_len);
328 }
329 }
330
331 if (!host)
332 {
333 return;
334 }
335
336 this->lock->write_lock(this->lock);
337 ifaces = this->ifaces->create_enumerator(this->ifaces);
338 while (ifaces->enumerate(ifaces, &iface))
339 {
340 if (iface->ifindex == ifa->ifam_index)
341 {
342 addrs = iface->addrs->create_enumerator(iface->addrs);
343 while (addrs->enumerate(addrs, &addr))
344 {
345 if (host->ip_equals(host, addr->ip))
346 {
347 found = TRUE;
348 if (ifa->ifam_type == RTM_DELADDR)
349 {
350 iface->addrs->remove_at(iface->addrs, addrs);
351 if (!addr->virtual && iface->usable)
352 {
353 changed = TRUE;
354 DBG1(DBG_KNL, "%H disappeared from %s",
355 host, iface->ifname);
356 }
357 addr_map_entry_remove(addr, iface, this);
358 addr_entry_destroy(addr);
359 }
360 else if (ifa->ifam_type == RTM_NEWADDR && addr->virtual)
361 {
362 addr->refcount = 1;
363 }
364 }
365 }
366 addrs->destroy(addrs);
367
368 if (!found && ifa->ifam_type == RTM_NEWADDR)
369 {
370 changed = TRUE;
371 addr = malloc_thing(addr_entry_t);
372 addr->ip = host->clone(host);
373 addr->virtual = FALSE;
374 addr->refcount = 1;
375 iface->addrs->insert_last(iface->addrs, addr);
376 addr_map_entry_add(this, addr, iface);
377 if (iface->usable)
378 {
379 DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
380 }
381 }
382
383 if (changed && iface_entry_up_and_usable(iface))
384 {
385 roam = TRUE;
386 }
387 break;
388 }
389 }
390 ifaces->destroy(ifaces);
391 this->lock->unlock(this->lock);
392 host->destroy(host);
393
394 if (roam)
395 {
396 fire_roam_event(this, TRUE);
397 }
398 }
399
400 /**
401 * Process an RTM_IFINFO message from the kernel
402 */
403 static void process_link(private_kernel_pfroute_net_t *this,
404 struct rt_msghdr *hdr)
405 {
406 struct if_msghdr *msg = (struct if_msghdr*)hdr;
407 enumerator_t *enumerator;
408 iface_entry_t *iface;
409 bool roam = FALSE;
410
411 this->lock->write_lock(this->lock);
412 enumerator = this->ifaces->create_enumerator(this->ifaces);
413 while (enumerator->enumerate(enumerator, &iface))
414 {
415 if (iface->ifindex == msg->ifm_index)
416 {
417 if (iface->usable)
418 {
419 if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP))
420 {
421 roam = TRUE;
422 DBG1(DBG_KNL, "interface %s activated", iface->ifname);
423 }
424 else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP))
425 {
426 roam = TRUE;
427 DBG1(DBG_KNL, "interface %s deactivated", iface->ifname);
428 }
429 }
430 iface->flags = msg->ifm_flags;
431 break;
432 }
433 }
434 enumerator->destroy(enumerator);
435 this->lock->unlock(this->lock);
436
437 if (roam)
438 {
439 fire_roam_event(this, TRUE);
440 }
441 }
442
443 /**
444 * Process an RTM_*ROUTE message from the kernel
445 */
446 static void process_route(private_kernel_pfroute_net_t *this,
447 struct rt_msghdr *msg)
448 {
449
450 }
451
452 /**
453 * Receives events from kernel
454 */
455 static job_requeue_t receive_events(private_kernel_pfroute_net_t *this)
456 {
457 unsigned char buf[PFROUTE_BUFFER_SIZE];
458 struct rt_msghdr *msg = (struct rt_msghdr*)buf;
459 int len;
460 bool oldstate;
461
462 oldstate = thread_cancelability(TRUE);
463 len = recvfrom(this->socket_events, buf, sizeof(buf), 0, NULL, 0);
464 thread_cancelability(oldstate);
465
466 if (len < 0)
467 {
468 switch (errno)
469 {
470 case EINTR:
471 /* interrupted, try again */
472 return JOB_REQUEUE_DIRECT;
473 case EAGAIN:
474 /* no data ready, select again */
475 return JOB_REQUEUE_DIRECT;
476 default:
477 DBG1(DBG_KNL, "unable to receive from PF_ROUTE event socket");
478 sleep(1);
479 return JOB_REQUEUE_FAIR;
480 }
481 }
482
483 if (len < sizeof(msg->rtm_msglen) || len < msg->rtm_msglen ||
484 msg->rtm_version != RTM_VERSION)
485 {
486 DBG2(DBG_KNL, "received corrupted PF_ROUTE message");
487 return JOB_REQUEUE_DIRECT;
488 }
489
490 switch (msg->rtm_type)
491 {
492 case RTM_NEWADDR:
493 case RTM_DELADDR:
494 process_addr(this, msg);
495 break;
496 case RTM_IFINFO:
497 /*case RTM_IFANNOUNCE <- what about this*/
498 process_link(this, msg);
499 break;
500 case RTM_ADD:
501 case RTM_DELETE:
502 process_route(this, msg);
503 default:
504 break;
505 }
506
507 return JOB_REQUEUE_DIRECT;
508 }
509
510
511 /** enumerator over addresses */
512 typedef struct {
513 private_kernel_pfroute_net_t* this;
514 /** which addresses to enumerate */
515 kernel_address_type_t which;
516 } address_enumerator_t;
517
518 /**
519 * cleanup function for address enumerator
520 */
521 static void address_enumerator_destroy(address_enumerator_t *data)
522 {
523 data->this->lock->unlock(data->this->lock);
524 free(data);
525 }
526
527 /**
528 * filter for addresses
529 */
530 static bool filter_addresses(address_enumerator_t *data,
531 addr_entry_t** in, host_t** out)
532 {
533 host_t *ip;
534 if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual)
535 { /* skip virtual interfaces added by us */
536 return FALSE;
537 }
538 ip = (*in)->ip;
539 if (ip->get_family(ip) == AF_INET6)
540 {
541 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
542 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
543 { /* skip addresses with a unusable scope */
544 return FALSE;
545 }
546 }
547 *out = ip;
548 return TRUE;
549 }
550
551 /**
552 * enumerator constructor for interfaces
553 */
554 static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
555 address_enumerator_t *data)
556 {
557 return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
558 (void*)filter_addresses, data, NULL);
559 }
560
561 /**
562 * filter for interfaces
563 */
564 static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
565 iface_entry_t** out)
566 {
567 if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable)
568 { /* skip interfaces excluded by config */
569 return FALSE;
570 }
571 if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK))
572 { /* ignore loopback devices */
573 return FALSE;
574 }
575 if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP))
576 { /* skip interfaces not up */
577 return FALSE;
578 }
579 *out = *in;
580 return TRUE;
581 }
582
583 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
584 private_kernel_pfroute_net_t *this, kernel_address_type_t which)
585 {
586 address_enumerator_t *data = malloc_thing(address_enumerator_t);
587 data->this = this;
588 data->which = which;
589
590 this->lock->read_lock(this->lock);
591 return enumerator_create_nested(
592 enumerator_create_filter(
593 this->ifaces->create_enumerator(this->ifaces),
594 (void*)filter_interfaces, data, NULL),
595 (void*)create_iface_enumerator, data,
596 (void*)address_enumerator_destroy);
597 }
598
599 METHOD(kernel_net_t, get_interface_name, bool,
600 private_kernel_pfroute_net_t *this, host_t* ip, char **name)
601 {
602 addr_map_entry_t *entry, lookup = {
603 .ip = ip,
604 };
605
606 if (ip->is_anyaddr(ip))
607 {
608 return FALSE;
609 }
610 this->lock->read_lock(this->lock);
611 /* first try to find it on an up and usable interface */
612 entry = this->addrs->get_match(this->addrs, &lookup,
613 (void*)addr_map_entry_match_up_and_usable);
614 if (entry)
615 {
616 if (name)
617 {
618 *name = strdup(entry->iface->ifname);
619 DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
620 }
621 this->lock->unlock(this->lock);
622 return TRUE;
623 }
624 /* maybe it is installed on an ignored interface */
625 entry = this->addrs->get_match(this->addrs, &lookup,
626 (void*)addr_map_entry_match_up);
627 if (!entry)
628 { /* the address does not exist, is on a down interface */
629 DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip);
630 }
631 this->lock->unlock(this->lock);
632 return FALSE;
633 }
634
635 METHOD(kernel_net_t, get_source_addr, host_t*,
636 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
637 {
638 return NULL;
639 }
640
641 METHOD(kernel_net_t, get_nexthop, host_t*,
642 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
643 {
644 return NULL;
645 }
646
647 METHOD(kernel_net_t, add_ip, status_t,
648 private_kernel_pfroute_net_t *this, host_t *virtual_ip, host_t *iface_ip)
649 {
650 return FAILED;
651 }
652
653 METHOD(kernel_net_t, del_ip, status_t,
654 private_kernel_pfroute_net_t *this, host_t *virtual_ip)
655 {
656 return FAILED;
657 }
658
659 METHOD(kernel_net_t, add_route, status_t,
660 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
661 host_t *gateway, host_t *src_ip, char *if_name)
662 {
663 return FAILED;
664 }
665
666 METHOD(kernel_net_t, del_route, status_t,
667 private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
668 host_t *gateway, host_t *src_ip, char *if_name)
669 {
670 return FAILED;
671 }
672
673 /**
674 * Initialize a list of local addresses.
675 */
676 static status_t init_address_list(private_kernel_pfroute_net_t *this)
677 {
678 struct ifaddrs *ifap, *ifa;
679 iface_entry_t *iface, *current;
680 addr_entry_t *addr;
681 enumerator_t *ifaces, *addrs;
682
683 DBG2(DBG_KNL, "known interfaces and IP addresses:");
684
685 if (getifaddrs(&ifap) < 0)
686 {
687 DBG1(DBG_KNL, " failed to get interfaces!");
688 return FAILED;
689 }
690
691 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
692 {
693 if (ifa->ifa_addr == NULL)
694 {
695 continue;
696 }
697 switch(ifa->ifa_addr->sa_family)
698 {
699 case AF_LINK:
700 case AF_INET:
701 case AF_INET6:
702 {
703 iface = NULL;
704 ifaces = this->ifaces->create_enumerator(this->ifaces);
705 while (ifaces->enumerate(ifaces, &current))
706 {
707 if (streq(current->ifname, ifa->ifa_name))
708 {
709 iface = current;
710 break;
711 }
712 }
713 ifaces->destroy(ifaces);
714
715 if (!iface)
716 {
717 iface = malloc_thing(iface_entry_t);
718 memcpy(iface->ifname, ifa->ifa_name, IFNAMSIZ);
719 iface->ifindex = if_nametoindex(ifa->ifa_name);
720 iface->flags = ifa->ifa_flags;
721 iface->addrs = linked_list_create();
722 iface->usable = hydra->kernel_interface->is_interface_usable(
723 hydra->kernel_interface, ifa->ifa_name);
724 this->ifaces->insert_last(this->ifaces, iface);
725 }
726
727 if (ifa->ifa_addr->sa_family != AF_LINK)
728 {
729 addr = malloc_thing(addr_entry_t);
730 addr->ip = host_create_from_sockaddr(ifa->ifa_addr);
731 addr->virtual = FALSE;
732 addr->refcount = 1;
733 iface->addrs->insert_last(iface->addrs, addr);
734 }
735 }
736 }
737 }
738 freeifaddrs(ifap);
739
740 ifaces = this->ifaces->create_enumerator(this->ifaces);
741 while (ifaces->enumerate(ifaces, &iface))
742 {
743 if (iface->usable && iface->flags & IFF_UP)
744 {
745 DBG2(DBG_KNL, " %s", iface->ifname);
746 addrs = iface->addrs->create_enumerator(iface->addrs);
747 while (addrs->enumerate(addrs, (void**)&addr))
748 {
749 DBG2(DBG_KNL, " %H", addr->ip);
750 }
751 addrs->destroy(addrs);
752 }
753 }
754 ifaces->destroy(ifaces);
755
756 return SUCCESS;
757 }
758
759 METHOD(kernel_net_t, destroy, void,
760 private_kernel_pfroute_net_t *this)
761 {
762 enumerator_t *enumerator;
763 addr_entry_t *addr;
764
765 if (this->socket > 0)
766 {
767 close(this->socket);
768 }
769 if (this->socket_events)
770 {
771 close(this->socket_events);
772 }
773 enumerator = this->addrs->create_enumerator(this->addrs);
774 while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
775 {
776 free(addr);
777 }
778 enumerator->destroy(enumerator);
779 this->addrs->destroy(this->addrs);
780 this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
781 this->lock->destroy(this->lock);
782 this->mutex_pfroute->destroy(this->mutex_pfroute);
783 free(this);
784 }
785
786 /*
787 * Described in header.
788 */
789 kernel_pfroute_net_t *kernel_pfroute_net_create()
790 {
791 private_kernel_pfroute_net_t *this;
792 bool register_for_events = TRUE;
793
794 INIT(this,
795 .public = {
796 .interface = {
797 .get_interface = _get_interface_name,
798 .create_address_enumerator = _create_address_enumerator,
799 .get_source_addr = _get_source_addr,
800 .get_nexthop = _get_nexthop,
801 .add_ip = _add_ip,
802 .del_ip = _del_ip,
803 .add_route = _add_route,
804 .del_route = _del_route,
805 .destroy = _destroy,
806 },
807 },
808 .ifaces = linked_list_create(),
809 .addrs = hashtable_create(
810 (hashtable_hash_t)addr_map_entry_hash,
811 (hashtable_equals_t)addr_map_entry_equals, 16),
812 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
813 .mutex_pfroute = mutex_create(MUTEX_TYPE_DEFAULT),
814 );
815
816 if (streq(hydra->daemon, "starter"))
817 { /* starter has no threads, so we do not register for kernel events */
818 register_for_events = FALSE;
819 }
820
821 /* create a PF_ROUTE socket to communicate with the kernel */
822 this->socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
823 if (this->socket < 0)
824 {
825 DBG1(DBG_KNL, "unable to create PF_ROUTE socket");
826 destroy(this);
827 return NULL;
828 }
829
830 if (register_for_events)
831 {
832 /* create a PF_ROUTE socket to receive events */
833 this->socket_events = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
834 if (this->socket_events < 0)
835 {
836 DBG1(DBG_KNL, "unable to create PF_ROUTE event socket");
837 destroy(this);
838 return NULL;
839 }
840
841 lib->processor->queue_job(lib->processor,
842 (job_t*)callback_job_create_with_prio(
843 (callback_job_cb_t)receive_events, this, NULL,
844 (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
845 }
846
847 if (init_address_list(this) != SUCCESS)
848 {
849 DBG1(DBG_KNL, "unable to get interface list");
850 destroy(this);
851 return NULL;
852 }
853
854 return &this->public;
855 }