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