1/*
2 * Copyright (c) 2003-2014 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#ifndef _SCNETWORKREACHABILITYINTERNAL_H
25#define _SCNETWORKREACHABILITYINTERNAL_H
26
27#include <Availability.h>
28#include <TargetConditionals.h>
29#include <sys/cdefs.h>
30#include <CoreFoundation/CoreFoundation.h>
31#include <CoreFoundation/CFRuntime.h>
32#include <SystemConfiguration/SystemConfiguration.h>
33#include <SystemConfiguration/SCPrivate.h>
34#include <dispatch/dispatch.h>
35
36#include <dns_sd.h>
37#include <netdb.h>
38#include <sys/socket.h>
39#include <net/if.h>
40#include <xpc/xpc.h>
41
42
43
44
45#pragma mark -
46#pragma mark SCNetworkReachability
47
48
49#define kSCNetworkReachabilityFlagsFirstResolvePending	(1<<31)
50
51
52
53#define kSCNetworkReachabilityFlagsMask			0x00ffffff	// top 8-bits reserved for implementation
54
55
56typedef	enum {
57	NO	= 0,
58	YES,
59	UNKNOWN
60} lazyBoolean;
61
62
63typedef enum {
64	// by-address SCNetworkReachability targets
65	reachabilityTypeAddress,
66	reachabilityTypeAddressPair,
67	// by-name SCNetworkReachability targets
68	reachabilityTypeName,
69	reachabilityTypePTR
70} ReachabilityAddressType;
71
72#define isReachabilityTypeAddress(type)		(type < reachabilityTypeName)
73#define isReachabilityTypeName(type)		(type >= reachabilityTypeName)
74
75
76typedef struct {
77	uint64_t			cycle;
78	SCNetworkReachabilityFlags	flags;
79	unsigned int			if_index;
80	char				if_name[IFNAMSIZ];
81	Boolean				sleeping;
82} ReachabilityInfo;
83
84
85typedef struct {
86
87	/* base CFType information */
88	CFRuntimeBase			cfBase;
89
90	/* lock */
91	pthread_mutex_t			lock;
92
93	/* logging */
94	Boolean				quiet;
95
96	/* address type */
97	ReachabilityAddressType		type;
98
99	/* target host name */
100	const char			*name;
101	Boolean				needResolve;
102	CFArrayRef			resolvedAddresses;	/* CFArray[CFData] or CFArray[CFString] */
103	int				resolvedError;
104	SCNetworkReachabilityFlags	resolverFlags;
105
106	/* [scoped routing] interface constraints */
107	unsigned int			if_index;
108	char				if_name[IFNAMSIZ];
109
110	/* local & remote addresses */
111	struct sockaddr			*localAddress;
112	struct sockaddr			*remoteAddress;
113
114	/* current reachability flags */
115	uint64_t			cycle;
116	ReachabilityInfo		info;
117	ReachabilityInfo		last_notify;
118
119	/* run loop source, callout, context, rl scheduling info */
120	Boolean				scheduled;
121	CFRunLoopSourceRef		rls;
122	SCNetworkReachabilityCallBack	rlsFunction;
123	SCNetworkReachabilityContext	rlsContext;
124	CFMutableArrayRef		rlList;
125	unsigned int			pending;		// 0 == no notifications queued, else # to be delivered
126
127	dispatch_group_t		dispatchGroup;
128	dispatch_queue_t		dispatchQueue;		// SCNetworkReachabilitySetDispatchQueue
129
130	/* [async] DNS query info */
131	Boolean				haveDNS;
132	struct timeval			dnsQueryStart;
133	struct timeval			dnsQueryEnd;
134
135	/* [async] processing info */
136	struct timeval			last_dns;
137	struct timeval			last_network;
138#if	!TARGET_OS_IPHONE
139	struct timeval			last_power;
140#endif	// !TARGET_OS_IPHONE
141	struct timeval			last_push;
142
143	/* on demand info */
144	Boolean				onDemandBypass;
145	CFStringRef			onDemandName;
146	CFStringRef			onDemandRemoteAddress;
147	SCNetworkReachabilityRef	onDemandServer;
148	CFStringRef			onDemandServiceID;
149
150
151	union {
152		uint32_t		dnsFlags;
153		struct {
154			Boolean		dnsActive     :1;	// if DNSServiceGetAddrInfo active
155
156			Boolean		dnsHaveError  :1;	// error during query
157			Boolean		dnsHaveV4     :1;	// have IPv4 (A) reply
158			Boolean		dnsHaveV6     :1;	// have IPv6 (AAAA) reply
159			Boolean		dnsHavePTR    :1;	// have PTR reply
160			Boolean		dnsHaveTimeout:1;	// no replies (A, AAAA, or PTR)
161		};
162	};
163	CFArrayRef			dnsAddresses;		// CFArray[CFData]
164	Boolean				dnsBlocked;		// if DNS query blocked
165	int				dnsError;
166	int				dnsFailures;		// # of unexpected DNSServiceXXX errors
167	int				dnsGeneration;
168	DNSServiceRef			dnsTarget;
169	Boolean				dnsNoAddressesSinceLastTimeout;
170
171	/* SCNetworkReachability server "client" info */
172	Boolean				serverActive;
173	Boolean				serverBypass;
174	Boolean				serverScheduled;
175	ReachabilityInfo		serverInfo;
176
177	/* SCNetworkReachability server "server" info */
178	CFDataRef			serverDigest;
179	dispatch_group_t		serverGroup;
180	Boolean				serverInfoValid;
181	unsigned int			serverSyncQueryActive;	// 0 == no [sync] query active, else # waiting on group
182	dispatch_queue_t		serverQueue;
183	unsigned int			serverReferences;	// how many [client] targets
184	CFMutableDictionaryRef		serverWatchers;		// [client_id/target_id] watchers
185
186	Boolean				useNEVPN;
187	uid_t				uid;
188	void				*nePolicyResult;
189	Boolean				serverBypassForVPN;	// if serverBypassForVPN, only use client mode
190
191	Boolean				resolverBypass;		// set this flag to bypass resolving the name
192
193
194
195	/* logging */
196	char				log_prefix[32];
197
198} SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef;
199
200
201
202// ------------------------------------------------------------
203
204#pragma mark -
205#pragma mark [XPC] Reachability Server
206
207
208#define	REACH_SERVER_VERSION		20110323
209
210#if	!TARGET_IPHONE_SIMULATOR
211#define	REACH_SERVICE_NAME		"com.apple.SystemConfiguration.SCNetworkReachability"
212#else	// !TARGET_IPHONE_SIMULATOR
213#define	REACH_SERVICE_NAME		"com.apple.SystemConfiguration.SCNetworkReachability_sim"
214#endif	// !TARGET_IPHONE_SIMULATOR
215
216// ------------------------------------------------------------
217
218
219#pragma mark -
220#pragma mark [XPC] Reachability Server (client->server request)
221
222
223#define	REACH_CLIENT_PROC_NAME		"proc_name"		// string
224#define	REACH_CLIENT_TARGET_ID		"target_id"		// uint64
225
226#define	REACH_REQUEST			"request_op"		// int64
227
228enum {
229	REACH_REQUEST_CREATE		= 0x0001,
230	REACH_REQUEST_REMOVE,
231	REACH_REQUEST_SCHEDULE,
232	REACH_REQUEST_STATUS,
233	REACH_REQUEST_UNSCHEDULE,
234	REACH_REQUEST_SNAPSHOT		= 0x0101,
235};
236
237#define	REACH_TARGET_NAME		"name"			// string
238
239#define	REACH_TARGET_LOCAL_ADDR		"local_address"		// data (struct sockaddr)
240#define	REACH_TARGET_REMOTE_ADDR	"remote_address"	// data (struct sockaddr)
241
242#define	REACH_TARGET_PTR_ADDR		"ptr_address"		// data (struct sockaddr)
243
244#define	REACH_TARGET_IF_INDEX		"if_index"		// int64
245#define	REACH_TARGET_IF_NAME		"if_name"		// string
246#define	REACH_TARGET_ONDEMAND_BYPASS	"ondemand_bypass"	// bool
247#define REACH_TARGET_RESOLVER_BYPASS	"resolver_bypass"	// bool
248
249
250#define REACH_REQUEST_REPLY		"reply"			// int64
251#define REACH_REQUEST_REPLY_DETAIL	"reply_detail"		// string
252
253enum {
254	REACH_REQUEST_REPLY_OK		= 0x0000,
255	REACH_REQUEST_REPLY_FAILED,
256	REACH_REQUEST_REPLY_UNKNOWN,
257};
258
259
260// ------------------------------------------------------------
261
262
263#pragma mark -
264#pragma mark [XPC] Reachability Server (server->client request)
265
266
267#define	MESSAGE_NOTIFY			"notify_op"		// int64
268
269enum {
270	MESSAGE_REACHABILITY_STATUS	= 0x1001,
271};
272
273#define REACH_STATUS_CYCLE		"cycle"			// uint64
274#define REACH_STATUS_DNS_FLAGS		"dns_flags"		// uint64
275#define REACH_STATUS_FLAGS		"flags"			// uint64
276#define REACH_STATUS_IF_INDEX		"if_index"		// uint64
277#define REACH_STATUS_IF_NAME		"if_name"		// data (char if_name[IFNAMSIZ])
278#define REACH_STATUS_RESOLVED_ADDRESSES	"resolved_addresses"	// array[data]
279#define REACH_STATUS_RESOLVED_ERROR	"resolved_error"	// int64
280#define REACH_STATUS_SLEEPING		"sleeping"		// bool
281
282
283// ------------------------------------------------------------
284
285
286__BEGIN_DECLS
287
288CFStringRef
289_SCNetworkReachabilityCopyTargetDescription	(SCNetworkReachabilityRef	target);
290
291CFStringRef
292_SCNetworkReachabilityCopyTargetFlags		(SCNetworkReachabilityRef	target);
293
294void
295__SCNetworkReachabilityUpdate			(SCNetworkReachabilityRef	target);
296
297void
298__SCNetworkReachabilityUpdateConcurrent		(SCNetworkReachabilityRef	target);
299
300dispatch_queue_t
301__SCNetworkReachability_concurrent_queue	(void);
302
303#pragma mark -
304#pragma mark [XPC] Reachability Server (client APIs)
305
306Boolean
307_SCNetworkReachabilityServer_snapshot		(void);
308
309Boolean
310__SCNetworkReachabilityServer_targetAdd		(SCNetworkReachabilityRef	target);
311
312void
313__SCNetworkReachabilityServer_targetRemove	(SCNetworkReachabilityRef	target);
314
315Boolean
316__SCNetworkReachabilityServer_targetSchedule	(SCNetworkReachabilityRef	target);
317
318Boolean
319__SCNetworkReachabilityServer_targetStatus	(SCNetworkReachabilityRef	target);
320
321Boolean
322__SCNetworkReachabilityServer_targetUnschedule	(SCNetworkReachabilityRef	target);
323
324
325Boolean
326__SC_checkResolverReachabilityInternal		(SCDynamicStoreRef		*storeP,
327						 SCNetworkReachabilityFlags	*flags,
328						 Boolean			*haveDNS,
329						 const char			*nodename,
330						 uint32_t			*resolver_if_index,
331						 int				*dns_config_index);
332
333static __inline__ void
334__SCNetworkReachabilityPrintFlags(SCNetworkReachabilityFlags flags)
335{
336	if (flags != 0) {
337		if (flags & kSCNetworkReachabilityFlagsReachable) {
338			SCPrint(TRUE, stdout, CFSTR("Reachable"));
339			flags &= ~kSCNetworkReachabilityFlagsReachable;
340			SCPrint(flags != 0, stdout, CFSTR(","));
341		}
342		if (flags & kSCNetworkReachabilityFlagsTransientConnection) {
343			SCPrint(TRUE, stdout, CFSTR("Transient Connection"));
344			flags &= ~kSCNetworkReachabilityFlagsTransientConnection;
345			SCPrint(flags != 0, stdout, CFSTR(","));
346		}
347		if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
348			SCPrint(TRUE, stdout, CFSTR("Connection Required"));
349			flags &= ~kSCNetworkReachabilityFlagsConnectionRequired;
350			SCPrint(flags != 0, stdout, CFSTR(","));
351		}
352		if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) {
353			SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Traffic"));
354			flags &= ~kSCNetworkReachabilityFlagsConnectionOnTraffic;
355			SCPrint(flags != 0, stdout, CFSTR(","));
356		}
357		if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) {
358			SCPrint(TRUE, stdout, CFSTR("Automatic Connection On Demand"));
359			flags &= ~kSCNetworkReachabilityFlagsConnectionOnDemand;
360			SCPrint(flags != 0, stdout, CFSTR(","));
361		}
362		if (flags & kSCNetworkReachabilityFlagsInterventionRequired) {
363			SCPrint(TRUE, stdout, CFSTR("Intervention Required"));
364			flags &= ~kSCNetworkReachabilityFlagsInterventionRequired;
365			SCPrint(flags != 0, stdout, CFSTR(","));
366		}
367		if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) {
368			SCPrint(TRUE, stdout, CFSTR("Local Address"));
369			flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress;
370			SCPrint(flags != 0, stdout, CFSTR(","));
371		}
372		if (flags & kSCNetworkReachabilityFlagsIsDirect) {
373			SCPrint(TRUE, stdout, CFSTR("Directly Reachable Address"));
374			flags &= ~kSCNetworkReachabilityFlagsIsDirect;
375			SCPrint(flags != 0, stdout, CFSTR(","));
376		}
377#if	TARGET_OS_IPHONE
378		if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
379			SCPrint(TRUE, stdout, CFSTR("WWAN"));
380			flags &= ~kSCNetworkReachabilityFlagsIsWWAN;
381			SCPrint(flags != 0, stdout, CFSTR(","));
382		}
383#endif	// TARGET_OS_IPHONE
384		if (flags != 0) {
385			SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags);
386		}
387	} else {
388		SCPrint(TRUE, stdout, CFSTR("Not Reachable"));
389	}
390
391	return;
392}
393
394
395__END_DECLS
396
397#endif	// _SCNETWORKREACHABILITYINTERNAL_H
398