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