this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at fixPythonPipStalling 1122 lines 27 kB view raw
1/* 2 * Copyright (c) 2011-2019 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#include <pthread.h> 26#include <notify.h> 27#include <stdlib.h> 28#include <stdio.h> 29#include <sys/socket.h> 30#include <dispatch/dispatch.h> 31#include <os/log.h> 32#include <xpc/xpc.h> 33 34#include "libSystemConfiguration_client.h" 35#include "network_information.h" 36#include "network_state_information_priv.h" 37 38#if !TARGET_OS_SIMULATOR 39#include "network_config_agent_info_priv.h" 40#include "configAgentDefines.h" 41#endif // !TARGET_OS_SIMULATOR 42 43static nwi_state_t G_nwi_state = NULL; 44static pthread_mutex_t nwi_store_lock = PTHREAD_MUTEX_INITIALIZER; 45static boolean_t nwi_store_token_valid = FALSE; 46 47static pthread_once_t initialized = PTHREAD_ONCE_INIT; 48static int nwi_store_token; 49 50static boolean_t nwi_store_force_refresh = FALSE; 51static const char * client_proc_name = NULL; 52 53#pragma mark - 54#pragma mark Network information [nwi] client support 55 56 57// Note: protected by __nwi_client_queue() 58static int nwi_active = 0; 59static libSC_info_client_t *nwi_client = NULL; 60 61 62static dispatch_queue_t 63__nwi_client_queue() 64{ 65 static dispatch_once_t once; 66 static dispatch_queue_t q; 67 68 dispatch_once(&once, ^{ 69 q = dispatch_queue_create(NWI_SERVICE_NAME, NULL); 70 }); 71 72 return q; 73} 74 75static 76void 77_nwi_state_initialize(void) 78{ 79 const char *nwi_key = nwi_state_get_notify_key(); 80 uint32_t status = notify_register_check(nwi_key, 81 &nwi_store_token); 82 83 if (status != NOTIFY_STATUS_OK) { 84 fprintf(stderr, "nwi_state: registration failed (%u)\n", status); 85 } 86 else { 87 nwi_store_token_valid = TRUE; 88 } 89} 90 91#pragma mark - 92#pragma mark Network information [nwi] APIs 93 94 95/* 96 * Function: nwi_state_get_notify_key 97 * Purpose: 98 * Returns the BSD notify key to use to monitor when the state changes. 99 * 100 * Note: 101 * The nwi_state_copy API uses this notify key to monitor when the state 102 * changes, so each invocation of nwi_state_copy returns the current 103 * information. 104 */ 105const char * 106nwi_state_get_notify_key() 107{ 108 return "com.apple.system.SystemConfiguration.nwi"; 109} 110 111#define ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n)) 112#define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++); 113#define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n); 114 115void 116_nwi_state_force_refresh() 117{ 118 ATOMIC_CMPXCHG(&nwi_store_force_refresh, FALSE, TRUE); 119} 120 121static void 122nwi_state_retain(nwi_state_t state) 123{ 124 ATOMIC_INC(&state->ref); 125 return; 126} 127 128static void 129_nwi_client_release() 130{ 131 // release connection reference on 1-->0 transition 132 dispatch_sync(__nwi_client_queue(), ^{ 133 if (--nwi_active == 0) { 134 // if last reference, drop connection 135 libSC_info_client_release(nwi_client); 136 nwi_client = NULL; 137 } 138 }); 139} 140 141static void 142_nwi_client_init() 143{ 144 dispatch_sync(__nwi_client_queue(), ^{ 145 if ((nwi_active++ == 0) || (nwi_client == NULL)) { 146 static dispatch_once_t once; 147 static const char *service_name = NWI_SERVICE_NAME; 148 149 dispatch_once(&once, ^{ 150#if DEBUG 151 const char *name; 152 153 // get [XPC] service name 154 name = getenv(service_name); 155 if (name != NULL) { 156 service_name = strdup(name); 157 } 158#endif // DEBUG 159 160 // get process name 161 client_proc_name = getprogname(); 162 }); 163 164 nwi_client = 165 libSC_info_client_create(__nwi_client_queue(), // dispatch queue 166 service_name, // XPC service name 167 "Network information"); // service description 168 if (nwi_client == NULL) { 169 --nwi_active; 170 } 171 } 172 }); 173} 174 175/* 176 * Function: nwi_state_release 177 * Purpose: 178 * Release the memory associated with the network state. 179 */ 180void 181nwi_state_release(nwi_state_t state) 182{ 183 if (ATOMIC_DEC(&state->ref) > 0) { 184 // if not last reference 185 return; 186 } 187 188 _nwi_client_release(); 189 190 // release nwi_state 191 nwi_state_free(state); 192 193 return; 194} 195 196static nwi_state * 197_nwi_state_copy_data() 198{ 199 nwi_state_t nwi_state = NULL; 200 xpc_object_t reqdict; 201 xpc_object_t reply; 202 203 if (!libSC_info_available()) { 204 os_log(OS_LOG_DEFAULT, "*** network information requested between fork() and exec()"); 205 return NULL; 206 } 207 208 _nwi_client_init(); 209 210 if ((nwi_client == NULL) || !nwi_client->active) { 211 // if network information server not available 212 return NULL; 213 } 214 215 // create message 216 reqdict = xpc_dictionary_create(NULL, NULL, 0); 217 218 // set process name 219 if (client_proc_name != NULL) { 220 xpc_dictionary_set_string(reqdict, NWI_PROC_NAME, client_proc_name); 221 } 222 223 // set request 224 xpc_dictionary_set_int64(reqdict, NWI_REQUEST, NWI_STATE_REQUEST_COPY); 225 226 // send request to the DNS configuration server 227 reply = libSC_send_message_with_reply_sync(nwi_client, reqdict); 228 xpc_release(reqdict); 229 230 if (reply != NULL) { 231 const void *dataRef; 232 size_t dataLen = 0; 233 234 dataRef = xpc_dictionary_get_data(reply, NWI_CONFIGURATION, &dataLen); 235 if (dataRef != NULL) { 236 nwi_state = malloc(dataLen); 237 memcpy(nwi_state, (void *)dataRef, dataLen); 238 if (nwi_state->version != NWI_STATE_VERSION) { 239 /* make sure the version matches */ 240 nwi_state_free(nwi_state); 241 nwi_state = NULL; 242 } 243 else { 244 nwi_state->ref = 0; 245 } 246 } 247 248 xpc_release(reply); 249 } 250 251 return nwi_state; 252} 253 254#if !TARGET_OS_SIMULATOR 255/* 256 * Function: _nwi_config_agent_copy_data 257 * Purpose: 258 * Copy the config agent data and the data length. 259 * Caller must free the buffer. 260 */ 261const void * 262_nwi_config_agent_copy_data(const struct netagent *agent, uint64_t *length) 263{ 264 const void *buffer = NULL; 265 xpc_object_t reqdict; 266 xpc_object_t reply; 267 268 if ((agent == NULL) || (length == NULL)) { 269 return NULL; 270 } 271 272 _nwi_client_init(); 273 274 reqdict = xpc_dictionary_create(NULL, NULL, 0); 275 276 xpc_dictionary_set_int64(reqdict, NWI_REQUEST, NWI_CONFIG_AGENT_REQUEST_COPY); 277 if (client_proc_name != NULL) { 278 xpc_dictionary_set_string(reqdict, NWI_PROC_NAME, client_proc_name); 279 } 280 281 xpc_dictionary_set_uuid(reqdict, kConfigAgentAgentUUID, agent->netagent_uuid); 282 xpc_dictionary_set_string(reqdict, kConfigAgentType, agent->netagent_type); 283 284 // send request to the NWI configuration server 285 reply = libSC_send_message_with_reply_sync(nwi_client, reqdict); 286 xpc_release(reqdict); 287 288 if (reply != NULL) { 289 const void *xpc_buffer = NULL; 290 unsigned long len = 0; 291 292 xpc_buffer = xpc_dictionary_get_data(reply, kConfigAgentAgentData, &len); 293 if ((xpc_buffer != NULL) && (len > 0)) { 294 buffer = malloc(len); 295 *length = len; 296 memcpy((void *)buffer, (void *)xpc_buffer, len); 297 } 298 xpc_release(reply); 299 } 300 301 _nwi_client_release(); 302 303 return buffer; 304} 305#endif // !TARGET_OS_SIMULATOR 306 307/* 308 * Function: nwi_state_copy 309 * Purpose: 310 * Returns the current network state information. 311 * Release after use by calling nwi_state_release(). 312 */ 313nwi_state_t 314nwi_state_copy(void) 315{ 316 boolean_t force_refresh; 317 nwi_state_t nwi_state = NULL; 318 nwi_state_t old_state = NULL; 319 320 pthread_once(&initialized, _nwi_state_initialize); 321 pthread_mutex_lock(&nwi_store_lock); 322 323 force_refresh = ATOMIC_CMPXCHG(&nwi_store_force_refresh, TRUE, FALSE); 324 325 if (G_nwi_state != NULL) { 326 int check = 0; 327 uint32_t status; 328 329 if (!nwi_store_token_valid) { 330 /* have to throw cached copy away every time */ 331 check = 1; 332 } 333 else { 334 status = notify_check(nwi_store_token, &check); 335 if (status != NOTIFY_STATUS_OK) { 336 fprintf(stderr, "nwi notify_check: failed with %u\n", 337 status); 338 /* assume that it changed, throw cached copy away */ 339 check = 1; 340 } 341 } 342 if (check != 0 || force_refresh) { 343 /* new need snapshot */ 344 old_state = G_nwi_state; 345 G_nwi_state = NULL; 346 } 347 } 348 /* Let's populate the cache if it's empty */ 349 if (G_nwi_state == NULL) { 350 G_nwi_state = _nwi_state_copy_data(); 351 if (G_nwi_state != NULL) { 352 /* one reference for G_nwi_state */ 353 nwi_state_retain(G_nwi_state); 354 } 355 } 356 if (G_nwi_state != NULL) { 357 /* another reference for this caller */ 358 nwi_state_retain(G_nwi_state); 359 } 360 nwi_state = G_nwi_state; 361 pthread_mutex_unlock(&nwi_store_lock); 362 363 if (old_state != NULL) { 364 /* get rid of G_nwi_state reference */ 365 nwi_state_release(old_state); 366 } 367 return nwi_state; 368} 369 370/* 371 * Function: _nwi_state_ack 372 * Purpose: 373 * Acknowledge receipt and any changes associated with the [new or 374 * updated] network state. 375 */ 376void 377_nwi_state_ack(nwi_state_t state, const char *bundle_id) 378{ 379#pragma unused(bundle_id) 380 xpc_object_t reqdict; 381 382 if (state == NULL) { 383 return; // ASSERT 384 } 385 386 if ((nwi_client == NULL) || !nwi_client->active) { 387 // if network information server not available 388 return; 389 } 390 391 dispatch_sync(__nwi_client_queue(), ^{ 392 nwi_active++; // keep connection active (for the life of the process) 393 }); 394 395 // create message 396 reqdict = xpc_dictionary_create(NULL, NULL, 0); 397 398 // set request 399 xpc_dictionary_set_int64(reqdict, NWI_REQUEST, NWI_STATE_REQUEST_ACKNOWLEDGE); 400 401 // set generation 402 xpc_dictionary_set_uint64(reqdict, NWI_GENERATION, state->generation_count); 403 404 // send acknowledgement to the DNS configuration server 405 xpc_connection_send_message(nwi_client->connection, reqdict); 406 407 xpc_release(reqdict); 408 return; 409} 410 411/* 412 * Function: nwi_state_get_generation 413 * Purpose: 414 * Returns the generation (mach_time) of the nwi_state data. 415 * Every time the data is updated due to changes 416 * in the network, this value will change. 417 */ 418uint64_t 419nwi_state_get_generation(nwi_state_t state) 420{ 421 return (state->generation_count); 422} 423 424/* 425 * Function: nwi_ifstate_get_generation 426 * Purpose: 427 * Returns the generation (mach_time) of the nwi_ifstate data. 428 */ 429uint64_t 430nwi_ifstate_get_generation(nwi_ifstate_t ifstate) 431{ 432 return (ifstate->if_generation_count); 433} 434 435/* 436 * Function: nwi_ifstate_get_ifname 437 * Purpose: 438 * Return the interface name of the specified ifstate. 439 */ 440const char * 441nwi_ifstate_get_ifname(nwi_ifstate_t ifstate) 442{ 443 return ((ifstate != NULL) ? ifstate->ifname : NULL); 444} 445 446static uint64_t 447flags_from_af(int af) 448{ 449 return ((af == AF_INET) 450 ? NWI_IFSTATE_FLAGS_HAS_IPV4 451 : NWI_IFSTATE_FLAGS_HAS_IPV6); 452} 453/* 454 * Function: nwi_ifstate_get_flags 455 * Purpose: 456 * Return the flags for the given ifstate (see above for bit definitions). 457 */ 458nwi_ifstate_flags 459nwi_ifstate_get_flags(nwi_ifstate_t ifstate) 460{ 461 nwi_ifstate_t alias = NULL; 462 nwi_ifstate_flags flags = 0ULL; 463 464 if (ifstate->af_alias_offset != 0) { 465 alias = ifstate + ifstate->af_alias_offset; 466 } 467 flags |= flags_from_af(ifstate->af); 468 if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) { 469 flags |= NWI_IFSTATE_FLAGS_HAS_DNS; 470 } 471 if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) != 0) { 472 flags |= NWI_IFSTATE_FLAGS_HAS_CLAT46; 473 } 474 if (alias != NULL) { 475 flags |= flags_from_af(alias->af); 476 if ((alias->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) { 477 flags |= NWI_IFSTATE_FLAGS_HAS_DNS; 478 } 479 if ((alias->flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) != 0) { 480 flags |= NWI_IFSTATE_FLAGS_HAS_CLAT46; 481 } 482 } 483 return flags; 484} 485 486/* 487 * Function: nwi_state_get_first_ifstate 488 * Purpose: 489 * Returns the first and highest priority interface that has connectivity 490 * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6. 491 * The connectivity provided is for general networking. To get information 492 * about an interface that isn't available for general networking, use 493 * nwi_state_get_ifstate(). 494 * 495 * Use nwi_ifstate_get_next() to get the next, lower priority interface 496 * in the list. 497 * 498 * Returns NULL if no connectivity for the specified address family is 499 * available. 500 */ 501nwi_ifstate_t 502nwi_state_get_first_ifstate(nwi_state_t state, int af) 503{ 504 nwi_ifstate_t ifstate; 505 506 if (state == NULL) { 507 return NULL; 508 } 509 510 ifstate = nwi_state_get_ifstate_with_index(state, af, 0); 511 if (ifstate == NULL) { 512 return NULL; 513 } 514 if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) 515 != 0) { 516 ifstate = NULL; 517 } 518 519 return ifstate; 520 521} 522 523/* 524 * Function: nwi_state_get_ifstate 525 * Purpose: 526 * Return information for the specified interface 'ifname'. 527 * 528 * This API directly returns the ifstate for the specified interface. 529 * This is the only way to access information about an interface that isn't 530 * available for general networking. 531 * 532 * Returns NULL if no information is available for that interface. 533 */ 534nwi_ifstate_t 535nwi_state_get_ifstate(nwi_state_t state, const char * ifname) 536{ 537 nwi_ifstate_t ifstate = nwi_state_get_ifstate_with_name(state, AF_INET, ifname); 538 if (ifstate == NULL) { 539 ifstate = nwi_state_get_ifstate_with_name(state, AF_INET6, ifname); 540 } 541 return ifstate; 542 543} 544 545/* 546 * Function: nwi_ifstate_get_next 547 * Purpose: 548 * Returns the next, lower priority nwi_ifstate_t after the specified 549 * 'ifstate' for the protocol family 'af'. 550 * 551 * Returns NULL when the end of the list is reached, or we reach an 552 * item that is not in the list. 553 */ 554nwi_ifstate_t 555nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af) 556{ 557 ifstate = nwi_ifstate_get_alias(ifstate, af); 558 if (ifstate == NULL 559 || ((ifstate->flags 560 & (NWI_IFSTATE_FLAGS_NOT_IN_LIST 561 | NWI_IFSTATE_FLAGS_LAST_ITEM)) 562 != 0)) { 563 return (NULL); 564 } 565 ifstate++; 566 if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) { 567 return (NULL); 568 } 569 return (ifstate); 570} 571 572/* 573 * Function: nwi_ifstate_compare_rank 574 * Purpose: 575 * Compare the relative rank of two nwi_ifstate_t objects. 576 * 577 * The "rank" indicates the importance of the underlying interface. 578 * 579 * Returns: 580 * 0 if ifstate1 and ifstate2 are ranked equally 581 * -1 if ifstate1 is ranked ahead of ifstate2 582 * 1 if ifstate2 is ranked ahead of ifstate1 583 */ 584int 585nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2) 586{ 587 return RankCompare(ifstate1->rank, ifstate2->rank); 588} 589 590/* 591 * nwi_state_get_reachability_flags 592 * 593 * returns the global reachability flags for a given address family. 594 * If no address family is passed in, it returns the global reachability 595 * flags for either families. 596 * 597 * The reachability flags returned follow the definition of 598 * SCNetworkReachabilityFlags. 599 * 600 * If the flags are zero (i.e. do not contain kSCNetworkReachabilityFlagsReachable), there is no connectivity. 601 * 602 * Otherwise, at least kSCNetworkReachabilityFlagsReachable is set: 603 * Reachable only 604 * No other connection flags are set. 605 * Reachable and no ConnectionRequired 606 * If we have connectivity for the specified address family (and we'd 607 * be returning the reachability flags associated with the default route) 608 * Reachable and ConnectionRequired 609 * If we do not currently have an active/primary network but we may 610 * be able to establish connectivity. 611 * Reachable and OnDemand 612 * If we do not currently have an active/primary network but we may 613 * be able to establish connective on demand. 614 * Reachable and TransientConnection 615 * This connection is transient. 616 * Reachable and WWAN 617 * This connection will be going over the cellular network. 618 */ 619uint32_t 620nwi_state_get_reachability_flags(nwi_state_t nwi_state, int af) 621{ 622 if (nwi_state == NULL) { 623 return (0); 624 } 625 if (af == AF_INET || af == AF_INET6) { 626 nwi_ifstate_t ifstate; 627 628 ifstate = nwi_state_get_first_ifstate(nwi_state, af); 629 630 if (ifstate != NULL) { 631 return ifstate->reach_flags; 632 } 633 634 return (af == AF_INET) ? nwi_state->reach_flags_v4 : nwi_state->reach_flags_v6; 635 } else { 636 nwi_ifstate_t ifstate_v4; 637 nwi_ifstate_t ifstate_v6; 638 639 ifstate_v4 = nwi_state_get_first_ifstate(nwi_state, AF_INET); 640 ifstate_v6 = nwi_state_get_first_ifstate(nwi_state, AF_INET6); 641 642 if (ifstate_v4 != NULL) { 643 if (ifstate_v6 != NULL) { 644 if (nwi_ifstate_compare_rank(ifstate_v4, ifstate_v6) > 0) { 645 return ifstate_v6->reach_flags; 646 } else { 647 return ifstate_v4->reach_flags; 648 } 649 } else { 650 return ifstate_v4->reach_flags; 651 } 652 } else { 653 if (ifstate_v6 != NULL) { 654 return ifstate_v6->reach_flags; 655 } 656 } 657 658 if (nwi_state->reach_flags_v4 != 0) { 659 return nwi_state->reach_flags_v4; 660 } 661 // This is the case where both ifstate are NULL. 662 return nwi_state->reach_flags_v6; 663 } 664} 665 666/* 667 * nwi_ifstate_get_vpn_server 668 * 669 * returns a sockaddr representation of the vpn server address. 670 * NULL if PPP/VPN/IPSec server address does not exist. 671 */ 672const struct sockaddr * 673nwi_ifstate_get_vpn_server(nwi_ifstate_t ifstate) 674{ 675 const struct sockaddr * vpn_server_addr; 676 677 vpn_server_addr = (const struct sockaddr *)(void *) 678 &ifstate->vpn_server_address; 679 680 if (vpn_server_addr->sa_family == 0) { 681 return NULL; 682 } 683 return vpn_server_addr; 684} 685 686/* 687 * nwi_ifstate_get_reachability_flags 688 * 689 * returns the reachability flags for the interface given an address family. 690 * The flags returned are those determined outside of 691 * the routing table. [None, ConnectionRequired, OnDemand, 692 * Transient Connection, WWAN]. 693 */ 694uint32_t 695nwi_ifstate_get_reachability_flags(nwi_ifstate_t ifstate) 696{ 697 return ifstate->reach_flags; 698} 699 700/* 701 * nwi_ifstate_get_signature 702 * 703 * returns the signature and its length for an ifstate given an address family. 704 * If AF_UNSPEC is passed in, the signature for a given ifstate is returned. 705 * 706 * If the signature does not exist, NULL is returned. 707 */ 708const uint8_t * 709nwi_ifstate_get_signature(nwi_ifstate_t ifstate, int af, int * length) 710{ 711 nwi_ifstate_t i_state = NULL; 712 713 switch (af) { 714 case AF_UNSPEC: 715 i_state = ifstate; 716 break; 717 case AF_INET: 718 case AF_INET6: 719 i_state = nwi_ifstate_get_alias(ifstate, af); 720 break; 721 default: 722 break; 723 724 } 725 726 if (i_state != NULL) { 727 if ((i_state->flags & NWI_IFSTATE_FLAGS_HAS_SIGNATURE) != 0) { 728 *length = sizeof(i_state->signature); 729 return (i_state->signature); 730 } 731 } 732 733 *length = 0; 734 return NULL; 735} 736 737static inline 738boolean_t 739_nwi_ifstate_is_in_list(nwi_ifstate_t ifstate, int af) 740{ 741 nwi_ifstate_t i_state; 742 743 i_state = nwi_ifstate_get_alias(ifstate, af); 744 if (i_state == NULL) { 745 return FALSE; 746 } 747 748 if ((nwi_ifstate_get_flags(i_state) & NWI_IFSTATE_FLAGS_NOT_IN_LIST) 749 == 0) { 750 return TRUE; 751 } 752 753 return FALSE; 754} 755 756/* 757 * nwi_ifstate_get_dns_signature 758 * 759 * returns the signature and its length for given 760 * ifstate with a valid dns configuration. 761 * 762 * If the signature does not exist, NULL is returned. 763 * 764 */ 765const uint8_t * 766nwi_ifstate_get_dns_signature(nwi_ifstate_t ifstate, int * length) 767{ 768 const uint8_t * signature = NULL; 769 const uint8_t * v4_signature; 770 int v4_signature_len; 771 const uint8_t * v6_signature; 772 int v6_signature_len; 773 774 *length = 0; 775 776 if ((nwi_ifstate_get_flags(ifstate) & NWI_IFSTATE_FLAGS_HAS_DNS) == 0) { 777 return NULL; 778 } 779 780 v4_signature = nwi_ifstate_get_signature(ifstate, AF_INET, &v4_signature_len); 781 v6_signature = nwi_ifstate_get_signature(ifstate, AF_INET6, &v6_signature_len); 782 if (v4_signature == NULL && v6_signature == NULL) { 783 return NULL; 784 } 785 786 if (_nwi_ifstate_is_in_list(ifstate, AF_INET)) { 787 signature = v4_signature; 788 *length = v4_signature_len; 789 } else { 790 if (_nwi_ifstate_is_in_list(ifstate, AF_INET6) != TRUE && v4_signature_len > 0) { 791 /* v6 is ranked never, v4 is ranked never but has a valid signature */ 792 signature = v4_signature; 793 *length = v4_signature_len; 794 } else { 795 /* v6 is not ranked never or v4 has no signature */ 796 signature = v6_signature; 797 *length = v6_signature_len; 798 } 799 } 800 801 return signature; 802} 803 804unsigned int 805nwi_state_get_interface_names(nwi_state_t state, 806 const char * names[], 807 unsigned int names_count) 808{ 809 int i; 810 nwi_ifindex_t * scan; 811 812 if (names == NULL || names_count == 0) { 813 return (state->if_list_count); 814 } 815 for (i = 0, scan = nwi_state_if_list(state); 816 i < state->if_list_count; i++, scan++) { 817 names[i] = state->ifstate_list[*scan].ifname; 818 } 819 return (state->if_list_count); 820} 821 822#pragma mark - 823#pragma mark Network information [nwi] test code 824 825 826#ifdef TEST_NWI 827 828#include <arpa/inet.h> 829 830typedef union { 831 const struct sockaddr * sa; 832 const struct sockaddr_in * sin; 833 const struct sockaddr_in6 * sin6; 834} my_sockaddr_t; 835 836static const char * 837my_sockaddr_ntop(const struct sockaddr * sa, char * buf, int buf_len) 838{ 839 my_sockaddr_t addr; 840 const void * addr_ptr = NULL; 841 842 addr.sa = sa; 843 switch (sa->sa_family) { 844 case AF_INET: 845 addr_ptr = &addr.sin->sin_addr; 846 break; 847 case AF_INET6: 848 addr_ptr = &addr.sin6->sin6_addr; 849 break; 850 default: 851 addr_ptr = NULL; 852 break; 853 } 854 if (addr_ptr == NULL) { 855 return (NULL); 856 } 857 return (inet_ntop(addr.sa->sa_family, addr_ptr, buf, buf_len)); 858} 859 860static void 861nwi_ifstate_print(nwi_ifstate_t ifstate) 862{ 863 const char * addr_str; 864 void * address; 865 char addr_ntopbuf[INET6_ADDRSTRLEN]; 866 const char * diff_str; 867 char vpn_ntopbuf[INET6_ADDRSTRLEN]; 868 const struct sockaddr * vpn_addr; 869 const char * vpn_addr_str = NULL; 870 871 address = nwi_ifstate_get_address(ifstate); 872 addr_str = inet_ntop(ifstate->af, address, 873 addr_ntopbuf, sizeof(addr_ntopbuf)); 874 vpn_addr = nwi_ifstate_get_vpn_server(ifstate); 875 if (vpn_addr != NULL) { 876 vpn_addr_str = my_sockaddr_ntop(vpn_addr, vpn_ntopbuf, 877 sizeof(vpn_ntopbuf)); 878 } 879 diff_str = nwi_ifstate_get_diff_str(ifstate); 880 printf("%s%s%s%s%s rank 0x%x iaddr %s%s%s reach_flags 0x%x\n", 881 ifstate->ifname, 882 diff_str, 883 (ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0 884 ? " dns" : "", 885 (ifstate->flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) != 0 886 ? " clat46" : "", 887 (ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0 888 ? " never" : "", 889 ifstate->rank, 890 addr_str, 891 (vpn_addr_str != NULL) ? " vpn_server_addr: " : "", 892 (vpn_addr_str != NULL) ? vpn_addr_str : "", 893 ifstate->reach_flags); 894 return; 895} 896 897static void 898traverse_ifstates(nwi_state_t state) 899{ 900 nwi_ifstate_t alias; 901 int i; 902 nwi_ifstate_t scan; 903 904 scan = nwi_state_get_first_ifstate(state, AF_INET); 905 printf("IPv4 traverse list:\n"); 906 for (i = 0; scan != NULL; i++) { 907 printf("[%d] flags=0x%llx ", i, scan->flags); 908 nwi_ifstate_print(scan); 909 alias = nwi_ifstate_get_alias(scan, nwi_other_af(scan->af)); 910 scan = nwi_ifstate_get_next(scan, AF_INET); 911 if (alias != NULL) { 912 printf("\t alias is "); 913 nwi_ifstate_print(alias); 914 } 915 } 916 printf("IPv6 traverse list:\n"); 917 scan = nwi_state_get_first_ifstate(state, AF_INET6); 918 for (i = 0; scan != NULL; i++) { 919 printf("[%d] flags=0x%llx ", i, scan->flags); 920 alias = nwi_ifstate_get_alias(scan, nwi_other_af(scan->af)); 921 nwi_ifstate_print(scan); 922 scan = nwi_ifstate_get_next(scan, AF_INET6); 923 if (alias != NULL) { 924 printf("\t alias is "); 925 nwi_ifstate_print(alias); 926 } 927 } 928} 929 930static void 931nwi_state_print_common(nwi_state_t state, bool diff) 932{ 933 unsigned int count = 0; 934 int i; 935 nwi_ifstate_t scan; 936 937 if (state == NULL) { 938 return; 939 } 940 printf("nwi_state = { " 941 "gen=%llu max_if=%u #v4=%u #v6=%u " 942 "reach_flags=(v4=0x%x, v6=0x%x) }\n", 943 state->generation_count, 944 state->max_if_count, 945 state->ipv4_count, 946 state->ipv6_count, 947 nwi_state_get_reachability_flags(state, AF_INET), 948 nwi_state_get_reachability_flags(state, AF_INET6)); 949 if (state->ipv4_count) { 950 printf("IPv4:\n"); 951 for (i = 0, scan = nwi_state_ifstate_list(state, AF_INET); 952 i < state->ipv4_count; i++, scan++) { 953 printf("[%d] ", i); 954 nwi_ifstate_print(scan); 955 } 956 } 957 if (state->ipv6_count) { 958 printf("IPv6:\n"); 959 for (i = 0, scan = nwi_state_ifstate_list(state, AF_INET6); 960 i < state->ipv6_count; i++, scan++) { 961 printf("[%d] ", i); 962 nwi_ifstate_print(scan); 963 } 964 } 965 if (!diff) { 966 count = nwi_state_get_interface_names(state, NULL, 0); 967 if (count > 0) { 968 const char * names[count]; 969 970 count = nwi_state_get_interface_names(state, names, 971 count); 972 printf("%d interfaces%s", count, 973 (count != 0) ? ": " : ""); 974 for (i = 0; i < count; i++) { 975 printf("%s%s", (i == 0) ? "" : ", ", names[i]); 976 } 977 printf("\n"); 978 } 979 else { 980 printf("0 interfaces\n"); 981 } 982 traverse_ifstates(state); 983 } 984 printf("-----------------------------------\n"); 985 return; 986} 987 988static void 989nwi_state_print(nwi_state_t state) 990{ 991 nwi_state_print_common(state, FALSE); 992} 993 994static void 995nwi_state_print_diff(nwi_state_t state) 996{ 997 printf("DIFF\n"); 998 nwi_state_print_common(state, TRUE); 999} 1000 1001static void 1002doit(void) 1003{ 1004 struct in_addr addr = { 0 }; 1005 struct in6_addr addr6; 1006 nwi_ifstate_t ifstate; 1007 nwi_state_t state; 1008 nwi_state_t diff_state; 1009 nwi_state_t new_state; 1010 nwi_state_t old_state; 1011 nwi_state_t old_state_copy; 1012 1013 state = nwi_state_new(NULL, 0); 1014 nwi_state_print(state); 1015 state = nwi_state_new(NULL, 1); 1016 nwi_state_print(state); 1017 state = nwi_state_new(state, 2); 1018 nwi_state_print(state); 1019 state = nwi_state_new(state, 10); 1020 nwi_state_print(state); 1021 1022 memset(&addr6, 0, sizeof(addr6)); 1023 /* populate old_state */ 1024 old_state = nwi_state_new(NULL, 5); 1025 for (int i = 0; i < 5; i++) { 1026 char ifname[IFNAMSIZ]; 1027 1028 snprintf(ifname, sizeof(ifname), "en%d", i); 1029 addr.s_addr = htonl((i % 2) ? i : (i + 1)); 1030 ifstate = nwi_state_add_ifstate(old_state, ifname, AF_INET, 0, 1031 (i % 2) ? (i - 1) : (i + 1), 1032 &addr, 1033 NULL, 1034 0); 1035 addr6.__u6_addr.__u6_addr32[0] = htonl(i); 1036 ifstate = nwi_state_add_ifstate(old_state, ifname, AF_INET6, 0, 1037 (i % 2) ? (10 - i) : i, 1038 &addr6, 1039 NULL, 1040 0); 1041 } 1042 nwi_state_finalize(old_state); 1043 nwi_state_print(old_state); 1044 1045 diff_state = nwi_state_diff(NULL, old_state); 1046 nwi_state_print_diff(diff_state); 1047 nwi_state_free(diff_state); 1048 1049 /* remember the old state */ 1050 old_state_copy = nwi_state_make_copy(old_state); 1051 1052 /* create new state */ 1053 new_state = nwi_state_new(old_state, 10); 1054 nwi_state_print(new_state); 1055 1056 for (int i = 0; i < 10; i++) { 1057 char ifname[IFNAMSIZ]; 1058 uint64_t flags; 1059 1060 snprintf(ifname, sizeof(ifname), "en%d", i); 1061 addr6.__u6_addr.__u6_addr32[0] = htonl(i); 1062 flags = (i > 6) ? NWI_IFSTATE_FLAGS_NOT_IN_LIST : 0; 1063 ifstate = nwi_state_add_ifstate(new_state, ifname, AF_INET6, 1064 flags, 1065 i, 1066 &addr6, 1067 NULL, 1068 0); 1069 } 1070 for (int i = 9; i >= 0; i--) { 1071 char ifname[IFNAMSIZ]; 1072 1073 snprintf(ifname, sizeof(ifname), "en%d", i); 1074 addr.s_addr = htonl(i); 1075 if (i != 3) { 1076 ifstate = nwi_state_add_ifstate(new_state, 1077 ifname, AF_INET, 1078 0, 1079 i, 1080 &addr, 1081 NULL, 1082 0); 1083 } 1084 } 1085 nwi_state_finalize(new_state); 1086 nwi_state_print(new_state); 1087 1088 diff_state = nwi_state_diff(old_state_copy, new_state); 1089 nwi_state_print_diff(diff_state); 1090 nwi_state_free(diff_state); 1091 1092 diff_state = nwi_state_diff(new_state, old_state_copy); 1093 nwi_state_print_diff(diff_state); 1094 nwi_state_free(diff_state); 1095 1096 nwi_state_free(old_state_copy); 1097 nwi_state_free(new_state); 1098 return; 1099} 1100 1101int 1102main() 1103{ 1104 doit(); 1105 exit(0); 1106 return (0); 1107} 1108 1109#endif /* TEST_NWI */ 1110 1111#ifdef TEST_NWI_STATE 1112 1113int 1114main(int argc, char * argv[]) 1115{ 1116 nwi_state_t state = nwi_state_copy(); 1117 1118 exit(0); 1119 return (0); 1120} 1121 1122#endif