windows: Do not check if having clock_gettime()
[strongswan.git] / src / libcharon / plugins / kernel_iph / kernel_iph_net.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /* Windows 7, for some iphlpapi.h functionality */
17 #define _WIN32_WINNT 0x0601
18 #include <winsock2.h>
19 #include <ws2ipdef.h>
20 #include <windows.h>
21 #include <ntddndis.h>
22 #include <naptypes.h>
23 #include <iphlpapi.h>
24
25 #include "kernel_iph_net.h"
26
27 #include <hydra.h>
28 #include <threading/mutex.h>
29 #include <collections/linked_list.h>
30 #include <processing/jobs/callback_job.h>
31
32
33 /** delay before firing roam events (ms) */
34 #define ROAM_DELAY 500
35
36 typedef struct private_kernel_iph_net_t private_kernel_iph_net_t;
37
38 /**
39 * Private data of kernel_iph_net implementation.
40 */
41 struct private_kernel_iph_net_t {
42
43 /**
44 * Public interface.
45 */
46 kernel_iph_net_t public;
47
48 /**
49 * NotifyIpInterfaceChange() handle
50 */
51 HANDLE changes;
52
53 /**
54 * EnableRouter() OVERLAPPED
55 */
56 OVERLAPPED router;
57
58 /**
59 * Mutex to access interface list
60 */
61 mutex_t *mutex;
62
63 /**
64 * Known interfaces, as iface_t
65 */
66 linked_list_t *ifaces;
67
68 /**
69 * Earliest time of the next roam event
70 */
71 timeval_t roam_next;
72
73 /**
74 * Roam event due to address change?
75 */
76 bool roam_address;
77 };
78
79 /**
80 * Interface entry
81 */
82 typedef struct {
83 /** interface index */
84 DWORD ifindex;
85 /** interface name */
86 char *ifname;
87 /** interface description */
88 char *ifdesc;
89 /** type of interface */
90 DWORD iftype;
91 /** interface status */
92 IF_OPER_STATUS status;
93 /** list of known addresses, as host_t */
94 linked_list_t *addrs;
95 } iface_t;
96
97 /**
98 * Clean up an iface_t
99 */
100 static void iface_destroy(iface_t *this)
101 {
102 this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
103 free(this->ifname);
104 free(this->ifdesc);
105 free(this);
106 }
107
108 /**
109 * Enum names for Windows IF_OPER_STATUS
110 */
111 ENUM(if_oper_names, IfOperStatusUp, IfOperStatusLowerLayerDown,
112 "Up",
113 "Down",
114 "Testing",
115 "Unknown",
116 "Dormant",
117 "NotPresent",
118 "LowerLayerDown",
119 );
120
121 /**
122 * Callback function that raises the delayed roam event
123 */
124 static job_requeue_t roam_event(private_kernel_iph_net_t *this)
125 {
126 bool address;
127
128 this->mutex->lock(this->mutex);
129 address = this->roam_address;
130 this->roam_address = FALSE;
131 this->mutex->unlock(this->mutex);
132
133 hydra->kernel_interface->roam(hydra->kernel_interface, address);
134 return JOB_REQUEUE_NONE;
135 }
136
137 /**
138 * Fire delayed roam event, caller should hold mutex
139 */
140 static void fire_roam_event(private_kernel_iph_net_t *this, bool address)
141 {
142 timeval_t now;
143
144 time_monotonic(&now);
145 this->roam_address |= address;
146 if (timercmp(&now, &this->roam_next, >))
147 {
148 timeval_add_ms(&now, ROAM_DELAY);
149 this->roam_next = now;
150 lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
151 callback_job_create((callback_job_cb_t)roam_event,
152 this, NULL, NULL),
153 ROAM_DELAY);
154 }
155 }
156
157 /**
158 * Update addresses for an iface entry
159 */
160 static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
161 IP_ADAPTER_ADDRESSES *addr, bool log)
162 {
163 IP_ADAPTER_UNICAST_ADDRESS *current;
164 enumerator_t *enumerator;
165 linked_list_t *list;
166 host_t *host, *old;
167 bool changes = FALSE;
168
169 list = entry->addrs;
170 entry->addrs = linked_list_create();
171
172 for (current = addr->FirstUnicastAddress; current; current = current->Next)
173 {
174 if (current->Address.lpSockaddr->sa_family == AF_INET6)
175 {
176 struct sockaddr_in6 *sin;
177
178 sin = (struct sockaddr_in6*)current->Address.lpSockaddr;
179 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
180 {
181 continue;
182 }
183 }
184
185 host = host_create_from_sockaddr(current->Address.lpSockaddr);
186 if (host)
187 {
188 bool found = FALSE;
189
190 enumerator = list->create_enumerator(list);
191 while (enumerator->enumerate(enumerator, &old))
192 {
193 if (host->ip_equals(host, old))
194 {
195 list->remove_at(list, enumerator);
196 old->destroy(old);
197 found = TRUE;
198 }
199 }
200 enumerator->destroy(enumerator);
201
202 entry->addrs->insert_last(entry->addrs, host);
203
204 if (!found && log)
205 {
206 DBG1(DBG_KNL, "%H appeared on interface %u '%s'",
207 host, entry->ifindex, entry->ifdesc);
208 changes = TRUE;
209 }
210 }
211 }
212
213 while (list->remove_first(list, (void**)&old) == SUCCESS)
214 {
215 if (log)
216 {
217 DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
218 old, entry->ifindex, entry->ifdesc);
219 changes = TRUE;
220 }
221 old->destroy(old);
222 }
223 list->destroy(list);
224
225 if (changes)
226 {
227 fire_roam_event(this, TRUE);
228 }
229 }
230
231 /**
232 * Add an interface entry
233 */
234 static void add_interface(private_kernel_iph_net_t *this,
235 IP_ADAPTER_ADDRESSES *addr, bool log)
236 {
237 enumerator_t *enumerator;
238 iface_t *entry;
239 bool exists = FALSE;
240
241 this->mutex->lock(this->mutex);
242 enumerator = this->ifaces->create_enumerator(this->ifaces);
243 while (enumerator->enumerate(enumerator, &entry))
244 {
245 if (entry->ifindex == addr->IfIndex)
246 {
247 exists = TRUE;
248 break;
249 }
250 }
251 enumerator->destroy(enumerator);
252 this->mutex->unlock(this->mutex);
253
254 if (!exists)
255 {
256 char desc[128] = "";
257
258 wcstombs(desc, addr->Description, sizeof(desc));
259
260 INIT(entry,
261 .ifindex = addr->IfIndex,
262 .ifname = strdup(addr->AdapterName),
263 .ifdesc = strdup(desc),
264 .iftype = addr->IfType,
265 .status = addr->OperStatus,
266 .addrs = linked_list_create(),
267 );
268
269 if (log)
270 {
271 DBG1(DBG_KNL, "interface %u '%s' appeared",
272 entry->ifindex, entry->ifdesc);
273 }
274
275 this->mutex->lock(this->mutex);
276 update_addrs(this, entry, addr, log);
277 this->ifaces->insert_last(this->ifaces, entry);
278 this->mutex->unlock(this->mutex);
279 }
280 }
281
282 /**
283 * Remove an interface entry that is gone
284 */
285 static void remove_interface(private_kernel_iph_net_t *this, NET_IFINDEX index)
286 {
287 enumerator_t *enumerator;
288 iface_t *entry;
289
290 this->mutex->lock(this->mutex);
291 enumerator = this->ifaces->create_enumerator(this->ifaces);
292 while (enumerator->enumerate(enumerator, &entry))
293 {
294 if (entry->ifindex == index)
295 {
296 this->ifaces->remove_at(this->ifaces, enumerator);
297 DBG1(DBG_KNL, "interface %u '%s' disappeared",
298 entry->ifindex, entry->ifdesc);
299 iface_destroy(entry);
300 fire_roam_event(this, TRUE);
301 }
302 }
303 enumerator->destroy(enumerator);
304 this->mutex->unlock(this->mutex);
305 }
306
307 /**
308 * Update an interface entry changed
309 */
310 static void update_interface(private_kernel_iph_net_t *this,
311 IP_ADAPTER_ADDRESSES *addr)
312 {
313 enumerator_t *enumerator;
314 iface_t *entry;
315
316 this->mutex->lock(this->mutex);
317 enumerator = this->ifaces->create_enumerator(this->ifaces);
318 while (enumerator->enumerate(enumerator, &entry))
319 {
320 if (entry->ifindex == addr->IfIndex)
321 {
322 if (entry->status != addr->OperStatus)
323 {
324 DBG1(DBG_KNL, "interface %u '%s' changed state from %N to %N",
325 entry->ifindex, entry->ifdesc, if_oper_names,
326 entry->status, if_oper_names, addr->OperStatus);
327 entry->status = addr->OperStatus;
328 fire_roam_event(this, TRUE);
329 }
330 update_addrs(this, entry, addr, TRUE);
331 }
332 }
333 enumerator->destroy(enumerator);
334 this->mutex->unlock(this->mutex);
335 }
336
337 /**
338 * MinGW gets MIB_IPINTERFACE_ROW wrong, as it packs InterfaceLuid just after
339 * Family. Fix that with our own version of the struct header.
340 */
341 typedef struct {
342 ADDRESS_FAMILY Family;
343 union {
344 ULONG64 Value;
345 struct {
346 ULONG64 Reserved :24;
347 ULONG64 NetLuidIndex :24;
348 ULONG64 IfType :16;
349 } Info;
350 } InterfaceLuid;
351 NET_IFINDEX InterfaceIndex;
352 /* more would go here if needed */
353 } MIB_IPINTERFACE_ROW_FIXUP;
354
355 /**
356 * NotifyIpInterfaceChange() callback
357 */
358 static void change_interface(private_kernel_iph_net_t *this,
359 MIB_IPINTERFACE_ROW_FIXUP *row, MIB_NOTIFICATION_TYPE type)
360 {
361 IP_ADAPTER_ADDRESSES addrs[64], *current;
362 ULONG res, size = sizeof(addrs);
363
364 if (row && type == MibDeleteInstance)
365 {
366 remove_interface(this, row->InterfaceIndex);
367 }
368 else
369 {
370 res = GetAdaptersAddresses(AF_UNSPEC,
371 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
372 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
373 NULL, addrs, &size);
374 if (res == NO_ERROR)
375 {
376 current = addrs;
377 while (current)
378 {
379 /* row is NULL only on MibInitialNotification */
380 if (!row || row->InterfaceIndex == current->IfIndex)
381 {
382 switch (type)
383 {
384 case MibParameterNotification:
385 update_interface(this, current);
386 break;
387 case MibInitialNotification:
388 add_interface(this, current, FALSE);
389 break;
390 case MibAddInstance:
391 add_interface(this, current, TRUE);
392 break;
393 default:
394 break;
395 }
396 }
397 current = current->Next;
398 }
399 }
400 else
401 {
402 DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res);
403 }
404 }
405 }
406
407 /**
408 * Get an iface entry for a local address, does no locking
409 */
410 static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip)
411 {
412 enumerator_t *ifaces, *addrs;
413 iface_t *entry, *found = NULL;
414 host_t *host;
415
416 ifaces = this->ifaces->create_enumerator(this->ifaces);
417 while (!found && ifaces->enumerate(ifaces, &entry))
418 {
419 addrs = entry->addrs->create_enumerator(entry->addrs);
420 while (!found && addrs->enumerate(addrs, &host))
421 {
422 if (host->ip_equals(host, ip))
423 {
424 found = entry;
425 }
426 }
427 addrs->destroy(addrs);
428 }
429 ifaces->destroy(ifaces);
430
431 return found;
432 }
433
434 METHOD(kernel_net_t, get_interface_name, bool,
435 private_kernel_iph_net_t *this, host_t* ip, char **name)
436 {
437 iface_t *entry;
438
439 this->mutex->lock(this->mutex);
440 entry = address2entry(this, ip);
441 if (entry && name)
442 {
443 *name = strdup(entry->ifname);
444 }
445 this->mutex->unlock(this->mutex);
446
447 return entry != NULL;
448 }
449
450 /**
451 * Address enumerator
452 */
453 typedef struct {
454 /** implements enumerator_t */
455 enumerator_t public;
456 /** what kind of address should we enumerate? */
457 kernel_address_type_t which;
458 /** enumerator over interfaces */
459 enumerator_t *ifaces;
460 /** current enumerator over addresses, or NULL */
461 enumerator_t *addrs;
462 /** mutex to unlock on destruction */
463 mutex_t *mutex;
464 } addr_enumerator_t;
465
466 METHOD(enumerator_t, addr_enumerate, bool,
467 addr_enumerator_t *this, host_t **host)
468 {
469 iface_t *entry;
470
471 while (TRUE)
472 {
473 while (!this->addrs)
474 {
475 if (!this->ifaces->enumerate(this->ifaces, &entry))
476 {
477 return FALSE;
478 }
479 if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK &&
480 !(this->which & ADDR_TYPE_LOOPBACK))
481 {
482 continue;
483 }
484 if (entry->status != IfOperStatusUp &&
485 !(this->which & ADDR_TYPE_DOWN))
486 {
487 continue;
488 }
489 this->addrs = entry->addrs->create_enumerator(entry->addrs);
490 }
491 if (this->addrs->enumerate(this->addrs, host))
492 {
493 return TRUE;
494 }
495 this->addrs->destroy(this->addrs);
496 this->addrs = NULL;
497 }
498 }
499
500 METHOD(enumerator_t, addr_destroy, void,
501 addr_enumerator_t *this)
502 {
503 DESTROY_IF(this->addrs);
504 this->ifaces->destroy(this->ifaces);
505 this->mutex->unlock(this->mutex);
506 free(this);
507 }
508
509 METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
510 private_kernel_iph_net_t *this, kernel_address_type_t which)
511 {
512 addr_enumerator_t *enumerator;
513
514 if (!(which & ADDR_TYPE_REGULAR))
515 {
516 /* we currently have no virtual, but regular IPs only */
517 return enumerator_create_empty();
518 }
519
520 this->mutex->lock(this->mutex);
521
522 INIT(enumerator,
523 .public = {
524 .enumerate = (void*)_addr_enumerate,
525 .destroy = _addr_destroy,
526 },
527 .which = which,
528 .ifaces = this->ifaces->create_enumerator(this->ifaces),
529 .mutex = this->mutex,
530 );
531 return &enumerator->public;
532 }
533
534 METHOD(kernel_net_t, get_source_addr, host_t*,
535 private_kernel_iph_net_t *this, host_t *dest, host_t *src)
536 {
537 MIB_IPFORWARD_ROW2 route;
538 SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
539 DWORD res, index = 0;
540
541 res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
542 if (res != NO_ERROR)
543 {
544 DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
545 return NULL;
546 }
547
548 sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
549 if (src)
550 {
551 sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
552 }
553 res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
554 if (res != NO_ERROR)
555 {
556 DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res);
557 return NULL;
558 }
559 return host_create_from_sockaddr((struct sockaddr*)&best);
560 }
561
562 METHOD(kernel_net_t, get_nexthop, host_t*,
563 private_kernel_iph_net_t *this, host_t *dest, host_t *src)
564 {
565 MIB_IPFORWARD_ROW2 route;
566 SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
567 DWORD res, index = 0;
568 host_t *nexthop;
569
570 res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
571 if (res != NO_ERROR)
572 {
573 DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
574 return NULL;
575 }
576
577 sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
578 if (src)
579 {
580 sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
581 }
582 res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
583 if (res != NO_ERROR)
584 {
585 DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res);
586 return NULL;
587 }
588 nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop);
589 if (nexthop)
590 {
591 if (!nexthop->is_anyaddr(nexthop))
592 {
593 return nexthop;
594 }
595 nexthop->destroy(nexthop);
596 }
597 return NULL;
598 }
599
600 METHOD(kernel_net_t, add_ip, status_t,
601 private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
602 char *iface_name)
603 {
604 return NOT_SUPPORTED;
605 }
606
607 METHOD(kernel_net_t, del_ip, status_t,
608 private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
609 bool wait)
610 {
611 return NOT_SUPPORTED;
612 }
613
614 /**
615 * Add or remove a route
616 */
617 static status_t manage_route(private_kernel_iph_net_t *this, bool add,
618 chunk_t dst, u_int8_t prefixlen, host_t *gtw, char *name)
619 {
620 MIB_IPFORWARD_ROW2 row = {
621 .DestinationPrefix = {
622 .PrefixLength = prefixlen,
623 },
624 .SitePrefixLength = prefixlen,
625 .ValidLifetime = INFINITE,
626 .PreferredLifetime = INFINITE,
627 .Metric = 10,
628 .Protocol = MIB_IPPROTO_NETMGMT,
629 };
630 enumerator_t *enumerator;
631 iface_t *entry;
632 ULONG ret;
633
634 this->mutex->lock(this->mutex);
635 enumerator = this->ifaces->create_enumerator(this->ifaces);
636 while (enumerator->enumerate(enumerator, &entry))
637 {
638 if (streq(name, entry->ifname))
639 {
640 row.InterfaceIndex = entry->ifindex;
641 break;
642 }
643 }
644 enumerator->destroy(enumerator);
645 this->mutex->unlock(this->mutex);
646
647 if (!row.InterfaceIndex)
648 {
649 return NOT_FOUND;
650 }
651 switch (dst.len)
652 {
653 case 4:
654 row.DestinationPrefix.Prefix.si_family = AF_INET;
655 memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr,
656 dst.ptr, dst.len);
657 break;
658 case 16:
659 row.DestinationPrefix.Prefix.si_family = AF_INET6;
660 memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr,
661 dst.ptr, dst.len);
662 break;
663 default:
664 return FAILED;
665 }
666 if (gtw)
667 {
668 memcpy(&row.NextHop, gtw->get_sockaddr(gtw),
669 *gtw->get_sockaddr_len(gtw));
670 }
671
672 if (add)
673 {
674 ret = CreateIpForwardEntry2(&row);
675 }
676 else
677 {
678 ret = DeleteIpForwardEntry2(&row);
679 }
680 if (ret != NO_ERROR)
681 {
682 DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret);
683 return FAILED;
684 }
685
686 if (add)
687 {
688 ret = EnableRouter(NULL, &this->router);
689 if (ret != ERROR_IO_PENDING)
690 {
691 DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret);
692 }
693 }
694 else
695 {
696 ret = UnenableRouter(&this->router, NULL);
697 if (ret != NO_ERROR)
698 {
699 DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret);
700 }
701 }
702 return SUCCESS;
703 }
704
705 METHOD(kernel_net_t, add_route, status_t,
706 private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen,
707 host_t *gateway, host_t *src, char *name)
708 {
709 return manage_route(this, TRUE, dst, prefixlen, gateway, name);
710 }
711
712 METHOD(kernel_net_t, del_route, status_t,
713 private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen,
714 host_t *gateway, host_t *src, char *name)
715 {
716 return manage_route(this, FALSE, dst, prefixlen, gateway, name);
717 }
718
719 METHOD(kernel_net_t, destroy, void,
720 private_kernel_iph_net_t *this)
721 {
722 if (this->changes)
723 {
724 CancelMibChangeNotify2(this->changes);
725 }
726 CloseHandle(this->router.hEvent);
727 this->mutex->destroy(this->mutex);
728 this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy);
729 free(this);
730 }
731
732 /*
733 * Described in header.
734 */
735 kernel_iph_net_t *kernel_iph_net_create()
736 {
737 private_kernel_iph_net_t *this;
738 ULONG res;
739
740 INIT(this,
741 .public = {
742 .interface = {
743 .get_interface = _get_interface_name,
744 .create_address_enumerator = _create_address_enumerator,
745 .get_source_addr = _get_source_addr,
746 .get_nexthop = _get_nexthop,
747 .add_ip = _add_ip,
748 .del_ip = _del_ip,
749 .add_route = _add_route,
750 .del_route = _del_route,
751 .destroy = _destroy,
752 },
753 },
754 .router = {
755 .hEvent = CreateEvent(NULL, FALSE, FALSE, NULL),
756 },
757 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
758 .ifaces = linked_list_create(),
759 );
760
761 res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface,
762 this, TRUE, &this->changes);
763 if (res != NO_ERROR)
764 {
765 DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx",
766 res);
767 destroy(this);
768 return NULL;
769 }
770
771 return &this->public;
772 }