this repo has no description
at fixPythonPipStalling 986 lines 27 kB view raw
1/* 2 * Copyright (c) 2013-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * IPMonitorControlServer.c 26 * - IPC channel to IPMonitor 27 * - used to create interface rank assertions 28 */ 29 30/* 31 * Modification History 32 * 33 * December 16, 2013 Dieter Siegmund (dieter@apple.com) 34 * - initial revision 35 */ 36 37#include <CoreFoundation/CoreFoundation.h> 38#include <xpc/xpc.h> 39#include <xpc/private.h> 40#include <sys/queue.h> 41#include <CoreFoundation/CFRunLoop.h> 42#include <SystemConfiguration/SCNetworkConfigurationPrivate.h> 43#include <SystemConfiguration/SCPrivate.h> 44#include "IPMonitorControlServer.h" 45#include "symbol_scope.h" 46#include "IPMonitorControlPrivate.h" 47#include "IPMonitorAWDReport.h" 48 49#ifdef TEST_IPMONITOR_CONTROL 50#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__) 51 52#else /* TEST_IPMONITOR_CONTROL */ 53#include "ip_plugin.h" 54#endif /* TEST_IPMONITOR_CONTROL */ 55 56STATIC dispatch_queue_t S_IPMonitorControlServerQueue; 57 58typedef struct ControlSession ControlSession, * ControlSessionRef; 59 60#define LIST_HEAD_ControlSession LIST_HEAD(ControlSessionHead, ControlSession) 61#define LIST_ENTRY_ControlSession LIST_ENTRY(ControlSession) 62LIST_HEAD_ControlSession S_ControlSessions; 63 64struct ControlSession { 65 LIST_ENTRY_ControlSession link; 66 xpc_connection_t connection; 67 68 CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */ 69 CFMutableDictionaryRef advisories; /* ifname<string> = advisory<number> */ 70}; 71 72/** 73 ** Support Functions 74 **/ 75STATIC CFMutableArrayRef S_if_changes; 76STATIC CFRange S_if_changes_range; 77 78STATIC CFNumberRef 79RankLastNumberGet(void) 80{ 81 STATIC CFNumberRef rank_last; 82 83 if (rank_last == NULL) { 84 SCNetworkServicePrimaryRank rank; 85 86 rank = kSCNetworkServicePrimaryRankLast; 87 rank_last = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); 88 } 89 return (rank_last); 90} 91 92STATIC void 93InterfaceChangedListAddInterface(CFStringRef ifname) 94{ 95 if (S_if_changes == NULL) { 96 S_if_changes = CFArrayCreateMutable(NULL, 97 0, &kCFTypeArrayCallBacks); 98 CFArrayAppendValue(S_if_changes, ifname); 99 S_if_changes_range.length = 1; 100 } 101 else if (!CFArrayContainsValue(S_if_changes, S_if_changes_range, ifname)) { 102 CFArrayAppendValue(S_if_changes, ifname); 103 S_if_changes_range.length++; 104 } 105} 106 107STATIC CFArrayRef 108InterfaceChangedListCopy(void) 109{ 110 CFArrayRef current_list; 111 112 current_list = S_if_changes; 113 S_if_changes = NULL; 114 return (current_list); 115} 116 117STATIC void 118InterfaceRankAssertionAdd(const void * key, const void * value, void * context) 119{ 120 CFMutableDictionaryRef * assertions_p; 121 CFNumberRef existing_rank; 122 CFNumberRef rank = (CFNumberRef)value; 123 124 assertions_p = (CFMutableDictionaryRef *)context; 125 if (*assertions_p == NULL) { 126 *assertions_p 127 = CFDictionaryCreateMutable(NULL, 0, 128 &kCFTypeDictionaryKeyCallBacks, 129 &kCFTypeDictionaryValueCallBacks); 130 CFDictionarySetValue(*assertions_p, key, rank); 131 return; 132 } 133 existing_rank = CFDictionaryGetValue(*assertions_p, key); 134 if (existing_rank == NULL 135 || (CFNumberCompare(rank, existing_rank, NULL) 136 == kCFCompareGreaterThan)) { 137 CFDictionarySetValue(*assertions_p, key, rank); 138 } 139 return; 140} 141 142STATIC void 143InterfaceAdvisoryAdd(const void * key, const void * value, void * context) 144{ 145#pragma unused(value) 146 CFMutableDictionaryRef * assertions_p; 147 CFNumberRef existing_rank; 148 CFNumberRef rank; 149 150 /* an interface advisory implies RankLast */ 151 rank = RankLastNumberGet(); 152 assertions_p = (CFMutableDictionaryRef *)context; 153 if (*assertions_p == NULL) { 154 *assertions_p 155 = CFDictionaryCreateMutable(NULL, 0, 156 &kCFTypeDictionaryKeyCallBacks, 157 &kCFTypeDictionaryValueCallBacks); 158 CFDictionarySetValue(*assertions_p, key, rank); 159 return; 160 } 161 existing_rank = CFDictionaryGetValue(*assertions_p, key); 162 if (existing_rank == NULL 163 || (CFNumberCompare(rank, existing_rank, NULL) 164 == kCFCompareGreaterThan)) { 165 CFDictionarySetValue(*assertions_p, key, rank); 166 } 167 return; 168} 169 170STATIC CFDictionaryRef 171InterfaceRankAssertionsCopy(void) 172{ 173 CFMutableDictionaryRef assertions = NULL; 174 ControlSessionRef session; 175 176 LIST_FOREACH(session, &S_ControlSessions, link) { 177 if (session->advisories != NULL) { 178 CFDictionaryApplyFunction(session->advisories, 179 InterfaceAdvisoryAdd, 180 &assertions); 181 } 182 if (session->assertions != NULL) { 183 CFDictionaryApplyFunction(session->assertions, 184 InterfaceRankAssertionAdd, 185 &assertions); 186 } 187 } 188 return (assertions); 189} 190 191STATIC Boolean 192InterfaceHasAdvisories(CFStringRef ifname) 193{ 194 ControlSessionRef session; 195 196 LIST_FOREACH(session, &S_ControlSessions, link) { 197 if (session->advisories != NULL 198 && CFDictionaryContainsKey(session->advisories, ifname)) { 199 return (TRUE); 200 } 201 } 202 return (FALSE); 203} 204 205 206STATIC AWDIPMonitorInterfaceAdvisoryReport_Flags 207advisory_to_flags(SCNetworkInterfaceAdvisory advisory) 208{ 209 AWDIPMonitorInterfaceAdvisoryReport_Flags flags; 210 211 switch (advisory) { 212 case kSCNetworkInterfaceAdvisoryNone: 213 default: 214 flags = 0; 215 break; 216 case kSCNetworkInterfaceAdvisoryLinkLayerIssue: 217 flags = AWDIPMonitorInterfaceAdvisoryReport_Flags_LINK_LAYER_ISSUE; 218 break; 219 case kSCNetworkInterfaceAdvisoryUplinkIssue: 220 flags = AWDIPMonitorInterfaceAdvisoryReport_Flags_UPLINK_ISSUE; 221 break; 222 } 223 return (flags); 224} 225 226STATIC AWDIPMonitorInterfaceAdvisoryReport_Flags 227InterfaceGetAdvisoryFlags(CFStringRef ifname, 228 ControlSessionRef exclude_session, 229 uint32_t * ret_count) 230{ 231 uint32_t count; 232 AWDIPMonitorInterfaceAdvisoryReport_Flags flags = 0; 233 ControlSessionRef session; 234 235 count = 0; 236 LIST_FOREACH(session, &S_ControlSessions, link) { 237 SCNetworkInterfaceAdvisory advisory = 0; 238 CFNumberRef advisory_cf; 239 240 if (session->advisories == NULL) { 241 continue; 242 } 243 if (exclude_session != NULL && exclude_session == session) { 244 continue; 245 } 246 advisory_cf = CFDictionaryGetValue(session->advisories, ifname); 247 if (advisory_cf == NULL) { 248 /* session has no advisories for this interface */ 249 continue; 250 } 251 (void)CFNumberGetValue(advisory_cf, kCFNumberSInt32Type, &advisory); 252 flags |= advisory_to_flags(advisory); 253 count++; 254 } 255 *ret_count = count; 256 return (flags); 257} 258 259STATIC Boolean 260AnyInterfaceHasAdvisories(void) 261{ 262 ControlSessionRef session; 263 264 LIST_FOREACH(session, &S_ControlSessions, link) { 265 if (session->advisories != NULL) { 266 return (TRUE); 267 } 268 } 269 return (FALSE); 270} 271 272STATIC CFRunLoopRef S_runloop; 273STATIC CFRunLoopSourceRef S_signal_source; 274 275STATIC void 276SetNotificationInfo(CFRunLoopRef runloop, CFRunLoopSourceRef rls) 277{ 278 S_runloop = runloop; 279 S_signal_source = rls; 280 return; 281} 282 283STATIC void 284NotifyIPMonitor(void) 285{ 286 if (S_signal_source != NULL) { 287 CFRunLoopSourceSignal(S_signal_source); 288 if (S_runloop != NULL) { 289 CFRunLoopWakeUp(S_runloop); 290 } 291 } 292 return; 293} 294 295STATIC void 296NotifyInterfaceAdvisory(CFStringRef ifname) 297{ 298 CFStringRef key; 299 300 key = _IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname); 301 SCDynamicStoreNotifyValue(NULL, key); 302 CFRelease(key); 303 return; 304} 305 306STATIC void 307SubmitInterfaceAdvisoryMetric(CFStringRef ifname, 308 AWDIPMonitorInterfaceAdvisoryReport_Flags flags, 309 uint32_t count) 310{ 311 InterfaceAdvisoryReportRef report; 312 AWDIPMonitorInterfaceType type; 313 314 /* XXX need to actually figure out what the interface type is */ 315 if (CFStringHasPrefix(ifname, CFSTR("pdp"))) { 316 type = AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_CELLULAR; 317 } 318 else { 319 type = AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_WIFI; 320 } 321 report = InterfaceAdvisoryReportCreate(type); 322 if (report == NULL) { 323 return; 324 } 325 InterfaceAdvisoryReportSetFlags(report, flags); 326 InterfaceAdvisoryReportSetAdvisoryCount(report, count); 327 InterfaceAdvisoryReportSubmit(report); 328 my_log(LOG_NOTICE, "%@: submitted AWD report %@", ifname, report); 329 CFRelease(report); 330} 331 332/** 333 ** ControlSession 334 **/ 335STATIC void 336AddChangedInterface(const void * key, const void * value, void * context) 337{ 338#pragma unused(value) 339#pragma unused(context) 340 InterfaceChangedListAddInterface((CFStringRef)key); 341 return; 342} 343 344STATIC void 345AddChangedInterfaceNotify(const void * key, const void * value, void * context) 346{ 347#pragma unused(value) 348#pragma unused(context) 349 InterfaceChangedListAddInterface((CFStringRef)key); 350 NotifyInterfaceAdvisory((CFStringRef)key); 351 return; 352} 353 354STATIC void 355GenerateMetricForInterfaceAtSessionClose(const void * key, const void * value, 356 void * context) 357{ 358 uint32_t count_after; 359 uint32_t count_before; 360 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after; 361 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before; 362 CFStringRef ifname = (CFStringRef)key; 363 ControlSessionRef session = (ControlSessionRef)context; 364 365#pragma unused(value) 366 /* 367 * Get the flags and count including this session, then again 368 * excluding this session. If either flags or count are different, 369 * generate the metric. 370 */ 371 flags_before = InterfaceGetAdvisoryFlags(ifname, NULL, &count_before); 372 flags_after = InterfaceGetAdvisoryFlags(ifname, session, &count_after); 373 if (flags_before != flags_after || count_before != count_after) { 374 SubmitInterfaceAdvisoryMetric(ifname, flags_after, count_after); 375 } 376 return; 377} 378 379STATIC void 380ControlSessionGenerateMetricsAtClose(ControlSessionRef session) 381{ 382 if (session->advisories == NULL) { 383 return; 384 } 385 CFDictionaryApplyFunction(session->advisories, 386 GenerateMetricForInterfaceAtSessionClose, 387 session); 388} 389 390STATIC void 391ControlSessionInvalidate(ControlSessionRef session) 392{ 393 my_log(LOG_DEBUG, "Invalidating %p", session); 394 ControlSessionGenerateMetricsAtClose(session); 395 LIST_REMOVE(session, link); 396 if (session->assertions != NULL || session->advisories != NULL) { 397 if (session->advisories != NULL) { 398 my_log(LOG_NOTICE, 399 "pid %d removing advisories %@", 400 xpc_connection_get_pid(session->connection), 401 session->advisories); 402 CFDictionaryApplyFunction(session->advisories, 403 AddChangedInterfaceNotify, 404 NULL); 405 my_CFRelease(&session->advisories); 406 } 407 if (session->assertions != NULL) { 408 my_log(LOG_NOTICE, 409 "pid %d removing assertions %@", 410 xpc_connection_get_pid(session->connection), 411 session->assertions); 412 CFDictionaryApplyFunction(session->assertions, AddChangedInterface, 413 NULL); 414 my_CFRelease(&session->assertions); 415 } 416 NotifyIPMonitor(); 417 } 418 return; 419} 420 421STATIC void 422ControlSessionRelease(void * p) 423{ 424 my_log(LOG_DEBUG, "Releasing %p", p); 425 free(p); 426 return; 427} 428 429STATIC ControlSessionRef 430ControlSessionLookup(xpc_connection_t connection) 431{ 432 return ((ControlSessionRef)xpc_connection_get_context(connection)); 433} 434 435STATIC ControlSessionRef 436ControlSessionCreate(xpc_connection_t connection) 437{ 438 ControlSessionRef session; 439 440 session = (ControlSessionRef)malloc(sizeof(*session)); 441 memset(session, 0, sizeof(*session)); 442 session->connection = connection; 443 xpc_connection_set_finalizer_f(connection, ControlSessionRelease); 444 xpc_connection_set_context(connection, session); 445 LIST_INSERT_HEAD(&S_ControlSessions, session, link); 446 my_log(LOG_DEBUG, "Created %p (connection %p)", session, connection); 447 return (session); 448} 449 450STATIC ControlSessionRef 451ControlSessionForConnection(xpc_connection_t connection) 452{ 453 ControlSessionRef session; 454 455 session = ControlSessionLookup(connection); 456 if (session != NULL) { 457 return (session); 458 } 459 return (ControlSessionCreate(connection)); 460} 461 462STATIC void 463ControlSessionSetInterfaceRank(ControlSessionRef session, 464 const char * ifname, 465 SCNetworkServicePrimaryRank rank) 466{ 467 CFStringRef ifname_cf; 468 469 if (session->assertions == NULL) { 470 if (rank == kSCNetworkServicePrimaryRankDefault) { 471 /* no assertions, no need to store rank */ 472 return; 473 } 474 session->assertions 475 = CFDictionaryCreateMutable(NULL, 0, 476 &kCFTypeDictionaryKeyCallBacks, 477 &kCFTypeDictionaryValueCallBacks); 478 } 479 ifname_cf = CFStringCreateWithCString(NULL, ifname, 480 kCFStringEncodingUTF8); 481 482 if (rank == kSCNetworkServicePrimaryRankDefault) { 483 CFDictionaryRemoveValue(session->assertions, ifname_cf); 484 if (CFDictionaryGetCount(session->assertions) == 0) { 485 CFRelease(session->assertions); 486 session->assertions = NULL; 487 } 488 } 489 else { 490 CFNumberRef rank_cf; 491 492 rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); 493 CFDictionarySetValue(session->assertions, ifname_cf, rank_cf); 494 CFRelease(rank_cf); 495 } 496 InterfaceChangedListAddInterface(ifname_cf); 497 NotifyIPMonitor(); 498 CFRelease(ifname_cf); 499 return; 500} 501 502STATIC SCNetworkServicePrimaryRank 503ControlSessionGetInterfaceRank(ControlSessionRef session, 504 const char * ifname) 505{ 506 SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; 507 508 if (session->assertions != NULL) { 509 CFStringRef ifname_cf; 510 CFNumberRef rank_cf; 511 512 ifname_cf = CFStringCreateWithCString(NULL, ifname, 513 kCFStringEncodingUTF8); 514 rank_cf = CFDictionaryGetValue(session->assertions, ifname_cf); 515 CFRelease(ifname_cf); 516 if (rank_cf != NULL) { 517 (void)CFNumberGetValue(rank_cf, kCFNumberSInt32Type, &rank); 518 } 519 } 520 return (rank); 521} 522 523STATIC void 524ControlSessionSetInterfaceAdvisory(ControlSessionRef session, 525 const char * ifname, 526 SCNetworkInterfaceAdvisory advisory) 527{ 528 uint32_t count_after; 529 uint32_t count_before; 530 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after; 531 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before; 532 CFStringRef ifname_cf; 533 534 if (session->advisories == NULL) { 535 if (advisory == kSCNetworkInterfaceAdvisoryNone) { 536 /* no advisories, no need to store advisory */ 537 return; 538 } 539 session->advisories 540 = CFDictionaryCreateMutable(NULL, 0, 541 &kCFTypeDictionaryKeyCallBacks, 542 &kCFTypeDictionaryValueCallBacks); 543 } 544 ifname_cf = CFStringCreateWithCString(NULL, ifname, 545 kCFStringEncodingUTF8); 546 flags_before = InterfaceGetAdvisoryFlags(ifname_cf, NULL, &count_before); 547 if (advisory == kSCNetworkInterfaceAdvisoryNone) { 548 CFDictionaryRemoveValue(session->advisories, ifname_cf); 549 if (CFDictionaryGetCount(session->advisories) == 0) { 550 CFRelease(session->advisories); 551 session->advisories = NULL; 552 } 553 } 554 else { 555 CFNumberRef advisory_cf; 556 557 advisory_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &advisory); 558 CFDictionarySetValue(session->advisories, ifname_cf, advisory_cf); 559 CFRelease(advisory_cf); 560 } 561 flags_after = InterfaceGetAdvisoryFlags(ifname_cf, NULL, &count_after); 562 if (flags_before != flags_after || count_before != count_after) { 563 SubmitInterfaceAdvisoryMetric(ifname_cf, flags_after, count_after); 564 } 565 InterfaceChangedListAddInterface(ifname_cf); 566 NotifyInterfaceAdvisory(ifname_cf); 567 NotifyIPMonitor(); 568 CFRelease(ifname_cf); 569 return; 570} 571 572/** 573 ** IPMonitorControlServer 574 **/ 575 576STATIC const char * 577get_process_name(xpc_object_t request) 578{ 579 const char * process_name; 580 581 process_name 582 = xpc_dictionary_get_string(request, 583 kIPMonitorControlRequestKeyProcessName); 584 if (process_name == NULL) { 585 process_name = "<unknown>"; 586 } 587 return (process_name); 588} 589 590STATIC Boolean 591IPMonitorControlServerConnectionIsRoot(xpc_connection_t connection) 592{ 593 uid_t uid; 594 595 uid = xpc_connection_get_euid(connection); 596 return (uid == 0); 597} 598 599STATIC Boolean 600IPMonitorControlServerConnectionHasEntitlement(xpc_connection_t connection, 601 const char * entitlement) 602{ 603 Boolean entitled = FALSE; 604 xpc_object_t val; 605 606 val = xpc_connection_copy_entitlement_value(connection, entitlement); 607 if (val != NULL) { 608 if (xpc_get_type(val) == XPC_TYPE_BOOL) { 609 entitled = xpc_bool_get_value(val); 610 } 611 xpc_release(val); 612 } 613 return (entitled); 614} 615 616STATIC const char * 617get_rank_str(SCNetworkServicePrimaryRank rank) 618{ 619 const char * str = NULL; 620 621 switch (rank) { 622 case kSCNetworkServicePrimaryRankDefault: 623 str = "Default"; 624 break; 625 case kSCNetworkServicePrimaryRankFirst: 626 str = "First"; 627 break; 628 case kSCNetworkServicePrimaryRankLast: 629 str = "Last"; 630 break; 631 case kSCNetworkServicePrimaryRankNever: 632 str = "Never"; 633 break; 634 case kSCNetworkServicePrimaryRankScoped: 635 str = "Scoped"; 636 break; 637 default: 638 break; 639 } 640 return (str); 641} 642 643STATIC int 644HandleSetInterfaceRank(xpc_connection_t connection, 645 xpc_object_t request, 646 xpc_object_t reply) 647{ 648#pragma unused(reply) 649 const char * ifname; 650 SCNetworkServicePrimaryRank rank; 651 const char * rank_str; 652 ControlSessionRef session; 653 654 if (!IPMonitorControlServerConnectionIsRoot(connection)) { 655 my_log(LOG_INFO, "connection %p pid %d permission denied", 656 connection, xpc_connection_get_pid(connection)); 657 return (EPERM); 658 } 659 ifname 660 = xpc_dictionary_get_string(request, 661 kIPMonitorControlRequestKeyInterfaceName); 662 if (ifname == NULL) { 663 return (EINVAL); 664 } 665 rank = (SCNetworkServicePrimaryRank) 666 xpc_dictionary_get_uint64(request, 667 kIPMonitorControlRequestKeyPrimaryRank); 668 rank_str = get_rank_str(rank); 669 if (rank_str == NULL) { 670 return (EINVAL); 671 } 672 session = ControlSessionForConnection(connection); 673 ControlSessionSetInterfaceRank(session, ifname, rank); 674 my_log(LOG_NOTICE, "%s[%d] SetInterfaceRank(%s) = %s (%u)", 675 get_process_name(request), 676 xpc_connection_get_pid(connection), ifname, rank_str, rank); 677 return (0); 678} 679 680STATIC int 681HandleGetInterfaceRank(xpc_connection_t connection, 682 xpc_object_t request, 683 xpc_object_t reply) 684{ 685 const char * ifname; 686 SCNetworkServicePrimaryRank rank; 687 ControlSessionRef session; 688 689 if (reply == NULL) { 690 /* no point in processing the request if we can't provide an answer */ 691 return (EINVAL); 692 } 693 session = ControlSessionLookup(connection); 694 if (session == NULL) { 695 /* no session, no rank assertion */ 696 return (ENOENT); 697 } 698 ifname 699 = xpc_dictionary_get_string(request, 700 kIPMonitorControlRequestKeyInterfaceName); 701 if (ifname == NULL) { 702 return (EINVAL); 703 } 704 rank = ControlSessionGetInterfaceRank(session, ifname); 705 xpc_dictionary_set_uint64(reply, kIPMonitorControlResponseKeyPrimaryRank, 706 rank); 707 return (0); 708} 709 710STATIC const char * 711get_advisory_str(SCNetworkInterfaceAdvisory advisory) 712{ 713 const char * str = NULL; 714 715 switch (advisory) { 716 case kSCNetworkInterfaceAdvisoryNone: 717 str = "None"; 718 break; 719 case kSCNetworkInterfaceAdvisoryLinkLayerIssue: 720 str = "LinkLayerIssue"; 721 break; 722 case kSCNetworkInterfaceAdvisoryUplinkIssue: 723 str = "UplinkIssue"; 724 break; 725 default: 726 break; 727 } 728 return (str); 729} 730 731STATIC int 732HandleSetInterfaceAdvisory(xpc_connection_t connection, 733 xpc_object_t request, 734 xpc_object_t reply) 735{ 736#pragma unused(reply) 737 SCNetworkInterfaceAdvisory advisory; 738 const char * advisory_str; 739 const char * ifname; 740 const char * reason; 741 ControlSessionRef session; 742 743#define ENTITLEMENT "com.apple.SystemConfiguration.SCNetworkInterfaceSetAdvisory" 744 if (!IPMonitorControlServerConnectionIsRoot(connection) 745 && !IPMonitorControlServerConnectionHasEntitlement(connection, 746 ENTITLEMENT)) { 747 my_log(LOG_INFO, "connection %p pid %d permission denied", 748 connection, xpc_connection_get_pid(connection)); 749 return (EPERM); 750 } 751 ifname 752 = xpc_dictionary_get_string(request, 753 kIPMonitorControlRequestKeyInterfaceName); 754 if (ifname == NULL) { 755 return (EINVAL); 756 } 757 reason 758 = xpc_dictionary_get_string(request, 759 kIPMonitorControlRequestKeyReason); 760 advisory = (SCNetworkInterfaceAdvisory) 761 xpc_dictionary_get_uint64(request, kIPMonitorControlRequestKeyAdvisory); 762 763 /* validate the advisory code */ 764 advisory_str = get_advisory_str(advisory); 765 if (advisory_str == NULL) { 766 return (EINVAL); 767 } 768 session = ControlSessionForConnection(connection); 769 ControlSessionSetInterfaceAdvisory(session, ifname, advisory); 770 my_log(LOG_NOTICE, "%s[%d] SetInterfaceAdvisory(%s) = %s (%u) reason='%s'", 771 get_process_name(request), 772 xpc_connection_get_pid(connection), ifname, advisory_str, advisory, 773 reason != NULL ? reason : "" ); 774 return (0); 775} 776 777STATIC int 778HandleInterfaceAdvisoryIsSet(xpc_connection_t connection, 779 xpc_object_t request, 780 xpc_object_t reply) 781{ 782#pragma unused(connection) 783 const char * ifname; 784 CFStringRef ifname_cf; 785 786 if (reply == NULL) { 787 /* no point in processing the request if we can't provide an answer */ 788 return (EINVAL); 789 } 790 ifname 791 = xpc_dictionary_get_string(request, 792 kIPMonitorControlRequestKeyInterfaceName); 793 if (ifname == NULL) { 794 return (EINVAL); 795 } 796 ifname_cf = CFStringCreateWithCString(NULL, ifname, 797 kCFStringEncodingUTF8); 798 xpc_dictionary_set_bool(reply, 799 kIPMonitorControlResponseKeyAdvisoryIsSet, 800 InterfaceHasAdvisories(ifname_cf)); 801 CFRelease(ifname_cf); 802 return (0); 803} 804 805STATIC int 806HandleAnyInterfaceAdvisoryIsSet(xpc_connection_t connection, 807 xpc_object_t request, 808 xpc_object_t reply) 809{ 810#pragma unused(connection) 811#pragma unused(request) 812 if (reply == NULL) { 813 /* no point in processing the request if we can't provide an answer */ 814 return (EINVAL); 815 } 816 xpc_dictionary_set_bool(reply, 817 kIPMonitorControlResponseKeyAdvisoryIsSet, 818 AnyInterfaceHasAdvisories()); 819 return (0); 820} 821 822STATIC void 823IPMonitorControlServerHandleDisconnect(xpc_connection_t connection) 824{ 825 ControlSessionRef session; 826 827 my_log(LOG_DEBUG, "IPMonitorControlServer: client %p went away", 828 connection); 829 session = ControlSessionLookup(connection); 830 if (session == NULL) { 831 /* never asserted anything */ 832 return; 833 } 834 ControlSessionInvalidate(session); 835 return; 836} 837 838STATIC void 839IPMonitorControlServerHandleRequest(xpc_connection_t connection, 840 xpc_object_t request) 841{ 842 xpc_type_t type; 843 844 type = xpc_get_type(request); 845 if (type == XPC_TYPE_DICTIONARY) { 846 int error = 0; 847 uint64_t request_type; 848 xpc_connection_t remote; 849 xpc_object_t reply; 850 851 request_type 852 = xpc_dictionary_get_uint64(request, 853 kIPMonitorControlRequestKeyType); 854 reply = xpc_dictionary_create_reply(request); 855 switch (request_type) { 856 case kIPMonitorControlRequestTypeSetInterfaceRank: 857 error = HandleSetInterfaceRank(connection, request, reply); 858 break; 859 case kIPMonitorControlRequestTypeGetInterfaceRank: 860 error = HandleGetInterfaceRank(connection, request, reply); 861 break; 862 case kIPMonitorControlRequestTypeSetInterfaceAdvisory: 863 error = HandleSetInterfaceAdvisory(connection, request, reply); 864 break; 865 case kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet: 866 error = HandleInterfaceAdvisoryIsSet(connection, request, reply); 867 break; 868 case kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet: 869 error = HandleAnyInterfaceAdvisoryIsSet(connection, request, reply); 870 break; 871 default: 872 error = EINVAL; 873 break; 874 } 875 if (reply == NULL) { 876 /* client didn't want a reply */ 877 return; 878 } 879 xpc_dictionary_set_int64(reply, kIPMonitorControlResponseKeyError, 880 error); 881 remote = xpc_dictionary_get_remote_connection(request); 882 xpc_connection_send_message(remote, reply); 883 xpc_release(reply); 884 } 885 else if (type == XPC_TYPE_ERROR) { 886 if (request == XPC_ERROR_CONNECTION_INVALID) { 887 IPMonitorControlServerHandleDisconnect(connection); 888 } 889 else if (request == XPC_ERROR_CONNECTION_INTERRUPTED) { 890 my_log(LOG_INFO, "connection interrupted"); 891 } 892 } 893 else { 894 my_log(LOG_NOTICE, "unexpected event"); 895 } 896 return; 897} 898 899STATIC void 900IPMonitorControlServerHandleNewConnection(xpc_connection_t connection) 901{ 902 xpc_handler_t handler; 903 904 handler = ^(xpc_object_t event) { 905 IPMonitorControlServerHandleRequest(connection, event); 906 }; 907 xpc_connection_set_event_handler(connection, handler); 908 xpc_connection_set_target_queue(connection, S_IPMonitorControlServerQueue); 909 xpc_connection_resume(connection); 910 return; 911} 912 913STATIC xpc_connection_t 914IPMonitorControlServerCreate(dispatch_queue_t queue, const char * name) 915{ 916 uint64_t flags = XPC_CONNECTION_MACH_SERVICE_LISTENER; 917 xpc_connection_t connection; 918 xpc_handler_t handler; 919 920 connection = xpc_connection_create_mach_service(name, queue, flags); 921 if (connection == NULL) { 922 return (NULL); 923 } 924 handler = ^(xpc_object_t event) { 925 xpc_type_t type; 926 927 type = xpc_get_type(event); 928 if (type == XPC_TYPE_CONNECTION) { 929 IPMonitorControlServerHandleNewConnection(event); 930 } 931 else if (type == XPC_TYPE_ERROR) { 932 const char * desc; 933 934 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); 935 if (event == XPC_ERROR_CONNECTION_INVALID) { 936 my_log(LOG_NOTICE, "%s", desc); 937 xpc_release(connection); 938 } 939 else { 940 my_log(LOG_NOTICE, "%s", desc); 941 } 942 } 943 else { 944 my_log(LOG_NOTICE, "unknown event %p", type); 945 } 946 }; 947 S_IPMonitorControlServerQueue = queue; 948 xpc_connection_set_event_handler(connection, handler); 949 xpc_connection_resume(connection); 950 return (connection); 951} 952 953PRIVATE_EXTERN Boolean 954IPMonitorControlServerStart(CFRunLoopRef runloop, CFRunLoopSourceRef rls, 955 Boolean * verbose) 956{ 957#pragma unused(verbose) 958 dispatch_queue_t q; 959 xpc_connection_t connection; 960 961 SetNotificationInfo(runloop, rls); 962 q = dispatch_queue_create("IPMonitorControlServer", NULL); 963 connection = IPMonitorControlServerCreate(q, kIPMonitorControlServerName); 964 if (connection == NULL) { 965 my_log(LOG_ERR, 966 "IPMonitorControlServer: failed to create server"); 967 dispatch_release(q); 968 return (FALSE); 969 } 970 return (TRUE); 971} 972 973PRIVATE_EXTERN CFArrayRef 974IPMonitorControlServerCopyInterfaceRankInformation(CFDictionaryRef * info) 975{ 976 __block CFArrayRef changed; 977 __block CFDictionaryRef dict; 978 979 dispatch_sync(S_IPMonitorControlServerQueue, 980 ^{ 981 dict = InterfaceRankAssertionsCopy(); 982 changed = InterfaceChangedListCopy(); 983 }); 984 *info = dict; 985 return (changed); 986}