]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c
kernel-netlink: Implement passthrough type routes and use them on Linux
[thirdparty/strongswan.git] / src / libcharon / plugins / kernel_pfroute / kernel_pfroute_net.c
CommitLineData
d24a74c5 1/*
b52e540f 2 * Copyright (C) 2009-2016 Tobias Brunner
1b671669 3 * HSR Hochschule fuer Technik Rapperswil
d24a74c5
TB
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.
d24a74c5
TB
14 */
15
16#include <sys/types.h>
17#include <sys/socket.h>
21df4cc1 18#include <sys/sysctl.h>
d24a74c5 19#include <net/if.h>
272bcac8 20#include <net/if_dl.h>
d24a74c5
TB
21#include <ifaddrs.h>
22#include <net/route.h>
23#include <unistd.h>
d24a74c5
TB
24#include <errno.h>
25
26#include "kernel_pfroute_net.h"
27
8394ea2a 28#include <daemon.h>
f05b4272 29#include <utils/debug.h>
2e7cc07e 30#include <networking/host.h>
2a2d7a4d 31#include <networking/tun_device.h>
4a5a5dd2 32#include <threading/thread.h>
eba64cef 33#include <threading/mutex.h>
3a7f4b5c 34#include <threading/condvar.h>
bdf36dac 35#include <threading/rwlock.h>
55da01f3 36#include <threading/spinlock.h>
12642a68
TB
37#include <collections/hashtable.h>
38#include <collections/linked_list.h>
d24a74c5 39#include <processing/jobs/callback_job.h>
d24a74c5
TB
40
41#ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
42#error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
43#endif
44
aa33d2e6 45/** properly align sockaddrs */
4b3fea3d
TB
46#ifdef __APPLE__
47/* Apple always uses 4 bytes */
aa33d2e6 48#define SA_ALIGN 4
4b3fea3d
TB
49#else
50/* while on other platforms like FreeBSD it depends on the architecture */
51#define SA_ALIGN sizeof(long)
52#endif
aa33d2e6
TB
53#define SA_LEN(len) ((len) > 0 ? (((len)+SA_ALIGN-1) & ~(SA_ALIGN-1)) : SA_ALIGN)
54
ba26508d 55/** delay before firing roam events (ms) */
d24a74c5
TB
56#define ROAM_DELAY 100
57
0745f846
TB
58/** delay before reinstalling routes (ms) */
59#define ROUTE_DELAY 100
60
d24a74c5
TB
61typedef struct addr_entry_t addr_entry_t;
62
63/**
64 * IP address in an inface_entry_t
65 */
66struct addr_entry_t {
7daf5226 67
d24a74c5
TB
68 /** The ip address */
69 host_t *ip;
7daf5226 70
d24a74c5
TB
71 /** virtual IP managed by us */
72 bool virtual;
d24a74c5
TB
73};
74
75/**
76 * destroy a addr_entry_t object
77 */
78static void addr_entry_destroy(addr_entry_t *this)
79{
80 this->ip->destroy(this->ip);
81 free(this);
82}
83
84typedef struct iface_entry_t iface_entry_t;
85
86/**
87 * A network interface on this system, containing addr_entry_t's
88 */
89struct iface_entry_t {
7daf5226 90
d24a74c5
TB
91 /** interface index */
92 int ifindex;
7daf5226 93
d24a74c5
TB
94 /** name of the interface */
95 char ifname[IFNAMSIZ];
7daf5226 96
d24a74c5
TB
97 /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
98 u_int flags;
7daf5226 99
d24a74c5
TB
100 /** list of addresses as host_t */
101 linked_list_t *addrs;
940e1b0f
TB
102
103 /** TRUE if usable by config */
104 bool usable;
d24a74c5
TB
105};
106
107/**
108 * destroy an interface entry
109 */
110static void iface_entry_destroy(iface_entry_t *this)
111{
112 this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
113 free(this);
114}
115
1f97e1aa
TB
116/**
117 * check if an interface is up
118 */
119static inline bool iface_entry_up(iface_entry_t *iface)
120{
121 return (iface->flags & IFF_UP) == IFF_UP;
122}
123
940e1b0f
TB
124/**
125 * check if an interface is up and usable
126 */
127static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
128{
1f97e1aa
TB
129 return iface->usable && iface_entry_up(iface);
130}
131
132typedef struct addr_map_entry_t addr_map_entry_t;
133
134/**
135 * Entry that maps an IP address to an interface entry
136 */
137struct addr_map_entry_t {
138 /** The IP address */
139 host_t *ip;
140
e9c1ca02
TB
141 /** The address entry for this IP address */
142 addr_entry_t *addr;
143
1f97e1aa
TB
144 /** The interface this address is installed on */
145 iface_entry_t *iface;
146};
147
148/**
149 * Hash a addr_map_entry_t object, all entries with the same IP address
150 * are stored in the same bucket
151 */
152static u_int addr_map_entry_hash(addr_map_entry_t *this)
153{
154 return chunk_hash(this->ip->get_address(this->ip));
155}
156
157/**
158 * Compare two addr_map_entry_t objects, two entries are equal if they are
159 * installed on the same interface
160 */
161static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b)
162{
163 return a->iface->ifindex == b->iface->ifindex &&
164 a->ip->ip_equals(a->ip, b->ip);
940e1b0f
TB
165}
166
1f97e1aa
TB
167/**
168 * Used with get_match this finds an address entry if it is installed on
169 * an up and usable interface
170 */
171static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a,
172 addr_map_entry_t *b)
173{
e9c1ca02
TB
174 return !b->addr->virtual && iface_entry_up_and_usable(b->iface) &&
175 a->ip->ip_equals(a->ip, b->ip);
1f97e1aa
TB
176}
177
5310f485
TB
178/**
179 * Used with get_match this finds an address entry if it is installed as virtual
180 * IP address
181 */
182static bool addr_map_entry_match_virtual(addr_map_entry_t *a, addr_map_entry_t *b)
183{
184 return b->addr->virtual && a->ip->ip_equals(a->ip, b->ip);
185}
186
1f97e1aa
TB
187/**
188 * Used with get_match this finds an address entry if it is installed on
189 * any active local interface
190 */
191static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b)
192{
e9c1ca02
TB
193 return !b->addr->virtual && iface_entry_up(b->iface) &&
194 a->ip->ip_equals(a->ip, b->ip);
1f97e1aa 195}
d24a74c5 196
0745f846
TB
197typedef struct route_entry_t route_entry_t;
198
199/**
200 * Installed routing entry
201 */
202struct route_entry_t {
203 /** Name of the interface the route is bound to */
204 char *if_name;
205
206 /** Gateway for this route */
207 host_t *gateway;
208
209 /** Destination net */
210 chunk_t dst_net;
211
212 /** Destination net prefixlen */
b12c53ce 213 uint8_t prefixlen;
0745f846
TB
214};
215
216/**
217 * Clone a route_entry_t object.
218 */
219static route_entry_t *route_entry_clone(route_entry_t *this)
220{
221 route_entry_t *route;
222
223 INIT(route,
224 .if_name = strdup(this->if_name),
225 .gateway = this->gateway ? this->gateway->clone(this->gateway) : NULL,
226 .dst_net = chunk_clone(this->dst_net),
227 .prefixlen = this->prefixlen,
228 );
229 return route;
230}
231
232/**
233 * Destroy a route_entry_t object
234 */
235static void route_entry_destroy(route_entry_t *this)
236{
237 free(this->if_name);
238 DESTROY_IF(this->gateway);
239 chunk_free(&this->dst_net);
240 free(this);
241}
242
243/**
244 * Hash a route_entry_t object
245 */
246static u_int route_entry_hash(route_entry_t *this)
247{
248 return chunk_hash_inc(chunk_from_thing(this->prefixlen),
249 chunk_hash(this->dst_net));
250}
251
252/**
253 * Compare two route_entry_t objects
254 */
255static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
256{
257 if (a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
258 chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen)
259 {
260 return (!a->gateway && !b->gateway) || (a->gateway && b->gateway &&
261 a->gateway->ip_equals(a->gateway, b->gateway));
262 }
263 return FALSE;
264}
265
266typedef struct net_change_t net_change_t;
267
268/**
269 * Queued network changes
270 */
271struct net_change_t {
272 /** Name of the interface that got activated (or an IP appeared on) */
273 char *if_name;
274};
275
276/**
277 * Destroy a net_change_t object
278 */
279static void net_change_destroy(net_change_t *this)
280{
281 free(this->if_name);
282 free(this);
283}
284
285/**
286 * Hash a net_change_t object
287 */
288static u_int net_change_hash(net_change_t *this)
289{
290 return chunk_hash(chunk_create(this->if_name, strlen(this->if_name)));
291}
292
293/**
294 * Compare two net_change_t objects
295 */
296static bool net_change_equals(net_change_t *a, net_change_t *b)
297{
298 return streq(a->if_name, b->if_name);
299}
300
d24a74c5
TB
301typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t;
302
303/**
304 * Private variables and functions of kernel_pfroute class.
305 */
306struct private_kernel_pfroute_net_t
307{
308 /**
309 * Public part of the kernel_pfroute_t object.
310 */
311 kernel_pfroute_net_t public;
7daf5226 312
d24a74c5 313 /**
bdf36dac 314 * lock to access lists and maps
d24a74c5 315 */
bdf36dac 316 rwlock_t *lock;
7daf5226 317
d24a74c5
TB
318 /**
319 * Cached list of interfaces and their addresses (iface_entry_t)
320 */
321 linked_list_t *ifaces;
7daf5226 322
1f97e1aa
TB
323 /**
324 * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
325 */
326 hashtable_t *addrs;
327
2a2d7a4d
MW
328 /**
329 * List of tun devices we installed for virtual IPs
330 */
331 linked_list_t *tuns;
332
d24a74c5 333 /**
3a7f4b5c 334 * mutex to communicate exclusively with PF_KEY
d24a74c5 335 */
3a7f4b5c
MW
336 mutex_t *mutex;
337
338 /**
339 * condvar to signal if PF_KEY query got a response
340 */
341 condvar_t *condvar;
342
0745f846
TB
343 /**
344 * installed routes
345 */
346 hashtable_t *routes;
347
348 /**
349 * mutex for routes
350 */
351 mutex_t *routes_lock;
352
353 /**
354 * interface changes which may trigger route reinstallation
355 */
356 hashtable_t *net_changes;
357
358 /**
359 * mutex for route reinstallation triggers
360 */
361 mutex_t *net_changes_lock;
362
363 /**
364 * time of last route reinstallation
365 */
366 timeval_t last_route_reinstall;
367
3a7f4b5c
MW
368 /**
369 * pid to send PF_ROUTE messages with
370 */
371 pid_t pid;
7daf5226 372
d24a74c5
TB
373 /**
374 * PF_ROUTE socket to communicate with the kernel
375 */
376 int socket;
7daf5226 377
d24a74c5
TB
378 /**
379 * sequence number for messages sent to the kernel
380 */
381 int seq;
7daf5226 382
3a7f4b5c
MW
383 /**
384 * Sequence number a query is waiting for
385 */
386 int waiting_seq;
387
388 /**
389 * Allocated reply message from kernel
390 */
391 struct rt_msghdr *reply;
392
d24a74c5 393 /**
55da01f3 394 * earliest time of the next roam event
d24a74c5 395 */
55da01f3
TB
396 timeval_t next_roam;
397
398 /**
399 * roam event due to address change
400 */
401 bool roam_address;
402
403 /**
404 * lock to check and update roam event time
405 */
406 spinlock_t *roam_lock;
baa6419e
TB
407
408 /**
409 * Time in ms to wait for IP addresses to appear/disappear
410 */
411 int vip_wait;
df085a15
TB
412
413 /**
414 * whether to actually install virtual IPs
415 */
416 bool install_virtual_ip;
d24a74c5
TB
417};
418
0745f846
TB
419
420/**
421 * Forward declaration
422 */
423static status_t manage_route(private_kernel_pfroute_net_t *this, int op,
b12c53ce 424 chunk_t dst_net, uint8_t prefixlen,
0745f846
TB
425 host_t *gateway, char *if_name);
426
427/**
428 * Clear the queued network changes.
429 */
430static void net_changes_clear(private_kernel_pfroute_net_t *this)
431{
432 enumerator_t *enumerator;
433 net_change_t *change;
434
435 enumerator = this->net_changes->create_enumerator(this->net_changes);
436 while (enumerator->enumerate(enumerator, NULL, (void**)&change))
437 {
438 this->net_changes->remove_at(this->net_changes, enumerator);
439 net_change_destroy(change);
440 }
441 enumerator->destroy(enumerator);
442}
443
444/**
445 * Act upon queued network changes.
446 */
447static job_requeue_t reinstall_routes(private_kernel_pfroute_net_t *this)
448{
449 enumerator_t *enumerator;
450 route_entry_t *route;
451
452 this->net_changes_lock->lock(this->net_changes_lock);
453 this->routes_lock->lock(this->routes_lock);
454
455 enumerator = this->routes->create_enumerator(this->routes);
456 while (enumerator->enumerate(enumerator, NULL, (void**)&route))
457 {
458 net_change_t *change, lookup = {
459 .if_name = route->if_name,
460 };
461 /* check if a change for the outgoing interface is queued */
462 change = this->net_changes->get(this->net_changes, &lookup);
463 if (change)
464 {
465 manage_route(this, RTM_ADD, route->dst_net, route->prefixlen,
466 route->gateway, route->if_name);
467 }
468 }
469 enumerator->destroy(enumerator);
470 this->routes_lock->unlock(this->routes_lock);
471
472 net_changes_clear(this);
473 this->net_changes_lock->unlock(this->net_changes_lock);
474 return JOB_REQUEUE_NONE;
475}
476
477/**
478 * Queue route reinstallation caused by network changes for a given interface.
479 *
480 * The route reinstallation is delayed for a while and only done once for
481 * several calls during this delay, in order to avoid doing it too often.
482 * The interface name is freed.
483 */
484static void queue_route_reinstall(private_kernel_pfroute_net_t *this,
485 char *if_name)
486{
487 net_change_t *update, *found;
488 timeval_t now;
489 job_t *job;
490
491 INIT(update,
492 .if_name = if_name
493 );
494
495 this->net_changes_lock->lock(this->net_changes_lock);
496 found = this->net_changes->put(this->net_changes, update, update);
497 if (found)
498 {
499 net_change_destroy(found);
500 }
501 time_monotonic(&now);
502 if (timercmp(&now, &this->last_route_reinstall, >))
503 {
504 timeval_add_ms(&now, ROUTE_DELAY);
505 this->last_route_reinstall = now;
506
507 job = (job_t*)callback_job_create((callback_job_cb_t)reinstall_routes,
508 this, NULL, NULL);
509 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROUTE_DELAY);
510 }
511 this->net_changes_lock->unlock(this->net_changes_lock);
512}
513
1f97e1aa
TB
514/**
515 * Add an address map entry
516 */
bfd2cc1c 517static void addr_map_entry_add(private_kernel_pfroute_net_t *this,
1f97e1aa
TB
518 addr_entry_t *addr, iface_entry_t *iface)
519{
520 addr_map_entry_t *entry;
521
1f97e1aa
TB
522 INIT(entry,
523 .ip = addr->ip,
e9c1ca02 524 .addr = addr,
1f97e1aa
TB
525 .iface = iface,
526 );
527 entry = this->addrs->put(this->addrs, entry, entry);
528 free(entry);
529}
530
531/**
532 * Remove an address map entry (the argument order is a bit strange because
533 * it is also used with linked_list_t.invoke_function)
534 */
535static void addr_map_entry_remove(addr_entry_t *addr, iface_entry_t *iface,
bfd2cc1c 536 private_kernel_pfroute_net_t *this)
1f97e1aa
TB
537{
538 addr_map_entry_t *entry, lookup = {
539 .ip = addr->ip,
e9c1ca02 540 .addr = addr,
1f97e1aa
TB
541 .iface = iface,
542 };
543
1f97e1aa
TB
544 entry = this->addrs->remove(this->addrs, &lookup);
545 free(entry);
546}
547
d24a74c5 548/**
ba26508d 549 * callback function that raises the delayed roam event
d24a74c5 550 */
55da01f3 551static job_requeue_t roam_event(private_kernel_pfroute_net_t *this)
ba26508d 552{
55da01f3
TB
553 bool address;
554
555 this->roam_lock->lock(this->roam_lock);
556 address = this->roam_address;
557 this->roam_address = FALSE;
558 this->roam_lock->unlock(this->roam_lock);
8394ea2a 559 charon->kernel->roam(charon->kernel, address);
ba26508d
TB
560 return JOB_REQUEUE_NONE;
561}
562
563/**
564 * fire a roaming event. we delay it for a bit and fire only one event
565 * for multiple calls. otherwise we would create too many events.
566 */
567static void fire_roam_event(private_kernel_pfroute_net_t *this, bool address)
d24a74c5 568{
de578445 569 timeval_t now;
ba26508d 570 job_t *job;
7daf5226 571
de578445 572 time_monotonic(&now);
55da01f3 573 this->roam_lock->lock(this->roam_lock);
11f46853 574 this->roam_address |= address;
55da01f3 575 if (!timercmp(&now, &this->next_roam, >))
d24a74c5 576 {
55da01f3
TB
577 this->roam_lock->unlock(this->roam_lock);
578 return;
d24a74c5 579 }
55da01f3
TB
580 timeval_add_ms(&now, ROAM_DELAY);
581 this->next_roam = now;
55da01f3
TB
582 this->roam_lock->unlock(this->roam_lock);
583
584 job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
585 this, NULL, NULL);
586 lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
d24a74c5
TB
587}
588
b1c6b68e
MW
589/**
590 * Data for enumerator over rtmsg sockaddrs
591 */
592typedef struct {
593 /** implements enumerator */
594 enumerator_t public;
595 /** copy of attribute bitfield */
596 int types;
597 /** bytes remaining in buffer */
598 int remaining;
599 /** next sockaddr to enumerate */
600 struct sockaddr *addr;
601} rt_enumerator_t;
602
603METHOD(enumerator_t, rt_enumerate, bool,
95a63bf2 604 rt_enumerator_t *this, va_list args)
b1c6b68e 605{
95a63bf2
TB
606 struct sockaddr **addr;
607 int i, type, *xtype;
608
609 VA_ARGS_VGET(args, xtype, addr);
b1c6b68e
MW
610
611 if (this->remaining < sizeof(this->addr->sa_len) ||
612 this->remaining < this->addr->sa_len)
613 {
614 return FALSE;
615 }
616 for (i = 0; i < RTAX_MAX; i++)
617 {
618 type = (1 << i);
619 if (this->types & type)
620 {
621 this->types &= ~type;
622 *addr = this->addr;
623 *xtype = i;
aa33d2e6 624 this->remaining -= SA_LEN(this->addr->sa_len);
4b3fea3d
TB
625 this->addr = (struct sockaddr*)((char*)this->addr +
626 SA_LEN(this->addr->sa_len));
b1c6b68e
MW
627 return TRUE;
628 }
629 }
630 return FALSE;
631}
632
633/**
b308a979 634 * Create an enumerator over sockaddrs in rt/if messages
b1c6b68e 635 */
b308a979
TB
636static enumerator_t *create_rt_enumerator(int types, int remaining,
637 struct sockaddr *addr)
b1c6b68e 638{
b1c6b68e
MW
639 rt_enumerator_t *this;
640
641 INIT(this,
642 .public = {
95a63bf2
TB
643 .enumerate = enumerator_enumerate_default,
644 .venumerate = _rt_enumerate,
b1c6b68e
MW
645 .destroy = (void*)free,
646 },
b308a979
TB
647 .types = types,
648 .remaining = remaining,
649 .addr = addr,
b1c6b68e
MW
650 );
651 return &this->public;
652}
653
b308a979
TB
654/**
655 * Create a safe enumerator over sockaddrs in rt_msghdr
656 */
657static enumerator_t *create_rtmsg_enumerator(struct rt_msghdr *hdr)
658{
659 return create_rt_enumerator(hdr->rtm_addrs, hdr->rtm_msglen - sizeof(*hdr),
660 (struct sockaddr *)(hdr + 1));
661}
662
663/**
664 * Create a safe enumerator over sockaddrs in ifa_msghdr
665 */
666static enumerator_t *create_ifamsg_enumerator(struct ifa_msghdr *hdr)
667{
668 return create_rt_enumerator(hdr->ifam_addrs, hdr->ifam_msglen - sizeof(*hdr),
669 (struct sockaddr *)(hdr + 1));
670}
671
d24a74c5
TB
672/**
673 * Process an RTM_*ADDR message from the kernel
674 */
675static void process_addr(private_kernel_pfroute_net_t *this,
b1c6b68e 676 struct ifa_msghdr *ifa)
d24a74c5 677{
b1c6b68e 678 struct sockaddr *sockaddr;
d24a74c5
TB
679 host_t *host = NULL;
680 enumerator_t *ifaces, *addrs;
681 iface_entry_t *iface;
682 addr_entry_t *addr;
683 bool found = FALSE, changed = FALSE, roam = FALSE;
b1c6b68e 684 enumerator_t *enumerator;
0745f846 685 char *ifname = NULL;
b1c6b68e 686 int type;
7daf5226 687
b308a979 688 enumerator = create_ifamsg_enumerator(ifa);
b1c6b68e 689 while (enumerator->enumerate(enumerator, &type, &sockaddr))
d24a74c5 690 {
b1c6b68e 691 if (type == RTAX_IFA)
d24a74c5 692 {
b1c6b68e
MW
693 host = host_create_from_sockaddr(sockaddr);
694 break;
d24a74c5
TB
695 }
696 }
b1c6b68e 697 enumerator->destroy(enumerator);
7daf5226 698
fae4d67a 699 if (!host || host->is_anyaddr(host))
d24a74c5 700 {
fae4d67a 701 DESTROY_IF(host);
d24a74c5
TB
702 return;
703 }
7daf5226 704
bdf36dac 705 this->lock->write_lock(this->lock);
d24a74c5
TB
706 ifaces = this->ifaces->create_enumerator(this->ifaces);
707 while (ifaces->enumerate(ifaces, &iface))
708 {
709 if (iface->ifindex == ifa->ifam_index)
710 {
711 addrs = iface->addrs->create_enumerator(iface->addrs);
712 while (addrs->enumerate(addrs, &addr))
713 {
714 if (host->ip_equals(host, addr->ip))
715 {
716 found = TRUE;
717 if (ifa->ifam_type == RTM_DELADDR)
718 {
719 iface->addrs->remove_at(iface->addrs, addrs);
940e1b0f 720 if (!addr->virtual && iface->usable)
d24a74c5
TB
721 {
722 changed = TRUE;
723 DBG1(DBG_KNL, "%H disappeared from %s",
724 host, iface->ifname);
725 }
1f97e1aa 726 addr_map_entry_remove(addr, iface, this);
d24a74c5
TB
727 addr_entry_destroy(addr);
728 }
d24a74c5
TB
729 }
730 }
731 addrs->destroy(addrs);
7daf5226 732
d24a74c5
TB
733 if (!found && ifa->ifam_type == RTM_NEWADDR)
734 {
9650bf3c
MW
735 INIT(addr,
736 .ip = host->clone(host),
9650bf3c 737 );
d24a74c5 738 changed = TRUE;
0745f846 739 ifname = strdup(iface->ifname);
d24a74c5 740 iface->addrs->insert_last(iface->addrs, addr);
1f97e1aa 741 addr_map_entry_add(this, addr, iface);
940e1b0f
TB
742 if (iface->usable)
743 {
744 DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
745 }
d24a74c5 746 }
7daf5226 747
940e1b0f 748 if (changed && iface_entry_up_and_usable(iface))
d24a74c5
TB
749 {
750 roam = TRUE;
751 }
752 break;
753 }
754 }
755 ifaces->destroy(ifaces);
bdf36dac 756 this->lock->unlock(this->lock);
d24a74c5 757 host->destroy(host);
7daf5226 758
0745f846
TB
759 if (roam && ifname)
760 {
761 queue_route_reinstall(this, ifname);
762 }
763 else
764 {
765 free(ifname);
766 }
767
d24a74c5
TB
768 if (roam)
769 {
ba26508d 770 fire_roam_event(this, TRUE);
d24a74c5
TB
771 }
772}
773
6e879a59
MW
774/**
775 * Re-initialize address list of an interface if it changes state
776 */
777static void repopulate_iface(private_kernel_pfroute_net_t *this,
778 iface_entry_t *iface)
779{
780 struct ifaddrs *ifap, *ifa;
781 addr_entry_t *addr;
782
783 while (iface->addrs->remove_last(iface->addrs, (void**)&addr) == SUCCESS)
784 {
785 addr_map_entry_remove(addr, iface, this);
786 addr_entry_destroy(addr);
787 }
788
789 if (getifaddrs(&ifap) == 0)
790 {
791 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
792 {
793 if (ifa->ifa_addr && streq(ifa->ifa_name, iface->ifname))
794 {
795 switch (ifa->ifa_addr->sa_family)
796 {
797 case AF_INET:
798 case AF_INET6:
799 INIT(addr,
800 .ip = host_create_from_sockaddr(ifa->ifa_addr),
6e879a59
MW
801 );
802 iface->addrs->insert_last(iface->addrs, addr);
803 addr_map_entry_add(this, addr, iface);
804 break;
805 default:
806 break;
807 }
808 }
809 }
810 freeifaddrs(ifap);
811 }
812}
813
d24a74c5
TB
814/**
815 * Process an RTM_IFINFO message from the kernel
816 */
817static void process_link(private_kernel_pfroute_net_t *this,
b1c6b68e 818 struct if_msghdr *msg)
d24a74c5 819{
d24a74c5
TB
820 enumerator_t *enumerator;
821 iface_entry_t *iface;
0745f846 822 bool roam = FALSE, found = FALSE, update_routes = FALSE;
7daf5226 823
bdf36dac 824 this->lock->write_lock(this->lock);
d24a74c5
TB
825 enumerator = this->ifaces->create_enumerator(this->ifaces);
826 while (enumerator->enumerate(enumerator, &iface))
827 {
828 if (iface->ifindex == msg->ifm_index)
829 {
940e1b0f 830 if (iface->usable)
d24a74c5 831 {
940e1b0f
TB
832 if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP))
833 {
0745f846 834 roam = update_routes = TRUE;
940e1b0f
TB
835 DBG1(DBG_KNL, "interface %s activated", iface->ifname);
836 }
837 else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP))
838 {
839 roam = TRUE;
840 DBG1(DBG_KNL, "interface %s deactivated", iface->ifname);
841 }
d24a74c5 842 }
6fa203b8
MW
843#ifdef __APPLE__
844 /* There seems to be a race condition on 10.10, where we get
845 * the RTM_IFINFO, but getifaddrs() does not return the virtual
846 * IP installed on a tun device, but we also don't get a
847 * RTM_NEWADDR. We therefore could miss the new address, letting
848 * virtual IP installation fail. Delaying getifaddrs() helps,
849 * but is obviously not a clean fix. */
850 usleep(50000);
851#endif
d24a74c5 852 iface->flags = msg->ifm_flags;
6e879a59 853 repopulate_iface(this, iface);
0fd409db 854 found = TRUE;
d24a74c5
TB
855 break;
856 }
857 }
858 enumerator->destroy(enumerator);
0fd409db
MW
859
860 if (!found)
861 {
862 INIT(iface,
863 .ifindex = msg->ifm_index,
864 .flags = msg->ifm_flags,
865 .addrs = linked_list_create(),
866 );
039b85dd
TB
867#ifdef __APPLE__
868 /* Similar to the issue described above, on 10.13 we need this delay as
869 * we might otherwise not be able to convert the index to a name yet. */
870 usleep(50000);
871#endif
0fd409db
MW
872 if (if_indextoname(iface->ifindex, iface->ifname))
873 {
874 DBG1(DBG_KNL, "interface %s appeared", iface->ifname);
8394ea2a
TB
875 iface->usable = charon->kernel->is_interface_usable(charon->kernel,
876 iface->ifname);
6e879a59 877 repopulate_iface(this, iface);
0fd409db 878 this->ifaces->insert_last(this->ifaces, iface);
7b9c3fb4
TB
879 if (iface->usable)
880 {
0745f846 881 roam = update_routes = TRUE;
7b9c3fb4 882 }
0fd409db
MW
883 }
884 else
885 {
886 free(iface);
887 }
888 }
bdf36dac 889 this->lock->unlock(this->lock);
7daf5226 890
0745f846
TB
891 if (update_routes)
892 {
893 queue_route_reinstall(this, strdup(iface->ifname));
894 }
895
d24a74c5
TB
896 if (roam)
897 {
ba26508d 898 fire_roam_event(this, TRUE);
d24a74c5
TB
899 }
900}
901
4e37bdbf
MW
902#ifdef HAVE_RTM_IFANNOUNCE
903
f80093e2
TB
904/**
905 * Process an RTM_IFANNOUNCE message from the kernel
906 */
907static void process_announce(private_kernel_pfroute_net_t *this,
908 struct if_announcemsghdr *msg)
909{
910 enumerator_t *enumerator;
911 iface_entry_t *iface;
912
913 if (msg->ifan_what != IFAN_DEPARTURE)
914 {
915 /* we handle new interfaces in process_link() */
916 return;
917 }
918
919 this->lock->write_lock(this->lock);
920 enumerator = this->ifaces->create_enumerator(this->ifaces);
921 while (enumerator->enumerate(enumerator, &iface))
922 {
923 if (iface->ifindex == msg->ifan_index)
924 {
925 DBG1(DBG_KNL, "interface %s disappeared", iface->ifname);
926 this->ifaces->remove_at(this->ifaces, enumerator);
927 iface_entry_destroy(iface);
928 break;
929 }
930 }
931 enumerator->destroy(enumerator);
932 this->lock->unlock(this->lock);
933}
934
4e37bdbf
MW
935#endif /* HAVE_RTM_IFANNOUNCE */
936
d24a74c5
TB
937/**
938 * Process an RTM_*ROUTE message from the kernel
939 */
940static void process_route(private_kernel_pfroute_net_t *this,
941 struct rt_msghdr *msg)
942{
943
944}
945
946/**
b1c6b68e 947 * Receives PF_ROUTE messages from kernel
d24a74c5 948 */
46666dd3
MW
949static bool receive_events(private_kernel_pfroute_net_t *this, int fd,
950 watcher_event_t event)
d24a74c5 951{
b1c6b68e
MW
952 struct {
953 union {
954 struct rt_msghdr rtm;
955 struct if_msghdr ifm;
956 struct ifa_msghdr ifam;
4e37bdbf 957#ifdef HAVE_RTM_IFANNOUNCE
f80093e2 958 struct if_announcemsghdr ifanm;
4e37bdbf 959#endif
b1c6b68e
MW
960 };
961 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
962 } msg;
963 int len, hdrlen;
7daf5226 964
46666dd3 965 len = recv(this->socket, &msg, sizeof(msg), MSG_DONTWAIT);
d24a74c5
TB
966 if (len < 0)
967 {
968 switch (errno)
969 {
970 case EINTR:
d24a74c5 971 case EAGAIN:
46666dd3 972 return TRUE;
d24a74c5
TB
973 default:
974 DBG1(DBG_KNL, "unable to receive from PF_ROUTE event socket");
975 sleep(1);
46666dd3 976 return TRUE;
d24a74c5
TB
977 }
978 }
7daf5226 979
b1c6b68e 980 if (len < offsetof(struct rt_msghdr, rtm_flags) || len < msg.rtm.rtm_msglen)
d24a74c5 981 {
b1c6b68e 982 DBG1(DBG_KNL, "received invalid PF_ROUTE message");
46666dd3 983 return TRUE;
d24a74c5 984 }
b1c6b68e
MW
985 if (msg.rtm.rtm_version != RTM_VERSION)
986 {
987 DBG1(DBG_KNL, "received PF_ROUTE message with unsupported version: %d",
988 msg.rtm.rtm_version);
46666dd3 989 return TRUE;
b1c6b68e
MW
990 }
991 switch (msg.rtm.rtm_type)
d24a74c5
TB
992 {
993 case RTM_NEWADDR:
994 case RTM_DELADDR:
b1c6b68e 995 hdrlen = sizeof(msg.ifam);
d24a74c5
TB
996 break;
997 case RTM_IFINFO:
b1c6b68e 998 hdrlen = sizeof(msg.ifm);
d24a74c5 999 break;
4e37bdbf 1000#ifdef HAVE_RTM_IFANNOUNCE
f80093e2
TB
1001 case RTM_IFANNOUNCE:
1002 hdrlen = sizeof(msg.ifanm);
1003 break;
4e37bdbf 1004#endif /* HAVE_RTM_IFANNOUNCE */
d24a74c5
TB
1005 case RTM_ADD:
1006 case RTM_DELETE:
b1c6b68e
MW
1007 case RTM_GET:
1008 hdrlen = sizeof(msg.rtm);
1009 break;
1010 default:
46666dd3 1011 return TRUE;
b1c6b68e
MW
1012 }
1013 if (msg.rtm.rtm_msglen < hdrlen)
1014 {
1015 DBG1(DBG_KNL, "ignoring short PF_ROUTE message");
46666dd3 1016 return TRUE;
b1c6b68e
MW
1017 }
1018 switch (msg.rtm.rtm_type)
1019 {
1020 case RTM_NEWADDR:
1021 case RTM_DELADDR:
1022 process_addr(this, &msg.ifam);
1023 break;
1024 case RTM_IFINFO:
1025 process_link(this, &msg.ifm);
1026 break;
4e37bdbf 1027#ifdef HAVE_RTM_IFANNOUNCE
f80093e2
TB
1028 case RTM_IFANNOUNCE:
1029 process_announce(this, &msg.ifanm);
1030 break;
4e37bdbf 1031#endif /* HAVE_RTM_IFANNOUNCE */
b1c6b68e
MW
1032 case RTM_ADD:
1033 case RTM_DELETE:
1034 process_route(this, &msg.rtm);
1035 break;
d24a74c5
TB
1036 default:
1037 break;
1038 }
3a7f4b5c
MW
1039
1040 this->mutex->lock(this->mutex);
1041 if (msg.rtm.rtm_pid == this->pid && msg.rtm.rtm_seq == this->waiting_seq)
1042 {
1043 /* seems like the message someone is waiting for, deliver */
1044 this->reply = realloc(this->reply, msg.rtm.rtm_msglen);
1045 memcpy(this->reply, &msg, msg.rtm.rtm_msglen);
3a7f4b5c 1046 }
2a2d7a4d 1047 /* signal on any event, add_ip()/del_ip() might wait for it */
c9a323c1 1048 this->condvar->broadcast(this->condvar);
3a7f4b5c
MW
1049 this->mutex->unlock(this->mutex);
1050
46666dd3 1051 return TRUE;
d24a74c5
TB
1052}
1053
1054
1055/** enumerator over addresses */
1056typedef struct {
1057 private_kernel_pfroute_net_t* this;
4106aea8 1058 /** which addresses to enumerate */
bfd2cc1c 1059 kernel_address_type_t which;
d24a74c5
TB
1060} address_enumerator_t;
1061
525cc46c
TB
1062CALLBACK(address_enumerator_destroy, void,
1063 address_enumerator_t *data)
d24a74c5 1064{
bdf36dac 1065 data->this->lock->unlock(data->this->lock);
d24a74c5
TB
1066 free(data);
1067}
1068
525cc46c
TB
1069CALLBACK(filter_addresses, bool,
1070 address_enumerator_t *data, enumerator_t *orig, va_list args)
d24a74c5 1071{
525cc46c
TB
1072 addr_entry_t *addr;
1073 host_t *ip, **out;
1074 struct sockaddr_in6 *sin6;
1075
1076 VA_ARGS_VGET(args, out);
1077
1078 while (orig->enumerate(orig, &addr))
d24a74c5 1079 {
525cc46c
TB
1080 if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->virtual)
1081 { /* skip virtual interfaces added by us */
1082 continue;
d24a74c5 1083 }
525cc46c
TB
1084 if (!(data->which & ADDR_TYPE_REGULAR) && !addr->virtual)
1085 { /* address is regular, but not requested */
1086 continue;
1087 }
1088 ip = addr->ip;
1089 if (ip->get_family(ip) == AF_INET6)
1090 {
1091 sin6 = (struct sockaddr_in6 *)ip->get_sockaddr(ip);
1092 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1093 { /* skip addresses with a unusable scope */
1094 continue;
1095 }
1096 }
1097 *out = ip;
1098 return TRUE;
d24a74c5 1099 }
525cc46c 1100 return FALSE;
d24a74c5
TB
1101}
1102
1103/**
1104 * enumerator constructor for interfaces
1105 */
e131f117
MW
1106static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
1107 address_enumerator_t *data)
d24a74c5
TB
1108{
1109 return enumerator_create_filter(iface->addrs->create_enumerator(iface->addrs),
525cc46c 1110 filter_addresses, data, NULL);
d24a74c5
TB
1111}
1112
525cc46c
TB
1113CALLBACK(filter_interfaces, bool,
1114 address_enumerator_t *data, enumerator_t *orig, va_list args)
d24a74c5 1115{
525cc46c
TB
1116 iface_entry_t *iface, **out;
1117
1118 VA_ARGS_VGET(args, out);
1119
1120 while (orig->enumerate(orig, &iface))
1121 {
1122 if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable)
1123 { /* skip interfaces excluded by config */
1124 continue;
1125 }
1126 if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK))
1127 { /* ignore loopback devices */
1128 continue;
1129 }
1130 if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP))
1131 { /* skip interfaces not up */
1132 continue;
1133 }
1134 *out = iface;
1135 return TRUE;
d24a74c5 1136 }
525cc46c 1137 return FALSE;
d24a74c5
TB
1138}
1139
e131f117 1140METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
bfd2cc1c 1141 private_kernel_pfroute_net_t *this, kernel_address_type_t which)
d24a74c5 1142{
9650bf3c
MW
1143 address_enumerator_t *data;
1144
1145 INIT(data,
1146 .this = this,
1147 .which = which,
1148 );
d24a74c5 1149
bdf36dac 1150 this->lock->read_lock(this->lock);
d24a74c5 1151 return enumerator_create_nested(
e131f117
MW
1152 enumerator_create_filter(
1153 this->ifaces->create_enumerator(this->ifaces),
525cc46c 1154 filter_interfaces, data, NULL),
e131f117 1155 (void*)create_iface_enumerator, data,
525cc46c 1156 address_enumerator_destroy);
d24a74c5
TB
1157}
1158
580b768d
MW
1159METHOD(kernel_net_t, get_features, kernel_feature_t,
1160 private_kernel_pfroute_net_t *this)
1161{
1162 return KERNEL_REQUIRE_EXCLUDE_ROUTE;
1163}
1164
9ba36c0f
TB
1165METHOD(kernel_net_t, get_interface_name, bool,
1166 private_kernel_pfroute_net_t *this, host_t* ip, char **name)
d24a74c5 1167{
1f97e1aa
TB
1168 addr_map_entry_t *entry, lookup = {
1169 .ip = ip,
1170 };
d24a74c5 1171
645d7a5e
TB
1172 if (ip->is_anyaddr(ip))
1173 {
1174 return FALSE;
1175 }
bdf36dac 1176 this->lock->read_lock(this->lock);
1f97e1aa
TB
1177 /* first try to find it on an up and usable interface */
1178 entry = this->addrs->get_match(this->addrs, &lookup,
1179 (void*)addr_map_entry_match_up_and_usable);
1180 if (entry)
d24a74c5 1181 {
1f97e1aa 1182 if (name)
940e1b0f 1183 {
1f97e1aa 1184 *name = strdup(entry->iface->ifname);
940e1b0f
TB
1185 DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
1186 }
bdf36dac 1187 this->lock->unlock(this->lock);
1f97e1aa 1188 return TRUE;
d24a74c5 1189 }
5310f485
TB
1190 /* check if it is a virtual IP */
1191 entry = this->addrs->get_match(this->addrs, &lookup,
1192 (void*)addr_map_entry_match_virtual);
1193 if (entry)
1194 {
1195 if (name)
1196 {
1197 *name = strdup(entry->iface->ifname);
1198 DBG2(DBG_KNL, "virtual IP %H is on interface %s", ip, *name);
1199 }
1200 this->lock->unlock(this->lock);
1201 return TRUE;
1202 }
1f97e1aa
TB
1203 /* maybe it is installed on an ignored interface */
1204 entry = this->addrs->get_match(this->addrs, &lookup,
1205 (void*)addr_map_entry_match_up);
1206 if (!entry)
1207 { /* the address does not exist, is on a down interface */
1208 DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip);
1209 }
bdf36dac 1210 this->lock->unlock(this->lock);
1f97e1aa 1211 return FALSE;
d24a74c5
TB
1212}
1213
e131f117 1214METHOD(kernel_net_t, add_ip, status_t,
2a2d7a4d 1215 private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
77b6f196 1216 char *ifname)
d24a74c5 1217{
77b6f196
MW
1218 enumerator_t *ifaces, *addrs;
1219 iface_entry_t *iface;
1220 addr_entry_t *addr;
2a2d7a4d
MW
1221 tun_device_t *tun;
1222 bool timeout = FALSE;
1223
df085a15
TB
1224 if (!this->install_virtual_ip)
1225 { /* disabled by config */
1226 return SUCCESS;
1227 }
1228
2a2d7a4d
MW
1229 tun = tun_device_create(NULL);
1230 if (!tun)
1231 {
1232 return FAILED;
1233 }
1234 if (prefix == -1)
1235 {
1236 prefix = vip->get_address(vip).len * 8;
1237 }
93e4df37 1238 if (!tun->up(tun) || !tun->set_address(tun, vip, prefix))
2a2d7a4d
MW
1239 {
1240 tun->destroy(tun);
1241 return FAILED;
1242 }
1243
1244 /* wait until address appears */
1245 this->mutex->lock(this->mutex);
1246 while (!timeout && !get_interface_name(this, vip, NULL))
1247 {
baa6419e
TB
1248 timeout = this->condvar->timed_wait(this->condvar, this->mutex,
1249 this->vip_wait);
2a2d7a4d
MW
1250 }
1251 this->mutex->unlock(this->mutex);
1252 if (timeout)
1253 {
1254 DBG1(DBG_KNL, "virtual IP %H did not appear on %s",
1255 vip, tun->get_name(tun));
1256 tun->destroy(tun);
1257 return FAILED;
1258 }
1259
1260 this->lock->write_lock(this->lock);
1261 this->tuns->insert_last(this->tuns, tun);
77b6f196
MW
1262
1263 ifaces = this->ifaces->create_enumerator(this->ifaces);
1264 while (ifaces->enumerate(ifaces, &iface))
1265 {
1266 if (streq(iface->ifname, tun->get_name(tun)))
1267 {
1268 addrs = iface->addrs->create_enumerator(iface->addrs);
1269 while (addrs->enumerate(addrs, &addr))
1270 {
1271 if (addr->ip->ip_equals(addr->ip, vip))
1272 {
1273 addr->virtual = TRUE;
77b6f196
MW
1274 }
1275 }
1276 addrs->destroy(addrs);
0745f846
TB
1277 /* during IKEv1 reauthentication, children get moved from
1278 * old the new SA before the virtual IP is available. This
1279 * kills the route for our virtual IP, reinstall. */
1280 queue_route_reinstall(this, strdup(iface->ifname));
1281 break;
77b6f196
MW
1282 }
1283 }
1284 ifaces->destroy(ifaces);
554c4276 1285 /* lets do this while holding the lock, thus preventing another thread
0745f846 1286 * from deleting the TUN device concurrently, hopefully listeners are quick
554c4276 1287 * and cause no deadlocks */
8394ea2a 1288 charon->kernel->tun(charon->kernel, tun, TRUE);
2a2d7a4d
MW
1289 this->lock->unlock(this->lock);
1290
1291 return SUCCESS;
d24a74c5
TB
1292}
1293
e131f117 1294METHOD(kernel_net_t, del_ip, status_t,
2a2d7a4d 1295 private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
d88597f0 1296 bool wait)
d24a74c5 1297{
2a2d7a4d
MW
1298 enumerator_t *enumerator;
1299 tun_device_t *tun;
1300 host_t *addr;
1301 bool timeout = FALSE, found = FALSE;
1302
df085a15
TB
1303 if (!this->install_virtual_ip)
1304 { /* disabled by config */
1305 return SUCCESS;
1306 }
1307
2a2d7a4d
MW
1308 this->lock->write_lock(this->lock);
1309 enumerator = this->tuns->create_enumerator(this->tuns);
1310 while (enumerator->enumerate(enumerator, &tun))
1311 {
1312 addr = tun->get_address(tun, NULL);
1313 if (addr && addr->ip_equals(addr, vip))
1314 {
1315 this->tuns->remove_at(this->tuns, enumerator);
8394ea2a 1316 charon->kernel->tun(charon->kernel, tun, FALSE);
2a2d7a4d
MW
1317 tun->destroy(tun);
1318 found = TRUE;
1319 break;
1320 }
1321 }
1322 enumerator->destroy(enumerator);
1323 this->lock->unlock(this->lock);
1324
1325 if (!found)
1326 {
1327 return NOT_FOUND;
1328 }
1329 /* wait until address disappears */
1330 if (wait)
1331 {
1332 this->mutex->lock(this->mutex);
1333 while (!timeout && get_interface_name(this, vip, NULL))
1334 {
baa6419e
TB
1335 timeout = this->condvar->timed_wait(this->condvar, this->mutex,
1336 this->vip_wait);
2a2d7a4d
MW
1337 }
1338 this->mutex->unlock(this->mutex);
1339 if (timeout)
1340 {
1341 DBG1(DBG_KNL, "virtual IP %H did not disappear from tun", vip);
1342 return FAILED;
1343 }
1344 }
1345 return SUCCESS;
d24a74c5
TB
1346}
1347
272bcac8
MW
1348/**
1349 * Append a sockaddr_in/in6 of given type to routing message
1350 */
1351static void add_rt_addr(struct rt_msghdr *hdr, int type, host_t *addr)
1352{
1353 if (addr)
1354 {
1355 int len;
1356
1357 len = *addr->get_sockaddr_len(addr);
1358 memcpy((char*)hdr + hdr->rtm_msglen, addr->get_sockaddr(addr), len);
aa33d2e6 1359 hdr->rtm_msglen += SA_LEN(len);
272bcac8
MW
1360 hdr->rtm_addrs |= type;
1361 }
1362}
1363
1364/**
1365 * Append a subnet mask sockaddr using the given prefix to routing message
1366 */
1367static void add_rt_mask(struct rt_msghdr *hdr, int type, int family, int prefix)
1368{
1369 host_t *mask;
1370
1371 mask = host_create_netmask(family, prefix);
1372 if (mask)
1373 {
1374 add_rt_addr(hdr, type, mask);
1375 mask->destroy(mask);
1376 }
1377}
1378
1379/**
1380 * Append an interface name sockaddr_dl to routing message
1381 */
1382static void add_rt_ifname(struct rt_msghdr *hdr, int type, char *name)
1383{
1384 struct sockaddr_dl sdl = {
1385 .sdl_len = sizeof(struct sockaddr_dl),
1386 .sdl_family = AF_LINK,
1387 .sdl_nlen = strlen(name),
1388 };
1389
1390 if (strlen(name) <= sizeof(sdl.sdl_data))
1391 {
1392 memcpy(sdl.sdl_data, name, sdl.sdl_nlen);
1393 memcpy((char*)hdr + hdr->rtm_msglen, &sdl, sdl.sdl_len);
aa33d2e6 1394 hdr->rtm_msglen += SA_LEN(sdl.sdl_len);
272bcac8
MW
1395 hdr->rtm_addrs |= type;
1396 }
1397}
1398
1399/**
1400 * Add or remove a route
1401 */
1402static status_t manage_route(private_kernel_pfroute_net_t *this, int op,
b12c53ce 1403 chunk_t dst_net, uint8_t prefixlen,
272bcac8
MW
1404 host_t *gateway, char *if_name)
1405{
1406 struct {
1407 struct rt_msghdr hdr;
1408 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
1409 } msg = {
1410 .hdr = {
1411 .rtm_version = RTM_VERSION,
1412 .rtm_type = op,
1413 .rtm_flags = RTF_UP | RTF_STATIC,
1414 .rtm_pid = this->pid,
e50b2053 1415 .rtm_seq = ref_get(&this->seq),
272bcac8
MW
1416 },
1417 };
1418 host_t *dst;
1419 int type;
1420
12178303
MW
1421 if (prefixlen == 0 && dst_net.len)
1422 {
1423 status_t status;
1424 chunk_t half;
1425
1426 half = chunk_clonea(dst_net);
1427 half.ptr[0] |= 0x80;
1428 prefixlen = 1;
1429 status = manage_route(this, op, half, prefixlen, gateway, if_name);
1430 if (status != SUCCESS)
1431 {
1432 return status;
1433 }
1434 }
1435
272bcac8
MW
1436 dst = host_create_from_chunk(AF_UNSPEC, dst_net, 0);
1437 if (!dst)
1438 {
1439 return FAILED;
1440 }
1441
1442 if ((dst->get_family(dst) == AF_INET && prefixlen == 32) ||
1443 (dst->get_family(dst) == AF_INET6 && prefixlen == 128))
1444 {
1445 msg.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
1446 }
1447
1448 msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
1449 for (type = 0; type < RTAX_MAX; type++)
1450 {
1451 switch (type)
1452 {
1453 case RTAX_DST:
1454 add_rt_addr(&msg.hdr, RTA_DST, dst);
1455 break;
1456 case RTAX_NETMASK:
1457 if (!(msg.hdr.rtm_flags & RTF_HOST))
1458 {
1459 add_rt_mask(&msg.hdr, RTA_NETMASK,
1460 dst->get_family(dst), prefixlen);
1461 }
1462 break;
f58f8bf4 1463 case RTAX_IFP:
272bcac8
MW
1464 if (if_name)
1465 {
f58f8bf4 1466 add_rt_ifname(&msg.hdr, RTA_IFP, if_name);
272bcac8 1467 }
f58f8bf4
TB
1468 break;
1469 case RTAX_GATEWAY:
da565d98
TB
1470 if (gateway &&
1471 gateway->get_family(gateway) == dst->get_family(dst))
272bcac8
MW
1472 {
1473 add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway);
1474 }
1475 break;
1476 default:
1477 break;
1478 }
1479 }
1480 dst->destroy(dst);
1481
1482 if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) != msg.hdr.rtm_msglen)
1483 {
527663d6
TB
1484 if (errno == EEXIST)
1485 {
1486 return ALREADY_DONE;
1487 }
272bcac8
MW
1488 DBG1(DBG_KNL, "%s PF_ROUTE route failed: %s",
1489 op == RTM_ADD ? "adding" : "deleting", strerror(errno));
1490 return FAILED;
1491 }
1492 return SUCCESS;
1493}
1494
e131f117 1495METHOD(kernel_net_t, add_route, status_t,
b12c53ce 1496 private_kernel_pfroute_net_t *this, chunk_t dst_net, uint8_t prefixlen,
09f4bccf 1497 host_t *gateway, host_t *src_ip, char *if_name, bool pass)
d24a74c5 1498{
0745f846
TB
1499 status_t status;
1500 route_entry_t *found, route = {
1501 .dst_net = dst_net,
1502 .prefixlen = prefixlen,
1503 .gateway = gateway,
1504 .if_name = if_name,
1505 };
1506
1507 this->routes_lock->lock(this->routes_lock);
1508 found = this->routes->get(this->routes, &route);
1509 if (found)
1510 {
1511 this->routes_lock->unlock(this->routes_lock);
1512 return ALREADY_DONE;
1513 }
0745f846 1514 status = manage_route(this, RTM_ADD, dst_net, prefixlen, gateway, if_name);
822b22c9
TB
1515 if (status == SUCCESS)
1516 {
1517 found = route_entry_clone(&route);
1518 this->routes->put(this->routes, found, found);
1519 }
0745f846
TB
1520 this->routes_lock->unlock(this->routes_lock);
1521 return status;
d24a74c5
TB
1522}
1523
e131f117 1524METHOD(kernel_net_t, del_route, status_t,
b12c53ce 1525 private_kernel_pfroute_net_t *this, chunk_t dst_net, uint8_t prefixlen,
09f4bccf 1526 host_t *gateway, host_t *src_ip, char *if_name, bool pass)
d24a74c5 1527{
0745f846
TB
1528 status_t status;
1529 route_entry_t *found, route = {
1530 .dst_net = dst_net,
1531 .prefixlen = prefixlen,
1532 .gateway = gateway,
1533 .if_name = if_name,
1534 };
1535
1536 this->routes_lock->lock(this->routes_lock);
1537 found = this->routes->get(this->routes, &route);
1538 if (!found)
1539 {
1540 this->routes_lock->unlock(this->routes_lock);
1541 return NOT_FOUND;
1542 }
1543 this->routes->remove(this->routes, found);
1544 route_entry_destroy(found);
1545 status = manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway,
1546 if_name);
1547 this->routes_lock->unlock(this->routes_lock);
1548 return status;
d24a74c5
TB
1549}
1550
d6c17e96
TB
1551/**
1552 * Do a route lookup for dest and return either the nexthop or the source
1553 * address.
1554 */
1555static host_t *get_route(private_kernel_pfroute_net_t *this, bool nexthop,
b52e540f 1556 host_t *dest, host_t *src, char **iface)
9bc342ea
MW
1557{
1558 struct {
1559 struct rt_msghdr hdr;
1560 char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
1561 } msg = {
1562 .hdr = {
1563 .rtm_version = RTM_VERSION,
1564 .rtm_type = RTM_GET,
1565 .rtm_pid = this->pid,
e50b2053 1566 .rtm_seq = ref_get(&this->seq),
9bc342ea
MW
1567 },
1568 };
12488efa 1569 host_t *host = NULL;
9bc342ea
MW
1570 enumerator_t *enumerator;
1571 struct sockaddr *addr;
dc8b083d 1572 bool failed = FALSE;
9bc342ea
MW
1573 int type;
1574
dc8b083d 1575retry:
9bc342ea
MW
1576 msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
1577 for (type = 0; type < RTAX_MAX; type++)
1578 {
1579 switch (type)
1580 {
1581 case RTAX_DST:
1582 add_rt_addr(&msg.hdr, RTA_DST, dest);
1583 break;
1584 case RTAX_IFA:
1585 add_rt_addr(&msg.hdr, RTA_IFA, src);
1586 break;
1c697ff1
TB
1587 case RTAX_IFP:
1588 if (!nexthop)
1589 { /* add an empty IFP to ensure we get a source address */
1590 add_rt_ifname(&msg.hdr, RTA_IFP, "");
1591 }
1592 break;
9bc342ea
MW
1593 default:
1594 break;
1595 }
1596 }
1597 this->mutex->lock(this->mutex);
1598
c9a323c1
MW
1599 while (this->waiting_seq)
1600 {
1601 this->condvar->wait(this->condvar, this->mutex);
1602 }
9bc342ea
MW
1603 this->waiting_seq = msg.hdr.rtm_seq;
1604 if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) == msg.hdr.rtm_msglen)
1605 {
1606 while (TRUE)
1607 {
1608 if (this->condvar->timed_wait(this->condvar, this->mutex, 1000))
1609 { /* timed out? */
1610 break;
1611 }
52ba4f6b 1612 if (!this->reply)
9bc342ea
MW
1613 {
1614 continue;
1615 }
b308a979 1616 enumerator = create_rtmsg_enumerator(this->reply);
9bc342ea
MW
1617 while (enumerator->enumerate(enumerator, &type, &addr))
1618 {
12488efa 1619 if (nexthop)
b0629f7d 1620 {
12488efa
TB
1621 if (type == RTAX_DST && this->reply->rtm_flags & RTF_HOST)
1622 { /* probably a cloned/cached direct route, only use that
1623 * as fallback if no gateway is found */
1624 host = host ?: host_create_from_sockaddr(addr);
1625 }
1626 if (type == RTAX_GATEWAY)
1627 { /* could actually be a MAC address */
1628 host_t *gtw = host_create_from_sockaddr(addr);
1629 if (gtw)
1630 {
1631 DESTROY_IF(host);
1632 host = gtw;
1633 }
1634 }
b52e540f
TB
1635 if (type == RTAX_IFP && addr->sa_family == AF_LINK)
1636 {
1637 struct sockaddr_dl *sdl = (struct sockaddr_dl*)addr;
1638 if (iface)
1639 {
1640 free(*iface);
1641 *iface = strndup(sdl->sdl_data, sdl->sdl_nlen);
1642 }
1643 }
34b0ad06 1644 }
12488efa 1645 else
d6c17e96 1646 {
12488efa 1647 if (type == RTAX_IFA)
b0629f7d 1648 {
12488efa 1649 host = host_create_from_sockaddr(addr);
b0629f7d 1650 }
9bc342ea
MW
1651 }
1652 }
1653 enumerator->destroy(enumerator);
1654 break;
1655 }
1656 }
1657 else
1658 {
dc8b083d 1659 failed = TRUE;
9bc342ea 1660 }
52ba4f6b
TB
1661 free(this->reply);
1662 this->reply = NULL;
c9a323c1
MW
1663 /* signal completion of query to a waiting thread */
1664 this->waiting_seq = 0;
1665 this->condvar->signal(this->condvar);
9bc342ea
MW
1666 this->mutex->unlock(this->mutex);
1667
dc8b083d
TB
1668 if (failed)
1669 {
1670 if (src)
1671 { /* the given source address might be gone, try again without */
1672 src = NULL;
e50b2053 1673 msg.hdr.rtm_seq = ref_get(&this->seq);
dc8b083d 1674 msg.hdr.rtm_addrs = 0;
45b80880 1675 memset(msg.buf, 0, sizeof(msg.buf));
dc8b083d
TB
1676 goto retry;
1677 }
1678 DBG1(DBG_KNL, "PF_ROUTE lookup failed: %s", strerror(errno));
1679 }
7522fcff 1680 if (nexthop)
b0629f7d 1681 {
7522fcff 1682 host = host ?: dest->clone(dest);
cb082d15 1683 }
7522fcff 1684 else
cb082d15
TB
1685 { /* make sure the source address is not virtual and usable */
1686 addr_entry_t *entry, lookup = {
1687 .ip = host,
1688 };
1689
7522fcff
TB
1690 if (!host)
1691 {
1692 return NULL;
1693 }
cb082d15
TB
1694 this->lock->read_lock(this->lock);
1695 entry = this->addrs->get_match(this->addrs, &lookup,
1696 (void*)addr_map_entry_match_up_and_usable);
1697 this->lock->unlock(this->lock);
1698 if (!entry)
1699 {
1700 host->destroy(host);
1701 return NULL;
1702 }
b0629f7d 1703 }
cb082d15
TB
1704 DBG2(DBG_KNL, "using %H as %s to reach %H", host,
1705 nexthop ? "nexthop" : "address", dest);
d6c17e96
TB
1706 return host;
1707}
1708
1709METHOD(kernel_net_t, get_source_addr, host_t*,
1710 private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
1711{
b52e540f 1712 return get_route(this, FALSE, dest, src, NULL);
d6c17e96
TB
1713}
1714
1715METHOD(kernel_net_t, get_nexthop, host_t*,
99a57aa5
TB
1716 private_kernel_pfroute_net_t *this, host_t *dest, int prefix, host_t *src,
1717 char **iface)
d6c17e96 1718{
99a57aa5
TB
1719 if (iface)
1720 {
1721 *iface = NULL;
1722 }
b52e540f 1723 return get_route(this, TRUE, dest, src, iface);
9bc342ea
MW
1724}
1725
21df4cc1
TB
1726/**
1727 * Get the number of set bits in the given netmask
1728 */
1729static uint8_t sockaddr_to_netmask(sockaddr_t *sockaddr, host_t *dst)
1730{
1731 uint8_t len = 0, i, byte, mask = 0;
1732 struct sockaddr_storage ss;
1733 char *addr;
1734
1735 /* at least some older FreeBSD versions send us shorter sockaddrs
1736 * with the family set to -1 (255) */
1737 if (sockaddr->sa_family == 255)
1738 {
1739 memset(&ss, 0, sizeof(ss));
1740 memcpy(&ss, sockaddr, sockaddr->sa_len);
1741 /* use the address family and length of the destination as hint */
1742 ss.ss_len = *dst->get_sockaddr_len(dst);
1743 ss.ss_family = dst->get_family(dst);
1744 sockaddr = (sockaddr_t*)&ss;
1745 }
1746
1747 switch (sockaddr->sa_family)
1748 {
1749 case AF_INET:
1750 len = 4;
1751 addr = (char*)&((struct sockaddr_in*)sockaddr)->sin_addr;
1752 break;
1753 case AF_INET6:
1754 len = 16;
1755 addr = (char*)&((struct sockaddr_in6*)sockaddr)->sin6_addr;
1756 break;
1757 default:
1758 break;
1759 }
1760
1761 for (i = 0; i < len; i++)
1762 {
1763 byte = addr[i];
1764
1765 if (byte == 0x00)
1766 {
1767 break;
1768 }
1769 if (byte == 0xff)
1770 {
1771 mask += 8;
1772 }
1773 else
1774 {
1775 while (byte & 0x80)
1776 {
1777 mask++;
1778 byte <<= 1;
1779 }
1780 }
1781 }
1782 return mask;
1783}
1784
1785/** enumerator over subnets */
1786typedef struct {
1787 enumerator_t public;
1788 /** sysctl result */
1789 char *buf;
1790 /** length of the complete result */
1791 size_t len;
1792 /** start of the current route entry */
1793 char *current;
1794 /** last subnet enumerated */
1795 host_t *net;
1796 /** interface of current net */
1797 char *ifname;
1798} subnet_enumerator_t;
1799
1800METHOD(enumerator_t, destroy_subnet_enumerator, void,
1801 subnet_enumerator_t *this)
1802{
1803 DESTROY_IF(this->net);
1804 free(this->ifname);
1805 free(this->buf);
1806 free(this);
1807}
1808
1809METHOD(enumerator_t, enumerate_subnets, bool,
95a63bf2 1810 subnet_enumerator_t *this, va_list args)
21df4cc1
TB
1811{
1812 enumerator_t *enumerator;
95a63bf2 1813 host_t **net;
21df4cc1
TB
1814 struct rt_msghdr *rtm;
1815 struct sockaddr *addr;
95a63bf2
TB
1816 uint8_t *mask;
1817 char **ifname;
21df4cc1
TB
1818 int type;
1819
95a63bf2
TB
1820 VA_ARGS_VGET(args, net, mask, ifname);
1821
21df4cc1
TB
1822 if (!this->current)
1823 {
1824 this->current = this->buf;
1825 }
1826 else
1827 {
1828 rtm = (struct rt_msghdr*)this->current;
1829 this->current += rtm->rtm_msglen;
1830 DESTROY_IF(this->net);
1831 this->net = NULL;
1832 free(this->ifname);
1833 this->ifname = NULL;
1834 }
1835
1836 for (; this->current < this->buf + this->len;
1837 this->current += rtm->rtm_msglen)
1838 {
fd0a7b47 1839 struct sockaddr *netmask = NULL;
21df4cc1
TB
1840 uint8_t netbits = 0;
1841
1842 rtm = (struct rt_msghdr*)this->current;
1843
1844 if (rtm->rtm_version != RTM_VERSION)
1845 {
1846 continue;
1847 }
1848 if (rtm->rtm_flags & RTF_GATEWAY ||
1849 rtm->rtm_flags & RTF_HOST ||
1850 rtm->rtm_flags & RTF_REJECT)
1851 {
1852 continue;
1853 }
1854 enumerator = create_rtmsg_enumerator(rtm);
1855 while (enumerator->enumerate(enumerator, &type, &addr))
1856 {
1857 if (type == RTAX_DST)
1858 {
1859 this->net = this->net ?: host_create_from_sockaddr(addr);
1860 }
1861 if (type == RTAX_NETMASK)
1862 {
1863 netmask = addr;
1864 }
1865 if (type == RTAX_IFP && addr->sa_family == AF_LINK)
1866 {
1867 struct sockaddr_dl *sdl = (struct sockaddr_dl*)addr;
1868 free(this->ifname);
1869 this->ifname = strndup(sdl->sdl_data, sdl->sdl_nlen);
1870 }
1871 }
fd0a7b47 1872 if (this->net && netmask)
21df4cc1
TB
1873 {
1874 netbits = sockaddr_to_netmask(netmask, this->net);
1875 }
1876 enumerator->destroy(enumerator);
1877
1878 if (this->net && this->ifname)
1879 {
1880 *net = this->net;
1881 *mask = netbits ?: this->net->get_address(this->net).len * 8;
1882 *ifname = this->ifname;
1883 return TRUE;
1884 }
1885 }
1886 return FALSE;
1887}
1888
1889METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
1890 private_kernel_pfroute_net_t *this)
1891{
1892 subnet_enumerator_t *enumerator;
1893 char *buf;
1894 size_t len;
1895 int mib[7] = {
1896 CTL_NET, PF_ROUTE, 0, AF_UNSPEC, NET_RT_DUMP, 0, 0
1897 };
1898
1899 if (sysctl(mib, countof(mib), NULL, &len, NULL, 0) < 0)
1900 {
1901 DBG2(DBG_KNL, "enumerating local subnets failed");
1902 return enumerator_create_empty();
1903 }
1904 buf = malloc(len);
1905 if (sysctl(mib, countof(mib), buf, &len, NULL, 0) < 0)
1906 {
1907 DBG2(DBG_KNL, "enumerating local subnets failed");
1908 free(buf);
1909 return enumerator_create_empty();
1910 }
1911
1912 INIT(enumerator,
1913 .public = {
95a63bf2
TB
1914 .enumerate = enumerator_enumerate_default,
1915 .venumerate = _enumerate_subnets,
21df4cc1
TB
1916 .destroy = _destroy_subnet_enumerator,
1917 },
1918 .buf = buf,
1919 .len = len,
1920 );
1921 return &enumerator->public;
1922}
1923
d24a74c5
TB
1924/**
1925 * Initialize a list of local addresses.
1926 */
1927static status_t init_address_list(private_kernel_pfroute_net_t *this)
1928{
1929 struct ifaddrs *ifap, *ifa;
1930 iface_entry_t *iface, *current;
1931 addr_entry_t *addr;
1932 enumerator_t *ifaces, *addrs;
7daf5226 1933
31a0e24b 1934 DBG2(DBG_KNL, "known interfaces and IP addresses:");
7daf5226 1935
d24a74c5
TB
1936 if (getifaddrs(&ifap) < 0)
1937 {
1938 DBG1(DBG_KNL, " failed to get interfaces!");
1939 return FAILED;
1940 }
7daf5226 1941
d24a74c5
TB
1942 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
1943 {
1944 if (ifa->ifa_addr == NULL)
1945 {
1946 continue;
1947 }
1948 switch(ifa->ifa_addr->sa_family)
1949 {
1950 case AF_LINK:
1951 case AF_INET:
1952 case AF_INET6:
1953 {
d24a74c5
TB
1954 iface = NULL;
1955 ifaces = this->ifaces->create_enumerator(this->ifaces);
1956 while (ifaces->enumerate(ifaces, &current))
1957 {
1958 if (streq(current->ifname, ifa->ifa_name))
1959 {
1960 iface = current;
1961 break;
1962 }
1963 }
1964 ifaces->destroy(ifaces);
7daf5226 1965
d24a74c5
TB
1966 if (!iface)
1967 {
9650bf3c
MW
1968 INIT(iface,
1969 .ifindex = if_nametoindex(ifa->ifa_name),
1970 .flags = ifa->ifa_flags,
1971 .addrs = linked_list_create(),
8394ea2a
TB
1972 .usable = charon->kernel->is_interface_usable(
1973 charon->kernel, ifa->ifa_name),
9650bf3c 1974 );
d24a74c5 1975 memcpy(iface->ifname, ifa->ifa_name, IFNAMSIZ);
d24a74c5
TB
1976 this->ifaces->insert_last(this->ifaces, iface);
1977 }
7daf5226 1978
d24a74c5
TB
1979 if (ifa->ifa_addr->sa_family != AF_LINK)
1980 {
9650bf3c
MW
1981 INIT(addr,
1982 .ip = host_create_from_sockaddr(ifa->ifa_addr),
9650bf3c 1983 );
d24a74c5 1984 iface->addrs->insert_last(iface->addrs, addr);
9845391a 1985 addr_map_entry_add(this, addr, iface);
d24a74c5
TB
1986 }
1987 }
1988 }
1989 }
1990 freeifaddrs(ifap);
7daf5226 1991
d24a74c5
TB
1992 ifaces = this->ifaces->create_enumerator(this->ifaces);
1993 while (ifaces->enumerate(ifaces, &iface))
1994 {
940e1b0f 1995 if (iface->usable && iface->flags & IFF_UP)
d24a74c5 1996 {
31a0e24b 1997 DBG2(DBG_KNL, " %s", iface->ifname);
d24a74c5
TB
1998 addrs = iface->addrs->create_enumerator(iface->addrs);
1999 while (addrs->enumerate(addrs, (void**)&addr))
2000 {
31a0e24b 2001 DBG2(DBG_KNL, " %H", addr->ip);
d24a74c5
TB
2002 }
2003 addrs->destroy(addrs);
2004 }
2005 }
2006 ifaces->destroy(ifaces);
7daf5226 2007
d24a74c5
TB
2008 return SUCCESS;
2009}
2010
cce8f652 2011METHOD(kernel_net_t, destroy, void,
e131f117 2012 private_kernel_pfroute_net_t *this)
d24a74c5 2013{
1f97e1aa 2014 enumerator_t *enumerator;
0745f846 2015 route_entry_t *route;
bfd2cc1c 2016 addr_entry_t *addr;
1f97e1aa 2017
0745f846
TB
2018 enumerator = this->routes->create_enumerator(this->routes);
2019 while (enumerator->enumerate(enumerator, NULL, (void**)&route))
2020 {
2021 manage_route(this, RTM_DELETE, route->dst_net, route->prefixlen,
2022 route->gateway, route->if_name);
2023 route_entry_destroy(route);
2024 }
2025 enumerator->destroy(enumerator);
2026 this->routes->destroy(this->routes);
2027 this->routes_lock->destroy(this->routes_lock);
2028
0e107f03 2029 if (this->socket != -1)
d6a27ec6 2030 {
46666dd3 2031 lib->watcher->remove(lib->watcher, this->socket);
d6a27ec6
MW
2032 close(this->socket);
2033 }
0745f846
TB
2034
2035 net_changes_clear(this);
2036 this->net_changes->destroy(this->net_changes);
2037 this->net_changes_lock->destroy(this->net_changes_lock);
2038
1f97e1aa
TB
2039 enumerator = this->addrs->create_enumerator(this->addrs);
2040 while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
2041 {
2042 free(addr);
2043 }
2044 enumerator->destroy(enumerator);
2045 this->addrs->destroy(this->addrs);
d24a74c5 2046 this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
2a2d7a4d 2047 this->tuns->destroy(this->tuns);
bdf36dac 2048 this->lock->destroy(this->lock);
3a7f4b5c
MW
2049 this->mutex->destroy(this->mutex);
2050 this->condvar->destroy(this->condvar);
55da01f3 2051 this->roam_lock->destroy(this->roam_lock);
3a7f4b5c 2052 free(this->reply);
d24a74c5
TB
2053 free(this);
2054}
2055
2056/*
2057 * Described in header.
2058 */
2059kernel_pfroute_net_t *kernel_pfroute_net_create()
2060{
e131f117
MW
2061 private_kernel_pfroute_net_t *this;
2062
2063 INIT(this,
2064 .public = {
2065 .interface = {
580b768d 2066 .get_features = _get_features,
e131f117
MW
2067 .get_interface = _get_interface_name,
2068 .create_address_enumerator = _create_address_enumerator,
21df4cc1 2069 .create_local_subnet_enumerator = _create_local_subnet_enumerator,
e131f117
MW
2070 .get_source_addr = _get_source_addr,
2071 .get_nexthop = _get_nexthop,
2072 .add_ip = _add_ip,
2073 .del_ip = _del_ip,
2074 .add_route = _add_route,
2075 .del_route = _del_route,
2076 .destroy = _destroy,
2077 },
2078 },
3a7f4b5c 2079 .pid = getpid(),
e131f117 2080 .ifaces = linked_list_create(),
1f97e1aa
TB
2081 .addrs = hashtable_create(
2082 (hashtable_hash_t)addr_map_entry_hash,
2083 (hashtable_equals_t)addr_map_entry_equals, 16),
0745f846
TB
2084 .routes = hashtable_create((hashtable_hash_t)route_entry_hash,
2085 (hashtable_equals_t)route_entry_equals, 16),
2086 .net_changes = hashtable_create(
2087 (hashtable_hash_t)net_change_hash,
2088 (hashtable_equals_t)net_change_equals, 16),
2a2d7a4d 2089 .tuns = linked_list_create(),
bdf36dac 2090 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
3a7f4b5c
MW
2091 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
2092 .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
0745f846
TB
2093 .routes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
2094 .net_changes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
55da01f3 2095 .roam_lock = spinlock_create(),
baa6419e 2096 .vip_wait = lib->settings->get_int(lib->settings,
d347a130 2097 "%s.plugins.kernel-pfroute.vip_wait", 1000, lib->ns),
df085a15
TB
2098 .install_virtual_ip = lib->settings->get_bool(lib->settings,
2099 "%s.install_virtual_ip", TRUE, lib->ns),
e131f117 2100 );
0745f846 2101 timerclear(&this->last_route_reinstall);
55da01f3 2102 timerclear(&this->next_roam);
7daf5226 2103
d24a74c5
TB
2104 /* create a PF_ROUTE socket to communicate with the kernel */
2105 this->socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
0e107f03 2106 if (this->socket == -1)
d24a74c5 2107 {
d6a27ec6
MW
2108 DBG1(DBG_KNL, "unable to create PF_ROUTE socket");
2109 destroy(this);
2110 return NULL;
d24a74c5 2111 }
7daf5226 2112
d347a130 2113 if (streq(lib->ns, "starter"))
d24a74c5 2114 {
0e107f03
MW
2115 /* starter has no threads, so we do not register for kernel events */
2116 if (shutdown(this->socket, SHUT_RD) != 0)
05ca5655 2117 {
0e107f03
MW
2118 DBG1(DBG_KNL, "closing read end of PF_ROUTE socket failed: %s",
2119 strerror(errno));
05ca5655 2120 }
0e107f03
MW
2121 }
2122 else
2123 {
46666dd3
MW
2124 lib->watcher->add(lib->watcher, this->socket, WATCHER_READ,
2125 (watcher_cb_t)receive_events, this);
05ca5655 2126 }
d24a74c5
TB
2127 if (init_address_list(this) != SUCCESS)
2128 {
d6a27ec6
MW
2129 DBG1(DBG_KNL, "unable to get interface list");
2130 destroy(this);
2131 return NULL;
d24a74c5 2132 }
7daf5226 2133
d24a74c5
TB
2134 return &this->public;
2135}