Return to kernel_iph_net.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / kernel_iph |
1.1 misho 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 <daemon.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: charon->kernel->roam(charon->kernel, 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 WINAPI change_interface(void *user, PMIB_IPINTERFACE_ROW row_badal, 359: MIB_NOTIFICATION_TYPE type) 360: { 361: private_kernel_iph_net_t *this = user; 362: MIB_IPINTERFACE_ROW_FIXUP* row = (MIB_IPINTERFACE_ROW_FIXUP*)row_badal; 363: IP_ADAPTER_ADDRESSES addrs[64], *current; 364: ULONG res, size = sizeof(addrs); 365: 366: if (row && type == MibDeleteInstance) 367: { 368: remove_interface(this, row->InterfaceIndex); 369: } 370: else 371: { 372: res = GetAdaptersAddresses(AF_UNSPEC, 373: GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | 374: GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, 375: NULL, addrs, &size); 376: if (res == NO_ERROR) 377: { 378: current = addrs; 379: while (current) 380: { 381: /* row is NULL only on MibInitialNotification */ 382: if (!row || row->InterfaceIndex == current->IfIndex) 383: { 384: switch (type) 385: { 386: case MibParameterNotification: 387: update_interface(this, current); 388: break; 389: case MibInitialNotification: 390: add_interface(this, current, FALSE); 391: break; 392: case MibAddInstance: 393: add_interface(this, current, TRUE); 394: break; 395: default: 396: break; 397: } 398: } 399: current = current->Next; 400: } 401: } 402: else 403: { 404: DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res); 405: } 406: } 407: } 408: 409: /** 410: * Get an iface entry for a local address, does no locking 411: */ 412: static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip) 413: { 414: enumerator_t *ifaces, *addrs; 415: iface_t *entry, *found = NULL; 416: host_t *host; 417: 418: ifaces = this->ifaces->create_enumerator(this->ifaces); 419: while (!found && ifaces->enumerate(ifaces, &entry)) 420: { 421: addrs = entry->addrs->create_enumerator(entry->addrs); 422: while (!found && addrs->enumerate(addrs, &host)) 423: { 424: if (host->ip_equals(host, ip)) 425: { 426: found = entry; 427: } 428: } 429: addrs->destroy(addrs); 430: } 431: ifaces->destroy(ifaces); 432: 433: return found; 434: } 435: 436: METHOD(kernel_net_t, get_interface_name, bool, 437: private_kernel_iph_net_t *this, host_t* ip, char **name) 438: { 439: iface_t *entry; 440: 441: this->mutex->lock(this->mutex); 442: entry = address2entry(this, ip); 443: if (entry && name) 444: { 445: *name = strdup(entry->ifname); 446: } 447: this->mutex->unlock(this->mutex); 448: 449: return entry != NULL; 450: } 451: 452: /** 453: * Address enumerator 454: */ 455: typedef struct { 456: /** implements enumerator_t */ 457: enumerator_t public; 458: /** what kind of address should we enumerate? */ 459: kernel_address_type_t which; 460: /** enumerator over interfaces */ 461: enumerator_t *ifaces; 462: /** current enumerator over addresses, or NULL */ 463: enumerator_t *addrs; 464: /** mutex to unlock on destruction */ 465: mutex_t *mutex; 466: } addr_enumerator_t; 467: 468: METHOD(enumerator_t, addr_enumerate, bool, 469: addr_enumerator_t *this, va_list args) 470: { 471: iface_t *entry; 472: host_t **host; 473: 474: VA_ARGS_VGET(args, host); 475: 476: while (TRUE) 477: { 478: while (!this->addrs) 479: { 480: if (!this->ifaces->enumerate(this->ifaces, &entry)) 481: { 482: return FALSE; 483: } 484: if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK && 485: !(this->which & ADDR_TYPE_LOOPBACK)) 486: { 487: continue; 488: } 489: if (entry->status != IfOperStatusUp && 490: !(this->which & ADDR_TYPE_DOWN)) 491: { 492: continue; 493: } 494: this->addrs = entry->addrs->create_enumerator(entry->addrs); 495: } 496: if (this->addrs->enumerate(this->addrs, host)) 497: { 498: return TRUE; 499: } 500: this->addrs->destroy(this->addrs); 501: this->addrs = NULL; 502: } 503: } 504: 505: METHOD(enumerator_t, addr_destroy, void, 506: addr_enumerator_t *this) 507: { 508: DESTROY_IF(this->addrs); 509: this->ifaces->destroy(this->ifaces); 510: this->mutex->unlock(this->mutex); 511: free(this); 512: } 513: 514: METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, 515: private_kernel_iph_net_t *this, kernel_address_type_t which) 516: { 517: addr_enumerator_t *enumerator; 518: 519: if (!(which & ADDR_TYPE_REGULAR)) 520: { 521: /* we currently have no virtual, but regular IPs only */ 522: return enumerator_create_empty(); 523: } 524: 525: this->mutex->lock(this->mutex); 526: 527: INIT(enumerator, 528: .public = { 529: .enumerate = enumerator_enumerate_default, 530: .venumerate = _addr_enumerate, 531: .destroy = _addr_destroy, 532: }, 533: .which = which, 534: .ifaces = this->ifaces->create_enumerator(this->ifaces), 535: .mutex = this->mutex, 536: ); 537: return &enumerator->public; 538: } 539: 540: METHOD(kernel_net_t, get_source_addr, host_t*, 541: private_kernel_iph_net_t *this, host_t *dest, host_t *src) 542: { 543: MIB_IPFORWARD_ROW2 route; 544: SOCKADDR_INET best, *sai_dst, *sai_src = NULL; 545: DWORD res, index = 0; 546: 547: res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index); 548: if (res != NO_ERROR) 549: { 550: DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res); 551: return NULL; 552: } 553: 554: sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest); 555: if (src) 556: { 557: sai_src = (SOCKADDR_INET*)src->get_sockaddr(src); 558: } 559: res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best); 560: if (res != NO_ERROR) 561: { 562: DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res); 563: return NULL; 564: } 565: return host_create_from_sockaddr((struct sockaddr*)&best); 566: } 567: 568: METHOD(kernel_net_t, get_nexthop, host_t*, 569: private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src, 570: char **iface) 571: { 572: MIB_IPFORWARD_ROW2 route; 573: SOCKADDR_INET best, *sai_dst, *sai_src = NULL; 574: DWORD res, index = 0; 575: host_t *nexthop; 576: 577: res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index); 578: if (res != NO_ERROR) 579: { 580: DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res); 581: return NULL; 582: } 583: 584: sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest); 585: if (src) 586: { 587: sai_src = (SOCKADDR_INET*)src->get_sockaddr(src); 588: } 589: res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best); 590: if (res != NO_ERROR) 591: { 592: DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res); 593: return NULL; 594: } 595: nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop); 596: if (nexthop) 597: { 598: if (!nexthop->is_anyaddr(nexthop)) 599: { 600: if (iface) 601: { 602: *iface = NULL; 603: } 604: return nexthop; 605: } 606: nexthop->destroy(nexthop); 607: } 608: return NULL; 609: } 610: 611: METHOD(kernel_net_t, add_ip, status_t, 612: private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix, 613: char *iface_name) 614: { 615: return NOT_SUPPORTED; 616: } 617: 618: METHOD(kernel_net_t, del_ip, status_t, 619: private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix, 620: bool wait) 621: { 622: return NOT_SUPPORTED; 623: } 624: 625: /** 626: * Add or remove a route 627: */ 628: static status_t manage_route(private_kernel_iph_net_t *this, bool add, 629: chunk_t dst, uint8_t prefixlen, host_t *gtw, char *name) 630: { 631: MIB_IPFORWARD_ROW2 row = { 632: .DestinationPrefix = { 633: .PrefixLength = prefixlen, 634: }, 635: .SitePrefixLength = prefixlen, 636: .ValidLifetime = INFINITE, 637: .PreferredLifetime = INFINITE, 638: .Metric = 10, 639: .Protocol = MIB_IPPROTO_NETMGMT, 640: }; 641: enumerator_t *enumerator; 642: iface_t *entry; 643: ULONG ret; 644: 645: this->mutex->lock(this->mutex); 646: enumerator = this->ifaces->create_enumerator(this->ifaces); 647: while (enumerator->enumerate(enumerator, &entry)) 648: { 649: if (streq(name, entry->ifname)) 650: { 651: row.InterfaceIndex = entry->ifindex; 652: break; 653: } 654: } 655: enumerator->destroy(enumerator); 656: this->mutex->unlock(this->mutex); 657: 658: if (!row.InterfaceIndex) 659: { 660: return NOT_FOUND; 661: } 662: switch (dst.len) 663: { 664: case 4: 665: row.DestinationPrefix.Prefix.si_family = AF_INET; 666: memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr, 667: dst.ptr, dst.len); 668: break; 669: case 16: 670: row.DestinationPrefix.Prefix.si_family = AF_INET6; 671: memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr, 672: dst.ptr, dst.len); 673: break; 674: default: 675: return FAILED; 676: } 677: if (gtw) 678: { 679: memcpy(&row.NextHop, gtw->get_sockaddr(gtw), 680: *gtw->get_sockaddr_len(gtw)); 681: } 682: 683: if (add) 684: { 685: ret = CreateIpForwardEntry2(&row); 686: } 687: else 688: { 689: ret = DeleteIpForwardEntry2(&row); 690: } 691: if (ret != NO_ERROR) 692: { 693: DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret); 694: return FAILED; 695: } 696: 697: if (add) 698: { 699: ret = EnableRouter(NULL, &this->router); 700: if (ret != ERROR_IO_PENDING) 701: { 702: DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret); 703: } 704: } 705: else 706: { 707: ret = UnenableRouter(&this->router, NULL); 708: if (ret != NO_ERROR) 709: { 710: DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret); 711: } 712: } 713: return SUCCESS; 714: } 715: 716: METHOD(kernel_net_t, add_route, status_t, 717: private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen, 718: host_t *gateway, host_t *src, char *name, bool pass) 719: { 720: return manage_route(this, TRUE, dst, prefixlen, gateway, name); 721: } 722: 723: METHOD(kernel_net_t, del_route, status_t, 724: private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen, 725: host_t *gateway, host_t *src, char *name, bool pass) 726: { 727: return manage_route(this, FALSE, dst, prefixlen, gateway, name); 728: } 729: 730: METHOD(kernel_net_t, destroy, void, 731: private_kernel_iph_net_t *this) 732: { 733: if (this->changes) 734: { 735: CancelMibChangeNotify2(this->changes); 736: } 737: CloseHandle(this->router.hEvent); 738: this->mutex->destroy(this->mutex); 739: this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy); 740: free(this); 741: } 742: 743: /* 744: * Described in header. 745: */ 746: kernel_iph_net_t *kernel_iph_net_create() 747: { 748: private_kernel_iph_net_t *this; 749: ULONG res; 750: 751: INIT(this, 752: .public = { 753: .interface = { 754: .get_interface = _get_interface_name, 755: .create_address_enumerator = _create_address_enumerator, 756: .get_source_addr = _get_source_addr, 757: .get_nexthop = _get_nexthop, 758: .add_ip = _add_ip, 759: .del_ip = _del_ip, 760: .add_route = _add_route, 761: .del_route = _del_route, 762: .destroy = _destroy, 763: }, 764: }, 765: .router = { 766: .hEvent = CreateEvent(NULL, FALSE, FALSE, NULL), 767: }, 768: .mutex = mutex_create(MUTEX_TYPE_DEFAULT), 769: .ifaces = linked_list_create(), 770: ); 771: /* PIPINTERFACE_CHANGE_CALLBACK is not using WINAPI in MinGW, which seems 772: * to be wrong. Force a cast to our WINAPI call */ 773: res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface, 774: this, TRUE, &this->changes); 775: if (res != NO_ERROR) 776: { 777: DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx", 778: res); 779: destroy(this); 780: return NULL; 781: } 782: 783: return &this->public; 784: }