2 * Copyright (c) 2017, 2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef _NETWORK_STATE_INFORMATION_LOGGING_H
25 #define _NETWORK_STATE_INFORMATION_LOGGING_H
27 #include <os/availability.h>
28 #include <TargetConditionals.h>
29 #include <sys/cdefs.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <SystemConfiguration/SystemConfiguration.h>
32 #include <SystemConfiguration/SCPrivate.h>
34 #include <network_information.h>
35 #include "network_state_information_priv.c"
40 #define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
41 #define MY_LOG_DEFINED_LOCALLY
44 #ifndef my_log_context_type
45 #define my_log_context_type void *
46 #define MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY
47 #endif // !my_log_context_type
49 #ifndef my_log_context_name
50 #define my_log_context_name context
51 #define MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY
52 #endif // !my_log_context_name
54 #include "SCNetworkReachabilityLogging.h"
57 * _nwi_ifstate_flags_str()
59 * Returns a string representation of the nwi_state flags.
60 * "(IPv4,IPv6,DNS,...)"
62 static __inline__
void
63 _nwi_ifstate_flags_str(nwi_ifstate_flags flags
, char *str
, size_t len
)
66 nwi_ifstate_flags remaining
;
68 assert(len
>= sizeof("(0x01234567)")); // check min buffer size
70 flags
&= NWI_IFSTATE_FLAGS_MASK
;
76 len
--; // leave room for the closing paren
77 n
= strlcpy(str
, "(", len
);
80 if ((remaining
& NWI_IFSTATE_FLAGS_HAS_IPV4
) &&
81 (n
< len
) && ((len
- n
) > sizeof("IPv4,"))) {
82 n
= strlcat(str
, "IPv4,", len
);
83 remaining
&= ~NWI_IFSTATE_FLAGS_HAS_IPV4
;
86 if ((remaining
& NWI_IFSTATE_FLAGS_HAS_IPV6
) &&
87 (n
< len
) && ((len
- n
) > sizeof("IPv6,"))) {
88 n
= strlcat(str
, "IPv6,", len
);
89 remaining
&= ~NWI_IFSTATE_FLAGS_HAS_IPV6
;
92 if ((remaining
& NWI_IFSTATE_FLAGS_HAS_DNS
) &&
93 (n
< len
) && ((len
- n
) > sizeof("DNS,"))) {
94 n
= strlcat(str
, "DNS,", len
);
95 remaining
&= ~NWI_IFSTATE_FLAGS_HAS_DNS
;
98 if ((remaining
& NWI_IFSTATE_FLAGS_HAS_CLAT46
) &&
99 (n
< len
) && ((len
- n
) > sizeof("CLAT46,"))) {
100 n
= strlcat(str
, "CLAT46,", len
);
101 remaining
&= ~NWI_IFSTATE_FLAGS_HAS_CLAT46
;
104 if ((remaining
& NWI_IFSTATE_FLAGS_NOT_IN_LIST
) &&
105 (n
< len
) && ((len
- n
) > sizeof("NOT-IN-LIST,"))) {
106 n
= strlcat(str
, "NOT-IN-LIST,", len
);
107 remaining
&= ~NWI_IFSTATE_FLAGS_NOT_IN_LIST
;
110 if ((remaining
& NWI_IFSTATE_FLAGS_HAS_SIGNATURE
) &&
111 (n
< len
) && ((len
- n
) > sizeof("SIGNATURE,"))) {
112 n
= strlcat(str
, "SIGNATURE,", len
);
113 remaining
&= ~NWI_IFSTATE_FLAGS_HAS_SIGNATURE
;
116 if ((remaining
& NWI_IFSTATE_FLAGS_NOT_IN_IFLIST
) &&
117 (n
< len
) && ((len
- n
) > sizeof("NOT-IN-IFLIST,"))) {
118 n
= strlcat(str
, "NOT-IN-IFLIST,", len
);
119 remaining
&= ~NWI_IFSTATE_FLAGS_NOT_IN_IFLIST
;
122 if (remaining
!= 0) {
124 ((len
- n
) <= sizeof("0x01234567,"))) {
125 // if we don't have enough space, truncate and start over
126 n
= strlcpy(str
, "(", len
);
130 n
+= snprintf(str
+ n
, len
- n
, ",%p", (void *)remaining
);
134 str
[n
] = ')'; // trailing "," --> ")"
140 static __inline__
const char *
141 _nwi_ifstate_rank_str(Rank rank
)
143 const char *str
= "???";
145 switch (RANK_ASSERTION_MASK(rank
)) {
146 case kRankAssertionFirst
:
149 case kRankAssertionDefault
:
152 case kRankAssertionLast
:
155 case kRankAssertionNever
:
158 case kRankAssertionScoped
:
169 static __inline__
void
170 _nwi_ifstate_log(nwi_ifstate_t ifstate
, boolean_t debug
, my_log_context_type my_log_context_name
)
172 #if defined(MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY) && defined(MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY)
173 #pragma unused(my_log_context_name)
177 const struct in_addr
*ia
;
178 const struct in6_addr
*ia6
;
180 char addr_str
[INET6_ADDRSTRLEN
];
181 nwi_ifstate_flags flags_ifstate
;
184 SCNetworkReachabilityFlags reach_flags
;
186 const struct sockaddr
*vpn_addr
;
189 flags_ifstate
= nwi_ifstate_get_flags(ifstate
);
191 flags_ifstate
|= NWI_IFSTATE_FLAGS(ifstate
->flags
);
193 flags_ifstate
&= ~NWI_IFSTATE_FLAGS_HAS_SIGNATURE
; // exclude flag ('cause we'll report the signature only if present)
194 _nwi_ifstate_flags_str(flags_ifstate
, flags_str
, sizeof(flags_str
));
197 if_name
= nwi_ifstate_get_ifname(ifstate
);
199 // reachability flags
200 reach_flags
= nwi_ifstate_get_reachability_flags(ifstate
);
203 addr
.bytes
= nwi_ifstate_get_address(ifstate
);
204 if (inet_ntop(ifstate
->af
, addr
.bytes
, addr_str
, sizeof(addr_str
)) == NULL
) {
205 strlcpy(addr_str
, "???", sizeof(addr_str
));
208 // verbose format (e.g. scutil)
209 my_log(LOG_INFO
, " %7s : flags : %p %s",
211 (void *)flags_ifstate
,
214 my_log(LOG_INFO
, " address : %s", addr_str
);
216 // VPN server address
217 vpn_addr
= nwi_ifstate_get_vpn_server(ifstate
);
218 if (vpn_addr
!= NULL
) {
219 char vpn_str
[INET6_ADDRSTRLEN
];
221 _SC_sockaddr_to_string(vpn_addr
, vpn_str
, sizeof(vpn_str
));
222 my_log(LOG_INFO
, " VPN server : %s", vpn_str
);
226 __SCNetworkReachability_flags_string(reach_flags
, TRUE
, reach_str
, sizeof(reach_str
));
227 my_log(LOG_INFO
, " reach : %s", reach_str
);
233 const char *rank_str
;
234 const uint8_t *signature
;
235 int signature_length
= 0;
238 rank
= ifstate
->rank
;
239 rank_str
= _nwi_ifstate_rank_str(rank
);
240 rank_index
= RANK_INDEX_MASK(rank
);
241 if (rank_index
!= kRankIndexMask
) {
242 my_log(LOG_INFO
, " rank : 0x%08x (%s, %u)", rank
, rank_str
, rank_index
);
244 my_log(LOG_INFO
, " rank : 0x%08x (%s, Last)", rank
, rank_str
);
248 signature
= nwi_ifstate_get_signature(ifstate
, AF_UNSPEC
, &signature_length
);
249 if (signature
!= NULL
) {
252 digest
= CFDataCreate(NULL
, signature
, signature_length
);
253 my_log(LOG_INFO
, " signature : %@", digest
);
258 generation
= nwi_ifstate_get_generation(ifstate
);
259 my_log(LOG_INFO
, " generation : %llu", generation
);
265 static __inline__
void
266 _nwi_state_reachability_log(nwi_state_t state
, boolean_t debug
, int af
, my_log_context_type my_log_context_name
)
268 #if defined(MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY) && defined(MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY)
269 #pragma unused(my_log_context_name)
274 flags
= nwi_state_get_reachability_flags(state
, af
);
275 __SCNetworkReachability_flags_string(flags
, TRUE
, flags_str
, sizeof(flags_str
));
277 my_log(LOG_INFO
, "%s", "");
279 my_log(LOG_INFO
, " REACH : flags %s", flags_str
);
284 static __inline__
void
285 _nwi_state_log(nwi_state_t state
, boolean_t debug
, my_log_context_type my_log_context_name
)
287 #if defined(MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY) && defined(MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY)
288 #pragma unused(my_log_context_name)
292 nwi_ifstate_t ifstate
;
295 my_log(LOG_INFO
, "%s", "Network information");
298 "Network information (generation %llu size=%lu)",
299 nwi_state_get_generation(state
),
300 nwi_state_size(state
));
305 // show regular interfaces
306 my_log(LOG_INFO
, "%s", "");
307 my_log(LOG_INFO
, "%s", "IPv4 network interface information");
308 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET
);
309 if (ifstate
== NULL
) {
310 my_log(LOG_INFO
, "%s", " No IPv4 states found");
312 while (ifstate
!= NULL
) {
313 _nwi_ifstate_log(ifstate
, debug
, my_log_context_name
);
314 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET
);
318 my_log(LOG_INFO
, "%s", "IPv4 network interface information");
319 if (state
->ipv4_count
> 0) {
320 // show ALL interfaces
321 for (i
= 0, ifstate
= nwi_state_ifstate_list(state
, AF_INET
);
322 i
< state
->ipv4_count
; i
++, ifstate
++) {
323 _nwi_ifstate_log(ifstate
, debug
, my_log_context_name
);
326 my_log(LOG_INFO
, "%s", " No IPv4 states found");
329 _nwi_state_reachability_log(state
, debug
, AF_INET
, my_log_context_name
);
333 // show regular interfaces
334 my_log(LOG_INFO
, "%s", "");
335 my_log(LOG_INFO
, "%s", "IPv6 network interface information");
336 ifstate
= nwi_state_get_first_ifstate(state
, AF_INET6
);
337 if (ifstate
== NULL
) {
338 my_log(LOG_INFO
, "%s", " No IPv6 states found\n");
340 while (ifstate
!= NULL
) {
341 _nwi_ifstate_log(ifstate
, debug
, my_log_context_name
);
342 ifstate
= nwi_ifstate_get_next(ifstate
, AF_INET6
);
346 my_log(LOG_INFO
, "%s", "IPv6 network interface information");
347 if (state
->ipv6_count
> 0) {
348 // show ALL interfaces
349 for (i
= 0, ifstate
= nwi_state_ifstate_list(state
, AF_INET6
);
350 i
< state
->ipv6_count
; i
++, ifstate
++) {
351 _nwi_ifstate_log(ifstate
, debug
, my_log_context_name
);
354 my_log(LOG_INFO
, "%s", " No IPv6 states found\n");
357 _nwi_state_reachability_log(state
, debug
, AF_INET6
, my_log_context_name
);
359 count
= nwi_state_get_interface_names(state
, NULL
, 0);
361 const char *names
[count
];
363 count
= nwi_state_get_interface_names(state
, names
, count
);
365 char str
[count
* (IFNAMSIZ
+ 1)];
367 memset(str
, 0, sizeof(str
));
368 for (unsigned int i
= 0; i
< count
; i
++) {
370 strlcat(str
, " ", sizeof(str
));
372 strlcat(str
, names
[i
], sizeof(str
));
376 my_log(LOG_INFO
, "%s", "");
378 my_log(LOG_INFO
, "Network interfaces: %s", str
);
385 #ifdef MY_LOG_DEFINED_LOCALLY
387 #undef MY_LOG_DEFINED_LOCALLY
388 #endif // MY_LOG_DEFINED_LOCALLY
390 #ifdef MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY
391 #undef my_log_context_type
392 #undef MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY
393 #endif // MY_LOG_CONTEXT_TYPE_DEFINED_LOCALLY
395 #ifdef MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY
396 #undef my_log_context_name
397 #undef MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY
398 #endif // MY_LOG_CONTEXT_NAME_DEFINED_LOCALLY
402 #endif // _NETWORK_STATE_INFORMATION_LOGGING_H