1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19#include	<stdio.h>
20#include	<stdlib.h>
21#include	<string.h>
22
23#include	"ClientCommon.h"
24#include	"CommonServices.h"
25#include	"DebugServices.h"
26
27#include	<iphlpapi.h>
28#include	<guiddef.h>
29#include	<ws2spi.h>
30#include	<shlwapi.h>
31
32
33
34#include	"dns_sd.h"
35
36#pragma comment(lib, "DelayImp.lib")
37
38#ifdef _MSC_VER
39#define swprintf _snwprintf
40#define snprintf _snprintf
41#endif
42
43#define MAX_LABELS 128
44
45#if 0
46#pragma mark == Structures ==
47#endif
48
49//===========================================================================================================================
50//	Structures
51//===========================================================================================================================
52
53typedef struct	Query *		QueryRef;
54typedef struct	Query		Query;
55struct	Query
56{
57	QueryRef			next;
58	int					refCount;
59	DWORD				querySetFlags;
60	WSAQUERYSETW *		querySet;
61	size_t				querySetSize;
62	HANDLE				data4Event;
63	HANDLE				data6Event;
64	HANDLE				cancelEvent;
65	HANDLE				waitHandles[ 3 ];
66	DWORD				waitCount;
67	DNSServiceRef		resolver4;
68	DNSServiceRef		resolver6;
69	char				name[ kDNSServiceMaxDomainName ];
70	size_t				nameSize;
71	uint8_t				numValidAddrs;
72	uint32_t			addr4;
73	bool				addr4Valid;
74	uint8_t				addr6[16];
75	u_long				addr6ScopeId;
76	bool				addr6Valid;
77};
78
79#define BUFFER_INITIAL_SIZE		4192
80#define ALIASES_INITIAL_SIZE	5
81
82typedef struct HostsFile
83{
84	int			m_bufferSize;
85	char	*	m_buffer;
86	FILE	*	m_fp;
87} HostsFile;
88
89
90typedef struct HostsFileInfo
91{
92	struct hostent		m_host;
93	struct HostsFileInfo	*	m_next;
94} HostsFileInfo;
95
96
97#if 0
98#pragma mark == Prototypes ==
99#endif
100
101//===========================================================================================================================
102//	Prototypes
103//===========================================================================================================================
104
105// DLL Exports
106
107BOOL WINAPI		DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
108STDAPI			DllRegisterServer( void );
109STDAPI			DllRegisterServer( void );
110
111
112// NSP SPIs
113
114int	WSPAPI	NSPCleanup( LPGUID inProviderID );
115
116DEBUG_LOCAL int WSPAPI
117	NSPLookupServiceBegin(
118		LPGUID					inProviderID,
119		LPWSAQUERYSETW			inQuerySet,
120		LPWSASERVICECLASSINFOW	inServiceClassInfo,
121		DWORD					inFlags,
122		LPHANDLE				outLookup );
123
124DEBUG_LOCAL int WSPAPI
125	NSPLookupServiceNext(
126		HANDLE			inLookup,
127		DWORD			inFlags,
128		LPDWORD			ioBufferLength,
129		LPWSAQUERYSETW	outResults );
130
131DEBUG_LOCAL int WSPAPI	NSPLookupServiceEnd( HANDLE inLookup );
132
133DEBUG_LOCAL int WSPAPI
134	NSPSetService(
135		LPGUID					inProviderID,
136		LPWSASERVICECLASSINFOW	inServiceClassInfo,
137		LPWSAQUERYSETW			inRegInfo,
138		WSAESETSERVICEOP		inOperation,
139		DWORD					inFlags );
140
141DEBUG_LOCAL int WSPAPI	NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
142DEBUG_LOCAL int WSPAPI	NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
143DEBUG_LOCAL int WSPAPI	NSPGetServiceClassInfo(	LPGUID inProviderID, LPDWORD ioBufSize, LPWSASERVICECLASSINFOW ioServiceClassInfo );
144
145// Private
146
147#define	NSPLock()		EnterCriticalSection( &gLock );
148#define	NSPUnlock()		LeaveCriticalSection( &gLock );
149
150DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
151DEBUG_LOCAL OSStatus	QueryRetain( QueryRef inRef );
152DEBUG_LOCAL OSStatus	QueryRelease( QueryRef inRef );
153
154DEBUG_LOCAL void CALLBACK_COMPAT
155	QueryRecordCallback4(
156		DNSServiceRef		inRef,
157		DNSServiceFlags		inFlags,
158		uint32_t			inInterfaceIndex,
159		DNSServiceErrorType	inErrorCode,
160		const char *		inName,
161		uint16_t			inRRType,
162		uint16_t			inRRClass,
163		uint16_t			inRDataSize,
164		const void *		inRData,
165		uint32_t			inTTL,
166		void *				inContext );
167
168DEBUG_LOCAL void CALLBACK_COMPAT
169	QueryRecordCallback6(
170		DNSServiceRef		inRef,
171		DNSServiceFlags		inFlags,
172		uint32_t			inInterfaceIndex,
173		DNSServiceErrorType	inErrorCode,
174		const char *		inName,
175		uint16_t			inRRType,
176		uint16_t			inRRClass,
177		uint16_t			inRDataSize,
178		const void *		inRData,
179		uint32_t			inTTL,
180		void *				inContext );
181
182DEBUG_LOCAL OSStatus
183	QueryCopyQuerySet(
184		QueryRef 				inRef,
185		const WSAQUERYSETW *	inQuerySet,
186		DWORD 					inQuerySetFlags,
187		WSAQUERYSETW **			outQuerySet,
188		size_t *				outSize );
189
190DEBUG_LOCAL void
191	QueryCopyQuerySetTo(
192		QueryRef 				inRef,
193		const WSAQUERYSETW *	inQuerySet,
194		DWORD 					inQuerySetFlags,
195		WSAQUERYSETW *			outQuerySet );
196
197DEBUG_LOCAL size_t	QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
198
199#if( DEBUG )
200	void	DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
201
202	#define	dlog_query_set( LEVEL, SET )		DebugDumpQuerySet( LEVEL, SET )
203#else
204	#define	dlog_query_set( LEVEL, SET )
205#endif
206
207DEBUG_LOCAL BOOL		InHostsTable( const char * name );
208DEBUG_LOCAL BOOL		IsLocalName( HostsFileInfo * node );
209DEBUG_LOCAL BOOL		IsSameName( HostsFileInfo * node, const char * name );
210DEBUG_LOCAL OSStatus	HostsFileOpen( HostsFile ** self, const char * fname );
211DEBUG_LOCAL OSStatus	HostsFileClose( HostsFile * self );
212DEBUG_LOCAL void		HostsFileInfoFree( HostsFileInfo * info );
213DEBUG_LOCAL OSStatus	HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo );
214DEBUG_LOCAL DWORD		GetScopeId( DWORD ifIndex );
215
216#ifdef ENABLE_REVERSE_LOOKUP
217DEBUG_LOCAL OSStatus	IsReverseLookup( LPCWSTR name, size_t size );
218#endif
219
220
221#if 0
222#pragma mark == Globals ==
223#endif
224
225//===========================================================================================================================
226//	Globals
227//===========================================================================================================================
228
229// {B600E6E9-553B-4a19-8696-335E5C896153}
230DEBUG_LOCAL HINSTANCE				gInstance			= NULL;
231DEBUG_LOCAL wchar_t				*	gNSPName			= L"mdnsNSP";
232DEBUG_LOCAL GUID					gNSPGUID			= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
233DEBUG_LOCAL LONG					gRefCount			= 0;
234DEBUG_LOCAL CRITICAL_SECTION		gLock;
235DEBUG_LOCAL bool					gLockInitialized 	= false;
236DEBUG_LOCAL QueryRef				gQueryList	 		= NULL;
237DEBUG_LOCAL HostsFileInfo		*	gHostsFileInfo		= NULL;
238typedef DWORD
239	( WINAPI * GetAdaptersAddressesFunctionPtr )(
240			ULONG 					inFamily,
241			DWORD 					inFlags,
242			PVOID 					inReserved,
243			PIP_ADAPTER_ADDRESSES 	inAdapter,
244			PULONG					outBufferSize );
245
246DEBUG_LOCAL HMODULE								gIPHelperLibraryInstance			= NULL;
247DEBUG_LOCAL GetAdaptersAddressesFunctionPtr		gGetAdaptersAddressesFunctionPtr	= NULL;
248
249
250
251#if 0
252#pragma mark -
253#endif
254
255//===========================================================================================================================
256//	DllMain
257//===========================================================================================================================
258
259BOOL APIENTRY	DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
260{
261	DEBUG_USE_ONLY( inInstance );
262	DEBUG_UNUSED( inReserved );
263
264	switch( inReason )
265	{
266		case DLL_PROCESS_ATTACH:
267			gInstance = inInstance;
268			gHostsFileInfo	= NULL;
269			debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
270			debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelNotice );
271			dlog( kDebugLevelTrace, "\n" );
272			dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
273
274			break;
275
276		case DLL_PROCESS_DETACH:
277			HostsFileInfoFree( gHostsFileInfo );
278			gHostsFileInfo = NULL;
279			dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
280			break;
281
282		case DLL_THREAD_ATTACH:
283			dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
284			break;
285
286		case DLL_THREAD_DETACH:
287			dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
288			break;
289
290		default:
291			dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
292			break;
293	}
294
295	return( TRUE );
296}
297
298
299//===========================================================================================================================
300//	DllRegisterServer
301//===========================================================================================================================
302
303STDAPI	DllRegisterServer( void )
304{
305	WSADATA		wsd;
306	WCHAR		path[ MAX_PATH ];
307	HRESULT		err;
308
309	dlog( kDebugLevelTrace, "DllRegisterServer\n" );
310
311	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
312	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
313	require_noerr( err, exit );
314
315	// Unregister before registering to workaround an installer
316	// problem during upgrade installs.
317
318	WSCUnInstallNameSpace( &gNSPGUID );
319
320	err = GetModuleFileNameW( gInstance, path, MAX_PATH );
321	err = translate_errno( err != 0, errno_compat(), kUnknownErr );
322	require_noerr( err, exit );
323
324	err = WSCInstallNameSpace( gNSPName, path, NS_DNS, 1, &gNSPGUID );
325	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
326	require_noerr( err, exit );
327
328exit:
329
330	WSACleanup();
331	return( err );
332}
333
334//===========================================================================================================================
335//	DllUnregisterServer
336//===========================================================================================================================
337
338STDAPI	DllUnregisterServer( void )
339{
340	WSADATA		wsd;
341	HRESULT err;
342
343	dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
344
345	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
346	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
347	require_noerr( err, exit );
348
349	err = WSCUnInstallNameSpace( &gNSPGUID );
350	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
351	require_noerr( err, exit );
352
353exit:
354
355	WSACleanup();
356	return err;
357}
358
359
360//===========================================================================================================================
361//	NSPStartup
362//
363//	This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
364//===========================================================================================================================
365
366int WSPAPI	NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
367{
368	OSStatus		err;
369
370	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
371	dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
372
373	// Only initialize if this is the first time NSPStartup is called.
374
375	if( InterlockedIncrement( &gRefCount ) != 1 )
376	{
377		err = NO_ERROR;
378		goto exit;
379	}
380
381	// Initialize our internal state.
382
383	InitializeCriticalSection( &gLock );
384	gLockInitialized = true;
385
386	// Set the size to exclude NSPIoctl because we don't implement it.
387
388	outRoutines->cbSize					= FIELD_OFFSET( NSP_ROUTINE, NSPIoctl );
389	outRoutines->dwMajorVersion			= 4;
390	outRoutines->dwMinorVersion			= 4;
391	outRoutines->NSPCleanup				= NSPCleanup;
392	outRoutines->NSPLookupServiceBegin	= NSPLookupServiceBegin;
393	outRoutines->NSPLookupServiceNext	= NSPLookupServiceNext;
394	outRoutines->NSPLookupServiceEnd	= NSPLookupServiceEnd;
395	outRoutines->NSPSetService			= NSPSetService;
396	outRoutines->NSPInstallServiceClass	= NSPInstallServiceClass;
397	outRoutines->NSPRemoveServiceClass	= NSPRemoveServiceClass;
398	outRoutines->NSPGetServiceClassInfo	= NSPGetServiceClassInfo;
399
400	// See if we can get the address for the GetAdaptersAddresses() API.  This is only in XP, but we want our
401	// code to run on older versions of Windows
402
403	if ( !gIPHelperLibraryInstance )
404	{
405		gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
406		if( gIPHelperLibraryInstance )
407		{
408			gGetAdaptersAddressesFunctionPtr = (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
409		}
410	}
411
412	err = NO_ERROR;
413
414exit:
415	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
416	if( err != NO_ERROR )
417	{
418		NSPCleanup( inProviderID );
419		SetLastError( (DWORD) err );
420		return( SOCKET_ERROR );
421	}
422	return( NO_ERROR );
423}
424
425//===========================================================================================================================
426//	NSPCleanup
427//
428//	This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
429//===========================================================================================================================
430
431int	WSPAPI	NSPCleanup( LPGUID inProviderID )
432{
433	DEBUG_USE_ONLY( inProviderID );
434
435	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
436	dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
437
438	// Only initialize if this is the first time NSPStartup is called.
439
440	if( InterlockedDecrement( &gRefCount ) != 0 )
441	{
442		goto exit;
443	}
444
445	// Stop any outstanding queries.
446
447	if( gLockInitialized )
448	{
449		NSPLock();
450	}
451	while( gQueryList )
452	{
453		check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
454		QueryRelease( gQueryList );
455	}
456	if( gLockInitialized )
457	{
458		NSPUnlock();
459	}
460
461	if( gLockInitialized )
462	{
463		gLockInitialized = false;
464		DeleteCriticalSection( &gLock );
465	}
466
467	if( gIPHelperLibraryInstance )
468	{
469		BOOL ok;
470
471		ok = FreeLibrary( gIPHelperLibraryInstance );
472		check_translated_errno( ok, GetLastError(), kUnknownErr );
473		gIPHelperLibraryInstance = NULL;
474	}
475
476exit:
477	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
478	return( NO_ERROR );
479}
480
481//===========================================================================================================================
482//	NSPLookupServiceBegin
483//
484//	This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
485//	that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
486//	opposed to specifying the query parameters each time.
487//===========================================================================================================================
488
489DEBUG_LOCAL int WSPAPI
490	NSPLookupServiceBegin(
491		LPGUID					inProviderID,
492		LPWSAQUERYSETW			inQuerySet,
493		LPWSASERVICECLASSINFOW	inServiceClassInfo,
494		DWORD					inFlags,
495		LPHANDLE				outLookup )
496{
497	OSStatus		err;
498	QueryRef		obj;
499	LPCWSTR			name;
500	size_t			size;
501	LPCWSTR			p;
502	DWORD           type;
503	DWORD			n;
504	DWORD			i;
505	INT				family;
506	INT				protocol;
507
508	DEBUG_UNUSED( inProviderID );
509	DEBUG_UNUSED( inServiceClassInfo );
510
511	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
512
513	obj = NULL;
514	require_action( inQuerySet, exit, err = WSAEINVAL );
515	name = inQuerySet->lpszServiceInstanceName;
516	require_action_quiet( name, exit, err = WSAEINVAL );
517	require_action( outLookup, exit, err = WSAEINVAL );
518
519	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
520	dlog_query_set( kDebugLevelVerbose, inQuerySet );
521
522	// Check if we can handle this type of request and if we support any of the protocols being requested.
523	// We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
524
525	require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
526
527	type = inQuerySet->dwNameSpace;
528	require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
529
530	n = inQuerySet->dwNumberOfProtocols;
531	if( n > 0 )
532	{
533		require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
534		for( i = 0; i < n; ++i )
535		{
536			family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
537			protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
538			if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
539			{
540				break;
541			}
542		}
543		require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
544	}
545
546	// Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
547	// The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
548	// insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
549	// manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
550	// libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
551
552	for( p = name; *p; ++p ) {}		// Find end of string
553	size = (size_t)( p - name );
554	require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
555
556	p = name + ( size - 1 );
557	p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
558	if	( ( ( p[ 0 ] != '.' )						||
559		( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) )	||
560		( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) )	||
561		( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) )	||
562		( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) )	||
563		( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
564	{
565#ifdef ENABLE_REVERSE_LOOKUP
566
567		err = IsReverseLookup( name, size );
568
569#else
570
571		err = WSASERVICE_NOT_FOUND;
572
573#endif
574
575		require_noerr( err, exit );
576	}
577	else
578	{
579		const char	*	replyDomain;
580		char			translated[ kDNSServiceMaxDomainName ];
581		int				n;
582		int				labels		= 0;
583		const char	*	label[MAX_LABELS];
584		char			text[64];
585
586		n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
587		require_action( n > 0, exit, err = WSASERVICE_NOT_FOUND );
588
589		// <rdar://problem/4050633>
590
591		// Don't resolve multi-label name
592
593		// <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
594		// Add checks for GetNextLabel returning NULL, individual labels being greater than
595		// 64 bytes, and the number of labels being greater than MAX_LABELS
596		replyDomain = translated;
597
598		while (replyDomain && *replyDomain && labels < MAX_LABELS)
599		{
600			label[labels++]	= replyDomain;
601			replyDomain		= GetNextLabel(replyDomain, text);
602		}
603
604		require_action( labels == 2, exit, err = WSASERVICE_NOT_FOUND );
605
606		// <rdar://problem/3936771>
607		//
608		// Check to see if the name of this host is in the hosts table. If so,
609		// don't try and resolve it
610
611		require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
612	}
613
614	// The name ends in .local ( and isn't in the hosts table ), .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
615
616	NSPLock();
617
618	err = QueryCreate( inQuerySet, inFlags, &obj );
619	NSPUnlock();
620	require_noerr( err, exit );
621
622	*outLookup = (HANDLE) obj;
623
624exit:
625	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
626	if( err != NO_ERROR )
627	{
628		SetLastError( (DWORD) err );
629		return( SOCKET_ERROR );
630	}
631	return( NO_ERROR );
632}
633
634//===========================================================================================================================
635//	NSPLookupServiceNext
636//
637//	This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
638//	query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
639//	in the lpqsResults parameter.
640//===========================================================================================================================
641
642DEBUG_LOCAL int WSPAPI
643	NSPLookupServiceNext(
644		HANDLE			inLookup,
645		DWORD			inFlags,
646		LPDWORD			ioSize,
647		LPWSAQUERYSETW	outResults )
648{
649	BOOL			data4;
650	BOOL			data6;
651	OSStatus		err;
652	QueryRef		obj;
653	DWORD			waitResult;
654	size_t			size;
655
656	DEBUG_USE_ONLY( inFlags );
657
658	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
659
660	data4 = FALSE;
661	data6 = FALSE;
662	obj = NULL;
663	NSPLock();
664	err = QueryRetain( (QueryRef) inLookup );
665	require_noerr( err, exit );
666	obj = (QueryRef) inLookup;
667	require_action( ioSize, exit, err = WSAEINVAL );
668	require_action( outResults, exit, err = WSAEINVAL );
669
670	dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
671
672	// Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
673
674	NSPUnlock();
675	waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 2 * 1000 );
676	NSPLock();
677	require_action_quiet( waitResult != ( WAIT_OBJECT_0 ), exit, err = WSA_E_CANCELLED );
678	err = translate_errno( ( waitResult == WAIT_OBJECT_0 + 1 ) || ( waitResult == WAIT_OBJECT_0 + 2 ), (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
679	require_noerr_quiet( err, exit );
680
681	// If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
682
683	if ( waitResult == WAIT_OBJECT_0 + 1 )
684	{
685		data4 = TRUE;
686		data6 = WaitForSingleObject( obj->data6Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
687	}
688
689	// Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
690
691	else if ( waitResult == WAIT_OBJECT_0 + 2 )
692	{
693		data4 = WaitForSingleObject( obj->data4Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
694		data6 = TRUE;
695	}
696
697	if ( data4 )
698	{
699		__try
700		{
701			err = DNSServiceProcessResult(obj->resolver4);
702		}
703		__except( EXCEPTION_EXECUTE_HANDLER )
704		{
705			err = kUnknownErr;
706		}
707
708		require_noerr( err, exit );
709	}
710
711	if ( data6 )
712	{
713		__try
714		{
715			err = DNSServiceProcessResult( obj->resolver6 );
716		}
717		__except( EXCEPTION_EXECUTE_HANDLER )
718		{
719			err = kUnknownErr;
720		}
721
722		require_noerr( err, exit );
723	}
724
725	require_action_quiet( obj->addr4Valid || obj->addr6Valid, exit, err = WSA_E_NO_MORE );
726
727	// Copy the externalized query results to the callers buffer (if it fits).
728
729	size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
730	require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
731
732	QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
733	outResults->dwOutputFlags = RESULT_IS_ADDED;
734	obj->addr4Valid = false;
735	obj->addr6Valid = false;
736
737exit:
738	if( obj )
739	{
740		QueryRelease( obj );
741	}
742	NSPUnlock();
743	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
744	if( err != NO_ERROR )
745	{
746		SetLastError( (DWORD) err );
747		return( SOCKET_ERROR );
748	}
749	return( NO_ERROR );
750}
751
752//===========================================================================================================================
753//	NSPLookupServiceEnd
754//
755//	This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
756//	indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
757//	allocated resources associated with the query.
758//===========================================================================================================================
759
760DEBUG_LOCAL int WSPAPI	NSPLookupServiceEnd( HANDLE inLookup )
761{
762	OSStatus		err;
763
764	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
765
766	dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
767
768	NSPLock();
769	err = QueryRelease( (QueryRef) inLookup );
770	NSPUnlock();
771	require_noerr( err, exit );
772
773exit:
774	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
775	if( err != NO_ERROR )
776	{
777		SetLastError( (DWORD) err );
778		return( SOCKET_ERROR );
779	}
780	return( NO_ERROR );
781}
782
783//===========================================================================================================================
784//	NSPSetService
785//
786//	This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
787//	deregister an instance of a server with our service. For registration, the user needs to associate the server with a
788//	service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
789//	contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
790//===========================================================================================================================
791
792DEBUG_LOCAL int WSPAPI
793	NSPSetService(
794		LPGUID					inProviderID,
795		LPWSASERVICECLASSINFOW	inServiceClassInfo,
796		LPWSAQUERYSETW			inRegInfo,
797		WSAESETSERVICEOP		inOperation,
798		DWORD					inFlags )
799{
800	DEBUG_UNUSED( inProviderID );
801	DEBUG_UNUSED( inServiceClassInfo );
802	DEBUG_UNUSED( inRegInfo );
803	DEBUG_UNUSED( inOperation );
804	DEBUG_UNUSED( inFlags );
805
806	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
807	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
808
809	// We don't allow services to be registered so always return an error.
810
811	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
812	return( WSAEINVAL );
813}
814
815//===========================================================================================================================
816//	NSPInstallServiceClass
817//
818//	This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
819//	is used to define certain characteristics for a group of services. After a service class is registered, an actual
820//	instance of a server may be registered.
821//===========================================================================================================================
822
823DEBUG_LOCAL int WSPAPI	NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
824{
825	DEBUG_UNUSED( inProviderID );
826	DEBUG_UNUSED( inServiceClassInfo );
827
828	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
829	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
830
831	// We don't allow service classes to be installed so always return an error.
832
833	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
834	return( WSA_INVALID_PARAMETER );
835}
836
837//===========================================================================================================================
838//	NSPRemoveServiceClass
839//
840//	This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
841//	class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
842//	service class.
843//===========================================================================================================================
844
845DEBUG_LOCAL int WSPAPI	NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
846{
847	DEBUG_UNUSED( inProviderID );
848	DEBUG_UNUSED( inServiceClassID );
849
850	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
851	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
852
853	// We don't allow service classes to be installed so always return an error.
854
855	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
856	return( WSATYPE_NOT_FOUND );
857}
858
859//===========================================================================================================================
860//	NSPGetServiceClassInfo
861//
862//	This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
863//	a given service class.
864//===========================================================================================================================
865
866DEBUG_LOCAL int WSPAPI	NSPGetServiceClassInfo(	LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
867{
868	DEBUG_UNUSED( inProviderID );
869	DEBUG_UNUSED( ioSize );
870	DEBUG_UNUSED( ioServiceClassInfo );
871
872	dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
873	dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
874
875	// We don't allow service classes to be installed so always return an error.
876
877	dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
878	return( WSATYPE_NOT_FOUND );
879}
880
881#if 0
882#pragma mark -
883#endif
884
885//===========================================================================================================================
886//	QueryCreate
887//
888//	Warning: Assumes the NSP lock is held.
889//===========================================================================================================================
890
891DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
892{
893	OSStatus		err;
894	QueryRef		obj;
895	char			name[ kDNSServiceMaxDomainName ];
896	int				n;
897	QueryRef *		p;
898	SOCKET			s4;
899	SOCKET			s6;
900
901	obj = NULL;
902	check( inQuerySet );
903	check( inQuerySet->lpszServiceInstanceName );
904	check( outRef );
905
906	// Convert the wchar_t name to UTF-8.
907
908	n = WideCharToMultiByte( CP_UTF8, 0, inQuerySet->lpszServiceInstanceName, -1, name, sizeof( name ), NULL, NULL );
909	err = translate_errno( n > 0, (OSStatus) GetLastError(), WSAEINVAL );
910	require_noerr( err, exit );
911
912	// Allocate the object and append it to the list. Append immediately so releases of partial objects work.
913
914	obj = (QueryRef) calloc( 1, sizeof( *obj ) );
915	require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
916
917	obj->refCount = 1;
918
919	for( p = &gQueryList; *p; p = &( *p )->next ) {}	// Find the end of the list.
920	*p = obj;
921
922	// Set up cancel event
923
924	obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
925	require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
926
927	// Set up events to signal when A record data is ready
928
929	obj->data4Event = CreateEvent( NULL, TRUE, FALSE, NULL );
930	require_action( obj->data4Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
931
932	// Start the query.  Handle delay loaded DLL errors.
933
934	__try
935	{
936		err = DNSServiceQueryRecord( &obj->resolver4, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordCallback4, obj );
937	}
938	__except( EXCEPTION_EXECUTE_HANDLER )
939	{
940		err = kUnknownErr;
941	}
942
943	require_noerr( err, exit );
944
945	// Attach the socket to the event
946
947	__try
948	{
949		s4 = DNSServiceRefSockFD(obj->resolver4);
950	}
951	__except( EXCEPTION_EXECUTE_HANDLER )
952	{
953		s4 = INVALID_SOCKET;
954	}
955
956	err = translate_errno( s4 != INVALID_SOCKET, errno_compat(), kUnknownErr );
957	require_noerr( err, exit );
958
959	WSAEventSelect(s4, obj->data4Event, FD_READ|FD_CLOSE);
960
961	// Set up events to signal when AAAA record data is ready
962
963	obj->data6Event = CreateEvent( NULL, TRUE, FALSE, NULL );
964	require_action( obj->data6Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
965
966	// Start the query.  Handle delay loaded DLL errors.
967
968	__try
969	{
970		err = DNSServiceQueryRecord( &obj->resolver6, 0, 0, name, kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordCallback6, obj );
971	}
972	__except( EXCEPTION_EXECUTE_HANDLER )
973	{
974		err = kUnknownErr;
975	}
976
977	require_noerr( err, exit );
978
979	// Attach the socket to the event
980
981	__try
982	{
983		s6 = DNSServiceRefSockFD(obj->resolver6);
984	}
985	__except( EXCEPTION_EXECUTE_HANDLER )
986	{
987		s6 = INVALID_SOCKET;
988	}
989
990	err = translate_errno( s6 != INVALID_SOCKET, errno_compat(), kUnknownErr );
991	require_noerr( err, exit );
992
993	WSAEventSelect(s6, obj->data6Event, FD_READ|FD_CLOSE);
994
995	obj->waitCount = 0;
996	obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
997	obj->waitHandles[ obj->waitCount++ ] = obj->data4Event;
998	obj->waitHandles[ obj->waitCount++ ] = obj->data6Event;
999
1000	check( obj->waitCount == sizeof_array( obj->waitHandles ) );
1001
1002	// Copy the QuerySet so it can be returned later.
1003
1004	obj->querySetFlags = inQuerySetFlags;
1005	inQuerySetFlags = ( inQuerySetFlags & ~( LUP_RETURN_ADDR | LUP_RETURN_BLOB ) ) | LUP_RETURN_NAME;
1006	err = QueryCopyQuerySet( obj, inQuerySet, inQuerySetFlags, &obj->querySet, &obj->querySetSize );
1007	require_noerr( err, exit );
1008
1009	// Success!
1010
1011	*outRef	= obj;
1012	obj 	= NULL;
1013	err 	= NO_ERROR;
1014
1015exit:
1016	if( obj )
1017	{
1018		QueryRelease( obj );
1019	}
1020	return( err );
1021}
1022
1023//===========================================================================================================================
1024//	QueryRetain
1025//
1026//	Warning: Assumes the NSP lock is held.
1027//===========================================================================================================================
1028
1029DEBUG_LOCAL OSStatus	QueryRetain( QueryRef inRef )
1030{
1031	OSStatus		err;
1032	QueryRef		obj;
1033
1034	for( obj = gQueryList; obj; obj = obj->next )
1035	{
1036		if( obj == inRef )
1037		{
1038			break;
1039		}
1040	}
1041	require_action( obj, exit, err = WSA_INVALID_HANDLE );
1042
1043	++inRef->refCount;
1044	err = NO_ERROR;
1045
1046exit:
1047	return( err );
1048}
1049
1050//===========================================================================================================================
1051//	QueryRelease
1052//
1053//	Warning: Assumes the NSP lock is held.
1054//===========================================================================================================================
1055
1056DEBUG_LOCAL OSStatus	QueryRelease( QueryRef inRef )
1057{
1058	OSStatus		err;
1059	QueryRef *		p;
1060	BOOL			ok;
1061
1062	// Find the item in the list.
1063
1064	for( p = &gQueryList; *p; p = &( *p )->next )
1065	{
1066		if( *p == inRef )
1067		{
1068			break;
1069		}
1070	}
1071	require_action( *p, exit, err = WSA_INVALID_HANDLE );
1072
1073	// Signal a cancel to unblock any threads waiting for results.
1074
1075	if( inRef->cancelEvent )
1076	{
1077		ok = SetEvent( inRef->cancelEvent );
1078		check_translated_errno( ok, GetLastError(), WSAEINVAL );
1079	}
1080
1081	// Stop the query.
1082
1083	if( inRef->resolver4 )
1084	{
1085		__try
1086		{
1087			DNSServiceRefDeallocate( inRef->resolver4 );
1088		}
1089		__except( EXCEPTION_EXECUTE_HANDLER )
1090		{
1091		}
1092
1093		inRef->resolver4 = NULL;
1094	}
1095
1096	if ( inRef->resolver6 )
1097	{
1098		__try
1099		{
1100			DNSServiceRefDeallocate( inRef->resolver6 );
1101		}
1102		__except( EXCEPTION_EXECUTE_HANDLER )
1103		{
1104		}
1105
1106		inRef->resolver6 = NULL;
1107	}
1108
1109	// Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
1110
1111	if( --inRef->refCount != 0 )
1112	{
1113		err = NO_ERROR;
1114		goto exit;
1115	}
1116	*p = inRef->next;
1117
1118	// Release resources.
1119
1120	if( inRef->cancelEvent )
1121	{
1122		ok = CloseHandle( inRef->cancelEvent );
1123		check_translated_errno( ok, GetLastError(), WSAEINVAL );
1124	}
1125	if( inRef->data4Event )
1126	{
1127		ok = CloseHandle( inRef->data4Event );
1128		check_translated_errno( ok, GetLastError(), WSAEINVAL );
1129	}
1130	if( inRef->data6Event )
1131	{
1132		ok = CloseHandle( inRef->data6Event );
1133		check_translated_errno( ok, GetLastError(), WSAEINVAL );
1134	}
1135	if( inRef->querySet )
1136	{
1137		free( inRef->querySet );
1138	}
1139	free( inRef );
1140	err = NO_ERROR;
1141
1142exit:
1143	return( err );
1144}
1145
1146//===========================================================================================================================
1147//	QueryRecordCallback4
1148//===========================================================================================================================
1149
1150DEBUG_LOCAL void CALLBACK_COMPAT
1151	QueryRecordCallback4(
1152		DNSServiceRef		inRef,
1153		DNSServiceFlags		inFlags,
1154		uint32_t			inInterfaceIndex,
1155		DNSServiceErrorType	inErrorCode,
1156		const char *		inName,
1157		uint16_t			inRRType,
1158		uint16_t			inRRClass,
1159		uint16_t			inRDataSize,
1160		const void *		inRData,
1161		uint32_t			inTTL,
1162		void *				inContext )
1163{
1164	QueryRef			obj;
1165	const char *		src;
1166	char *				dst;
1167	BOOL				ok;
1168
1169	DEBUG_UNUSED( inFlags );
1170	DEBUG_UNUSED( inInterfaceIndex );
1171	DEBUG_UNUSED( inTTL );
1172
1173	NSPLock();
1174	obj = (QueryRef) inContext;
1175	check( obj );
1176	require_noerr( inErrorCode, exit );
1177	require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
1178	require( inRRClass   == kDNSServiceClass_IN, exit );
1179	require( inRRType    == kDNSServiceType_A, exit );
1180	require( inRDataSize == 4, exit );
1181
1182	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1183		__ROUTINE__, inFlags, inName, inRRType, inRDataSize );
1184
1185	// Copy the name if needed.
1186
1187	if( obj->name[ 0 ] == '\0' )
1188	{
1189		src = inName;
1190		dst = obj->name;
1191		while( *src != '\0' )
1192		{
1193			*dst++ = *src++;
1194		}
1195		*dst = '\0';
1196		obj->nameSize = (size_t)( dst - obj->name );
1197		check( obj->nameSize < sizeof( obj->name ) );
1198	}
1199
1200	// Copy the data.
1201
1202	memcpy( &obj->addr4, inRData, inRDataSize );
1203	obj->addr4Valid = true;
1204	obj->numValidAddrs++;
1205
1206	// Signal that a result is ready.
1207
1208	check( obj->data4Event );
1209	ok = SetEvent( obj->data4Event );
1210	check_translated_errno( ok, GetLastError(), WSAEINVAL );
1211
1212	// Stop the resolver after the first response.
1213
1214	__try
1215	{
1216		DNSServiceRefDeallocate( inRef );
1217	}
1218	__except( EXCEPTION_EXECUTE_HANDLER )
1219	{
1220	}
1221
1222	obj->resolver4 = NULL;
1223
1224exit:
1225	NSPUnlock();
1226}
1227
1228#if 0
1229#pragma mark -
1230#endif
1231
1232
1233//===========================================================================================================================
1234//	QueryRecordCallback6
1235//===========================================================================================================================
1236
1237DEBUG_LOCAL void CALLBACK_COMPAT
1238	QueryRecordCallback6(
1239		DNSServiceRef		inRef,
1240		DNSServiceFlags		inFlags,
1241		uint32_t			inInterfaceIndex,
1242		DNSServiceErrorType	inErrorCode,
1243		const char *		inName,
1244		uint16_t			inRRType,
1245		uint16_t			inRRClass,
1246		uint16_t			inRDataSize,
1247		const void *		inRData,
1248		uint32_t			inTTL,
1249		void *				inContext )
1250{
1251	QueryRef			obj;
1252	const char *		src;
1253	char *				dst;
1254	BOOL				ok;
1255
1256	DEBUG_UNUSED( inFlags );
1257	DEBUG_UNUSED( inInterfaceIndex );
1258	DEBUG_UNUSED( inTTL );
1259
1260	NSPLock();
1261	obj = (QueryRef) inContext;
1262	check( obj );
1263	require_noerr( inErrorCode, exit );
1264	require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
1265	require( inRRClass   == kDNSServiceClass_IN, exit );
1266	require( inRRType    == kDNSServiceType_AAAA, exit );
1267	require( inRDataSize == 16, exit );
1268
1269	dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1270		__ROUTINE__, inFlags, inName, inRRType, inRDataSize );
1271
1272	// Copy the name if needed.
1273
1274	if( obj->name[ 0 ] == '\0' )
1275	{
1276		src = inName;
1277		dst = obj->name;
1278		while( *src != '\0' )
1279		{
1280			*dst++ = *src++;
1281		}
1282		*dst = '\0';
1283		obj->nameSize = (size_t)( dst - obj->name );
1284		check( obj->nameSize < sizeof( obj->name ) );
1285	}
1286
1287	// Copy the data.
1288
1289	memcpy( &obj->addr6, inRData, inRDataSize );
1290
1291	obj->addr6ScopeId = GetScopeId( inInterfaceIndex );
1292	require( obj->addr6ScopeId, exit );
1293	obj->addr6Valid	  = true;
1294	obj->numValidAddrs++;
1295
1296	// Signal that we're done
1297
1298	check( obj->data6Event );
1299	ok = SetEvent( obj->data6Event );
1300	check_translated_errno( ok, GetLastError(), WSAEINVAL );
1301
1302	// Stop the resolver after the first response.
1303
1304	__try
1305	{
1306		DNSServiceRefDeallocate( inRef );
1307	}
1308	__except( EXCEPTION_EXECUTE_HANDLER )
1309	{
1310	}
1311
1312	obj->resolver6 = NULL;
1313
1314exit:
1315
1316
1317
1318	NSPUnlock();
1319}
1320
1321
1322//===========================================================================================================================
1323//	QueryCopyQuerySet
1324//
1325//	Warning: Assumes the NSP lock is held.
1326//===========================================================================================================================
1327
1328DEBUG_LOCAL OSStatus
1329	QueryCopyQuerySet(
1330		QueryRef 				inRef,
1331		const WSAQUERYSETW *	inQuerySet,
1332		DWORD 					inQuerySetFlags,
1333		WSAQUERYSETW **			outQuerySet,
1334		size_t *				outSize )
1335{
1336	OSStatus			err;
1337	size_t				size;
1338	WSAQUERYSETW *		qs;
1339
1340	check( inQuerySet );
1341	check( outQuerySet );
1342
1343	size  = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
1344	qs = (WSAQUERYSETW *) calloc( 1, size );
1345	require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY  );
1346
1347	QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
1348
1349	*outQuerySet = qs;
1350	if( outSize )
1351	{
1352		*outSize = size;
1353	}
1354	qs = NULL;
1355	err = NO_ERROR;
1356
1357exit:
1358	if( qs )
1359	{
1360		free( qs );
1361	}
1362	return( err );
1363}
1364
1365
1366
1367//===========================================================================================================================
1368//	QueryCopyQuerySetTo
1369//
1370//	Warning: Assumes the NSP lock is held.
1371//===========================================================================================================================
1372
1373DEBUG_LOCAL void
1374	QueryCopyQuerySetTo(
1375		QueryRef 				inRef,
1376		const WSAQUERYSETW *	inQuerySet,
1377		DWORD 					inQuerySetFlags,
1378		WSAQUERYSETW *			outQuerySet )
1379{
1380	uint8_t *		dst;
1381	LPCWSTR			s;
1382	LPWSTR			q;
1383	DWORD			n;
1384	DWORD			i;
1385
1386#if( DEBUG )
1387	size_t			debugSize;
1388
1389	debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
1390#endif
1391
1392	check( inQuerySet );
1393	check( outQuerySet );
1394
1395	dst = (uint8_t *) outQuerySet;
1396
1397	// Copy the static portion of the results.
1398
1399	*outQuerySet = *inQuerySet;
1400	dst += sizeof( *inQuerySet );
1401
1402	if( inQuerySetFlags & LUP_RETURN_NAME )
1403	{
1404		s = inQuerySet->lpszServiceInstanceName;
1405		if( s )
1406		{
1407			outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
1408			q = (LPWSTR) dst;
1409			while( ( *q++ = *s++ ) != 0 ) {}
1410			dst = (uint8_t *) q;
1411		}
1412	}
1413	else
1414	{
1415		outQuerySet->lpszServiceInstanceName = NULL;
1416	}
1417
1418	if( inQuerySet->lpServiceClassId )
1419	{
1420		outQuerySet->lpServiceClassId  = (LPGUID) dst;
1421		*outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
1422		dst += sizeof( *inQuerySet->lpServiceClassId );
1423	}
1424
1425	if( inQuerySet->lpVersion )
1426	{
1427		outQuerySet->lpVersion  = (LPWSAVERSION) dst;
1428		*outQuerySet->lpVersion = *inQuerySet->lpVersion;
1429		dst += sizeof( *inQuerySet->lpVersion );
1430	}
1431
1432	s = inQuerySet->lpszComment;
1433	if( s )
1434	{
1435		outQuerySet->lpszComment = (LPWSTR) dst;
1436		q = (LPWSTR) dst;
1437		while( ( *q++ = *s++ ) != 0 ) {}
1438		dst = (uint8_t *) q;
1439	}
1440
1441	if( inQuerySet->lpNSProviderId )
1442	{
1443		outQuerySet->lpNSProviderId  = (LPGUID) dst;
1444		*outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
1445		dst += sizeof( *inQuerySet->lpNSProviderId );
1446	}
1447
1448	s = inQuerySet->lpszContext;
1449	if( s )
1450	{
1451		outQuerySet->lpszContext = (LPWSTR) dst;
1452		q = (LPWSTR) dst;
1453		while( ( *q++ = *s++ ) != 0 ) {}
1454		dst = (uint8_t *) q;
1455	}
1456
1457	n = inQuerySet->dwNumberOfProtocols;
1458
1459	if( n > 0 )
1460	{
1461		check( inQuerySet->lpafpProtocols );
1462
1463		outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
1464		for( i = 0; i < n; ++i )
1465		{
1466			outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
1467			dst += sizeof( *inQuerySet->lpafpProtocols );
1468		}
1469	}
1470
1471	s = inQuerySet->lpszQueryString;
1472	if( s )
1473	{
1474		outQuerySet->lpszQueryString = (LPWSTR) dst;
1475		q = (LPWSTR) dst;
1476		while( ( *q++ = *s++ ) != 0 ) {}
1477		dst = (uint8_t *) q;
1478	}
1479
1480	// Copy the address(es).
1481
1482	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && ( inRef->numValidAddrs > 0 ) )
1483	{
1484		struct sockaddr_in	*	addr4;
1485		struct sockaddr_in6	*	addr6;
1486		int						index;
1487
1488		outQuerySet->dwNumberOfCsAddrs	= inRef->numValidAddrs;
1489		outQuerySet->lpcsaBuffer 		= (LPCSADDR_INFO) dst;
1490		dst 							+= ( sizeof( *outQuerySet->lpcsaBuffer ) ) * ( inRef->numValidAddrs ) ;
1491		index							= 0;
1492
1493		if ( inRef->addr4Valid )
1494		{
1495			outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr 			= NULL;
1496			outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength		= 0;
1497
1498			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr 		= (LPSOCKADDR) dst;
1499			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength	= sizeof( struct sockaddr_in );
1500
1501			addr4 															= (struct sockaddr_in *) dst;
1502			memset( addr4, 0, sizeof( *addr4 ) );
1503			addr4->sin_family												= AF_INET;
1504			memcpy( &addr4->sin_addr, &inRef->addr4, 4 );
1505			dst 															+= sizeof( *addr4 );
1506
1507			outQuerySet->lpcsaBuffer[ index ].iSocketType 					= AF_INET;		// Emulate Tcpip NSP
1508			outQuerySet->lpcsaBuffer[ index ].iProtocol						= IPPROTO_UDP;	// Emulate Tcpip NSP
1509
1510			index++;
1511		}
1512
1513		if ( inRef->addr6Valid )
1514		{
1515			outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr 			= NULL;
1516			outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength		= 0;
1517
1518			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr 		= (LPSOCKADDR) dst;
1519			outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength	= sizeof( struct sockaddr_in6 );
1520
1521			addr6 															= (struct sockaddr_in6 *) dst;
1522			memset( addr6, 0, sizeof( *addr6 ) );
1523			addr6->sin6_family												= AF_INET6;
1524			addr6->sin6_scope_id											= inRef->addr6ScopeId;
1525			memcpy( &addr6->sin6_addr, &inRef->addr6, 16 );
1526			dst 															+= sizeof( *addr6 );
1527
1528			outQuerySet->lpcsaBuffer[ index ].iSocketType 					= AF_INET6;		// Emulate Tcpip NSP
1529			outQuerySet->lpcsaBuffer[ index ].iProtocol						= IPPROTO_UDP;	// Emulate Tcpip NSP
1530		}
1531	}
1532	else
1533	{
1534		outQuerySet->dwNumberOfCsAddrs	= 0;
1535		outQuerySet->lpcsaBuffer 		= NULL;
1536	}
1537
1538	// Copy the hostent blob.
1539
1540	if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
1541	{
1542		uint8_t *				base;
1543		struct hostent *		he;
1544		uintptr_t *				p;
1545
1546		outQuerySet->lpBlob	 = (LPBLOB) dst;
1547		dst 				+= sizeof( *outQuerySet->lpBlob );
1548
1549		base = dst;
1550		he	 = (struct hostent *) dst;
1551		dst += sizeof( *he );
1552
1553		he->h_name = (char *)( dst - base );
1554		memcpy( dst, inRef->name, inRef->nameSize + 1 );
1555		dst += ( inRef->nameSize + 1 );
1556
1557		he->h_aliases 	= (char **)( dst - base );
1558		p	  			= (uintptr_t *) dst;
1559		*p++  			= 0;
1560		dst 		 	= (uint8_t *) p;
1561
1562		he->h_addrtype 	= AF_INET;
1563		he->h_length	= 4;
1564
1565		he->h_addr_list	= (char **)( dst - base );
1566		p	  			= (uintptr_t *) dst;
1567		dst 		   += ( 2 * sizeof( *p ) );
1568		*p++			= (uintptr_t)( dst - base );
1569		*p++			= 0;
1570		p	  			= (uintptr_t *) dst;
1571		*p++			= (uintptr_t) inRef->addr4;
1572		dst 		 	= (uint8_t *) p;
1573
1574		outQuerySet->lpBlob->cbSize 	= (ULONG)( dst - base );
1575		outQuerySet->lpBlob->pBlobData	= (BYTE *) base;
1576	}
1577	dlog_query_set( kDebugLevelVerbose, outQuerySet );
1578
1579	check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
1580}
1581
1582//===========================================================================================================================
1583//	QueryCopyQuerySetSize
1584//
1585//	Warning: Assumes the NSP lock is held.
1586//===========================================================================================================================
1587
1588DEBUG_LOCAL size_t	QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
1589{
1590	size_t		size;
1591	LPCWSTR		s;
1592	LPCWSTR		p;
1593
1594	check( inRef );
1595	check( inQuerySet );
1596
1597	// Calculate the size of the static portion of the results.
1598
1599	size = sizeof( *inQuerySet );
1600
1601	if( inQuerySetFlags & LUP_RETURN_NAME )
1602	{
1603		s = inQuerySet->lpszServiceInstanceName;
1604		if( s )
1605		{
1606			for( p = s; *p; ++p ) {}
1607			size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1608		}
1609	}
1610
1611	if( inQuerySet->lpServiceClassId )
1612	{
1613		size += sizeof( *inQuerySet->lpServiceClassId );
1614	}
1615
1616	if( inQuerySet->lpVersion )
1617	{
1618		size += sizeof( *inQuerySet->lpVersion );
1619	}
1620
1621	s = inQuerySet->lpszComment;
1622	if( s )
1623	{
1624		for( p = s; *p; ++p ) {}
1625		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1626	}
1627
1628	if( inQuerySet->lpNSProviderId )
1629	{
1630		size += sizeof( *inQuerySet->lpNSProviderId );
1631	}
1632
1633	s = inQuerySet->lpszContext;
1634	if( s )
1635	{
1636		for( p = s; *p; ++p ) {}
1637		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1638	}
1639
1640	size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
1641
1642	s = inQuerySet->lpszQueryString;
1643	if( s )
1644	{
1645		for( p = s; *p; ++p ) {}
1646		size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
1647	}
1648
1649	// Calculate the size of the address(es).
1650
1651	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr4Valid )
1652	{
1653		size += sizeof( *inQuerySet->lpcsaBuffer );
1654		size += sizeof( struct sockaddr_in );
1655	}
1656
1657	if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr6Valid )
1658	{
1659		size += sizeof( *inQuerySet->lpcsaBuffer );
1660		size += sizeof( struct sockaddr_in6 );
1661	}
1662
1663	// Calculate the size of the hostent blob.
1664
1665	if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
1666	{
1667		size += sizeof( *inQuerySet->lpBlob );	// Blob ptr/size structure
1668		size += sizeof( struct hostent );		// Old-style hostent structure
1669		size += ( inRef->nameSize + 1 );		// Name and null terminator
1670		size += 4;								// Alias list terminator (0 offset)
1671		size += 4;								// Offset to address.
1672		size += 4;								// Address list terminator (0 offset)
1673		size += 4;								// IPv4 address
1674	}
1675	return( size );
1676}
1677
1678#if 0
1679#pragma mark -
1680#endif
1681
1682#if( DEBUG )
1683//===========================================================================================================================
1684//	DebugDumpQuerySet
1685//===========================================================================================================================
1686
1687#define	DebugSocketFamilyToString( FAM )	( ( FAM ) == AF_INET )  ? "AF_INET"  : \
1688											( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1689
1690#define	DebugSocketProtocolToString( PROTO )	( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1691												( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1692
1693#define	DebugNameSpaceToString( NS )			( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1694
1695void	DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
1696{
1697	DWORD		i;
1698
1699	check( inQuerySet );
1700
1701	// Fixed portion of the QuerySet.
1702
1703	dlog( inLevel, "QuerySet:\n" );
1704	dlog( inLevel, "    dwSize:                  %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
1705	if( inQuerySet->lpszServiceInstanceName )
1706	{
1707		dlog( inLevel, "    lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
1708	}
1709	else
1710	{
1711		dlog( inLevel, "    lpszServiceInstanceName: <null>\n" );
1712	}
1713	if( inQuerySet->lpServiceClassId )
1714	{
1715		dlog( inLevel, "    lpServiceClassId:        %U\n", inQuerySet->lpServiceClassId );
1716	}
1717	else
1718	{
1719		dlog( inLevel, "    lpServiceClassId:        <null>\n" );
1720	}
1721	if( inQuerySet->lpVersion )
1722	{
1723		dlog( inLevel, "    lpVersion:\n" );
1724		dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->dwVersion );
1725		dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->ecHow );
1726	}
1727	else
1728	{
1729		dlog( inLevel, "    lpVersion:               <null>\n" );
1730	}
1731	if( inQuerySet->lpszComment )
1732	{
1733		dlog( inLevel, "    lpszComment:             %S\n", inQuerySet->lpszComment );
1734	}
1735	else
1736	{
1737		dlog( inLevel, "    lpszComment:             <null>\n" );
1738	}
1739	dlog( inLevel, "    dwNameSpace:             %d %s\n", inQuerySet->dwNameSpace,
1740		DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
1741	if( inQuerySet->lpNSProviderId )
1742	{
1743		dlog( inLevel, "    lpNSProviderId:          %U\n", inQuerySet->lpNSProviderId );
1744	}
1745	else
1746	{
1747		dlog( inLevel, "    lpNSProviderId:          <null>\n" );
1748	}
1749	if( inQuerySet->lpszContext )
1750	{
1751		dlog( inLevel, "    lpszContext:             %S\n", inQuerySet->lpszContext );
1752	}
1753	else
1754	{
1755		dlog( inLevel, "    lpszContext:             <null>\n" );
1756	}
1757	dlog( inLevel, "    dwNumberOfProtocols:     %d\n", inQuerySet->dwNumberOfProtocols );
1758	dlog( inLevel, "    lpafpProtocols:          %s\n", inQuerySet->lpafpProtocols ? "" : "<null>" );
1759	for( i = 0; i < inQuerySet->dwNumberOfProtocols; ++i )
1760	{
1761		if( i != 0 )
1762		{
1763			dlog( inLevel, "\n" );
1764		}
1765		dlog( inLevel, "        iAddressFamily:          %d %s\n", inQuerySet->lpafpProtocols[ i ].iAddressFamily,
1766			DebugSocketFamilyToString( inQuerySet->lpafpProtocols[ i ].iAddressFamily ) );
1767		dlog( inLevel, "        iProtocol:               %d %s\n", inQuerySet->lpafpProtocols[ i ].iProtocol,
1768			DebugSocketProtocolToString( inQuerySet->lpafpProtocols[ i ].iProtocol ) );
1769	}
1770	if( inQuerySet->lpszQueryString )
1771	{
1772		dlog( inLevel, "    lpszQueryString:         %S\n", inQuerySet->lpszQueryString );
1773	}
1774	else
1775	{
1776		dlog( inLevel, "    lpszQueryString:         <null>\n" );
1777	}
1778	dlog( inLevel, "    dwNumberOfCsAddrs:       %d\n", inQuerySet->dwNumberOfCsAddrs );
1779	dlog( inLevel, "    lpcsaBuffer:             %s\n", inQuerySet->lpcsaBuffer ? "" : "<null>" );
1780	for( i = 0; i < inQuerySet->dwNumberOfCsAddrs; ++i )
1781	{
1782		if( i != 0 )
1783		{
1784			dlog( inLevel, "\n" );
1785		}
1786		if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr &&
1787			( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
1788		{
1789			dlog( inLevel, "        LocalAddr:               %##a\n",
1790				inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
1791		}
1792		else
1793		{
1794			dlog( inLevel, "        LocalAddr:               <null/empty>\n" );
1795		}
1796		if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr &&
1797			( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
1798		{
1799			dlog( inLevel, "        RemoteAddr:              %##a\n",
1800				inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
1801		}
1802		else
1803		{
1804			dlog( inLevel, "        RemoteAddr:              <null/empty>\n" );
1805		}
1806		dlog( inLevel, "        iSocketType:             %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
1807		dlog( inLevel, "        iProtocol:               %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
1808	}
1809	dlog( inLevel, "    dwOutputFlags:           %d\n", inQuerySet->dwOutputFlags );
1810
1811	// Blob portion of the QuerySet.
1812
1813	if( inQuerySet->lpBlob )
1814	{
1815		dlog( inLevel, "    lpBlob:\n" );
1816		dlog( inLevel, "        cbSize:                  %ld\n", inQuerySet->lpBlob->cbSize );
1817		dlog( inLevel, "        pBlobData:               %#p\n", inQuerySet->lpBlob->pBlobData );
1818		dloghex( inLevel, 12, NULL, 0, 0, NULL, 0,
1819			inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->cbSize,
1820			kDebugFlagsNone, NULL, 0 );
1821	}
1822	else
1823	{
1824		dlog( inLevel, "    lpBlob:                  <null>\n" );
1825	}
1826}
1827#endif
1828
1829
1830//===========================================================================================================================
1831//	InHostsTable
1832//===========================================================================================================================
1833
1834DEBUG_LOCAL BOOL
1835InHostsTable( const char * name )
1836{
1837	HostsFileInfo	*	node;
1838	BOOL				ret = FALSE;
1839	OSStatus			err;
1840
1841	check( name );
1842
1843	if ( gHostsFileInfo == NULL )
1844	{
1845		TCHAR				systemDirectory[MAX_PATH];
1846		TCHAR				hFileName[MAX_PATH];
1847		HostsFile		*	hFile;
1848
1849		GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) );
1850		sprintf( hFileName, "%s\\drivers\\etc\\hosts", systemDirectory );
1851		err = HostsFileOpen( &hFile, hFileName );
1852		require_noerr( err, exit );
1853
1854		while ( HostsFileNext( hFile, &node ) == 0 )
1855		{
1856			if ( IsLocalName( node ) )
1857			{
1858				node->m_next = gHostsFileInfo;
1859				gHostsFileInfo = node;
1860			}
1861			else
1862			{
1863				HostsFileInfoFree( node );
1864			}
1865		}
1866
1867		HostsFileClose( hFile );
1868	}
1869
1870	for ( node = gHostsFileInfo; node; node = node->m_next )
1871	{
1872		if ( IsSameName( node, name ) )
1873		{
1874			ret = TRUE;
1875			break;
1876		}
1877	}
1878
1879exit:
1880
1881	return ret;
1882}
1883
1884
1885//===========================================================================================================================
1886//	IsLocalName
1887//===========================================================================================================================
1888
1889DEBUG_LOCAL BOOL
1890IsLocalName( HostsFileInfo * node )
1891{
1892	BOOL ret = TRUE;
1893
1894	check( node );
1895
1896	if ( strstr( node->m_host.h_name, ".local" ) == NULL )
1897	{
1898		int i;
1899
1900		for ( i = 0; node->m_host.h_aliases[i]; i++ )
1901		{
1902			if ( strstr( node->m_host.h_aliases[i], ".local" ) )
1903			{
1904				goto exit;
1905			}
1906		}
1907
1908		ret = FALSE;
1909	}
1910
1911exit:
1912
1913	return ret;
1914}
1915
1916
1917//===========================================================================================================================
1918//	IsSameName
1919//===========================================================================================================================
1920
1921DEBUG_LOCAL BOOL
1922IsSameName( HostsFileInfo * node, const char * name )
1923{
1924	BOOL ret = TRUE;
1925
1926	check( node );
1927	check( name );
1928
1929	if ( strcmp( node->m_host.h_name, name ) != 0 )
1930	{
1931		int i;
1932
1933		for ( i = 0; node->m_host.h_aliases[i]; i++ )
1934		{
1935			if ( strcmp( node->m_host.h_aliases[i], name ) == 0 )
1936			{
1937				goto exit;
1938			}
1939		}
1940
1941		ret = FALSE;
1942	}
1943
1944exit:
1945
1946	return ret;
1947}
1948
1949
1950//===========================================================================================================================
1951//	HostsFileOpen
1952//===========================================================================================================================
1953
1954DEBUG_LOCAL OSStatus
1955HostsFileOpen( HostsFile ** self, const char * fname )
1956{
1957	OSStatus err = kNoErr;
1958
1959	*self = (HostsFile*) malloc( sizeof( HostsFile ) );
1960	require_action( *self, exit, err = kNoMemoryErr );
1961	memset( *self, 0, sizeof( HostsFile ) );
1962
1963	(*self)->m_bufferSize = BUFFER_INITIAL_SIZE;
1964	(*self)->m_buffer = (char*) malloc( (*self)->m_bufferSize );
1965	require_action( (*self)->m_buffer, exit, err = kNoMemoryErr );
1966
1967	// check malloc
1968
1969	(*self)->m_fp = fopen( fname, "r" );
1970	require_action( (*self)->m_fp, exit, err = kUnknownErr );
1971
1972exit:
1973
1974	if ( err && *self )
1975	{
1976		HostsFileClose( *self );
1977		*self = NULL;
1978	}
1979
1980	return err;
1981}
1982
1983
1984//===========================================================================================================================
1985//	HostsFileClose
1986//===========================================================================================================================
1987
1988DEBUG_LOCAL OSStatus
1989HostsFileClose( HostsFile * self )
1990{
1991	check( self );
1992
1993	if ( self->m_buffer )
1994	{
1995		free( self->m_buffer );
1996		self->m_buffer = NULL;
1997	}
1998
1999	if ( self->m_fp )
2000	{
2001		fclose( self->m_fp );
2002		self->m_fp = NULL;
2003	}
2004
2005	free( self );
2006
2007	return kNoErr;
2008}
2009
2010
2011//===========================================================================================================================
2012//	HostsFileInfoFree
2013//===========================================================================================================================
2014
2015DEBUG_LOCAL void
2016HostsFileInfoFree( HostsFileInfo * info )
2017{
2018	while ( info )
2019	{
2020		HostsFileInfo * next = info->m_next;
2021
2022		if ( info->m_host.h_addr_list )
2023		{
2024			if ( info->m_host.h_addr_list[0] )
2025			{
2026				free( info->m_host.h_addr_list[0] );
2027				info->m_host.h_addr_list[0] = NULL;
2028			}
2029
2030			free( info->m_host.h_addr_list );
2031			info->m_host.h_addr_list = NULL;
2032		}
2033
2034		if ( info->m_host.h_aliases )
2035		{
2036			int i;
2037
2038			for ( i = 0; info->m_host.h_aliases[i]; i++ )
2039			{
2040				free( info->m_host.h_aliases[i] );
2041			}
2042
2043			free( info->m_host.h_aliases );
2044		}
2045
2046		if ( info->m_host.h_name )
2047		{
2048			free( info->m_host.h_name );
2049			info->m_host.h_name = NULL;
2050		}
2051
2052		free( info );
2053
2054		info = next;
2055	}
2056}
2057
2058
2059//===========================================================================================================================
2060//	HostsFileNext
2061//===========================================================================================================================
2062
2063DEBUG_LOCAL OSStatus
2064HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo )
2065{
2066	struct sockaddr_in6	addr_6;
2067	struct sockaddr_in	addr_4;
2068	int					numAliases = ALIASES_INITIAL_SIZE;
2069	char			*	line;
2070	char			*	tok;
2071	int					dwSize;
2072	int					idx;
2073	int					i;
2074	short				family;
2075	OSStatus			err = kNoErr;
2076
2077	check( self );
2078	check( self->m_fp );
2079	check( hInfo );
2080
2081	idx	= 0;
2082
2083	*hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) );
2084	require_action( *hInfo, exit, err = kNoMemoryErr );
2085	memset( *hInfo, 0, sizeof( HostsFileInfo ) );
2086
2087	for ( ; ; )
2088	{
2089		line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp );
2090
2091		if ( line == NULL )
2092		{
2093			err = 1;
2094			goto exit;
2095		}
2096
2097		// If there's no eol and no eof, then we didn't get the whole line
2098
2099		if ( !strchr( line, '\n' ) && !feof( self->m_fp ) )
2100		{
2101			int			bufferSize;
2102			char	*	buffer;
2103
2104			/* Try and allocate space for longer line */
2105
2106			bufferSize	= self->m_bufferSize * 2;
2107			buffer		= (char*) realloc( self->m_buffer, bufferSize );
2108			require_action( buffer, exit, err = kNoMemoryErr );
2109			self->m_bufferSize	= bufferSize;
2110			self->m_buffer		= buffer;
2111			idx					= (int) strlen( self->m_buffer );
2112
2113			continue;
2114		}
2115
2116		line	= self->m_buffer;
2117		idx		= 0;
2118
2119		if (*line == '#')
2120		{
2121			continue;
2122		}
2123
2124		// Get rid of either comments or eol characters
2125
2126		if (( tok = strpbrk(line, "#\n")) != NULL )
2127		{
2128			*tok = '\0';
2129		}
2130
2131		// Make sure there is some whitespace on this line
2132
2133		if (( tok = strpbrk(line, " \t")) == NULL )
2134		{
2135			continue;
2136		}
2137
2138		// Create two strings, where p == the IP Address and tok is the name list
2139
2140		*tok++ = '\0';
2141
2142		while ( *tok == ' ' || *tok == '\t')
2143		{
2144			tok++;
2145		}
2146
2147		// Now we have the name
2148
2149		(*hInfo)->m_host.h_name = (char*) malloc( strlen( tok ) + 1 );
2150		require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr );
2151		strcpy( (*hInfo)->m_host.h_name, tok );
2152
2153		// Now create the address (IPv6/IPv4)
2154
2155		addr_6.sin6_family	= family = AF_INET6;
2156		dwSize				= sizeof( addr_6 );
2157
2158		if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 )
2159		{
2160			addr_4.sin_family = family = AF_INET;
2161			dwSize = sizeof( addr_4 );
2162
2163			if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 )
2164			{
2165				continue;
2166			}
2167		}
2168
2169		(*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 );
2170		require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr );
2171
2172		if ( family == AF_INET6 )
2173		{
2174			(*hInfo)->m_host.h_length		= (short) sizeof( addr_6.sin6_addr );
2175			(*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
2176			require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
2177			memmove( (*hInfo)->m_host.h_addr_list[0], &addr_6.sin6_addr, sizeof( addr_6.sin6_addr ) );
2178
2179		}
2180		else
2181		{
2182			(*hInfo)->m_host.h_length		= (short) sizeof( addr_4.sin_addr );
2183			(*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
2184			require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
2185			memmove( (*hInfo)->m_host.h_addr_list[0], &addr_4.sin_addr, sizeof( addr_4.sin_addr ) );
2186		}
2187
2188		(*hInfo)->m_host.h_addr_list[1] = NULL;
2189		(*hInfo)->m_host.h_addrtype		= family;
2190
2191		// Now get the aliases
2192
2193		if ((tok = strpbrk(tok, " \t")) != NULL)
2194		{
2195			*tok++ = '\0';
2196		}
2197
2198		i = 0;
2199
2200		(*hInfo)->m_host.h_aliases		= (char**) malloc( sizeof(char**) * numAliases );
2201		require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
2202		(*hInfo)->m_host.h_aliases[0]	= NULL;
2203
2204		while ( tok && *tok )
2205		{
2206			// Skip over the whitespace, waiting for the start of the next alias name
2207
2208			if (*tok == ' ' || *tok == '\t')
2209			{
2210				tok++;
2211				continue;
2212			}
2213
2214			// Check to make sure we don't exhaust the alias buffer
2215
2216			if ( i >= ( numAliases - 1 ) )
2217			{
2218				numAliases = numAliases * 2;
2219				(*hInfo)->m_host.h_aliases = (char**) realloc( (*hInfo)->m_host.h_aliases, numAliases * sizeof( char** ) );
2220				require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
2221			}
2222
2223			(*hInfo)->m_host.h_aliases[i] = (char*) malloc( strlen( tok ) + 1 );
2224			require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr );
2225
2226			strcpy( (*hInfo)->m_host.h_aliases[i], tok );
2227
2228			if (( tok = strpbrk( tok, " \t")) != NULL )
2229			{
2230				*tok++ = '\0';
2231			}
2232
2233			(*hInfo)->m_host.h_aliases[++i] = NULL;
2234		}
2235
2236		break;
2237	}
2238
2239exit:
2240
2241	if ( err && ( *hInfo ) )
2242	{
2243		HostsFileInfoFree( *hInfo );
2244		*hInfo = NULL;
2245	}
2246
2247	return err;
2248}
2249
2250
2251#ifdef ENABLE_REVERSE_LOOKUP
2252//===========================================================================================================================
2253//	IsReverseLookup
2254//===========================================================================================================================
2255
2256DEBUG_LOCAL OSStatus
2257IsReverseLookup( LPCWSTR name, size_t size )
2258{
2259	LPCWSTR		p;
2260	OSStatus	err = kNoErr;
2261
2262	// IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
2263	require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
2264
2265	p = name + ( size - 1 );
2266	p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2267
2268	if	( ( ( p[ 0 ] != '.' )							||
2269		( ( p[ 1 ] != '0' ) )							||
2270		( ( p[ 2 ] != '.' ) )							||
2271		( ( p[ 3 ] != '8' ) )							||
2272		( ( p[ 4 ] != '.' ) )							||
2273		( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) )		||
2274		( ( p[ 6 ] != '.' ) )							||
2275		( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) )		||
2276		( ( p[ 8 ] != '.' ) )							||
2277		( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) )		||
2278		( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) )	||
2279		( ( p[ 11 ] != '6' ) )							||
2280		( ( p[ 12 ] != '.' ) )							||
2281		( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) )	||
2282		( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) )	||
2283		( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) )	||
2284		( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
2285	{
2286		require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
2287
2288		p = name + ( size - 1 );
2289		p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2290
2291		require_action_quiet( ( ( p[ 0 ] == '.' )						 &&
2292								( ( p[ 1 ] == '2' ) )							&&
2293								( ( p[ 2 ] == '5' ) )							&&
2294								( ( p[ 3 ] == '4' ) )							&&
2295								( ( p[ 4 ] == '.' ) )							&&
2296								( ( p[ 5 ] == '1' ) )							&&
2297								( ( p[ 6 ] == '6' ) )							&&
2298								( ( p[ 7 ] == '9' ) )							&&
2299								( ( p[ 8 ] == '.' ) )							&&
2300								( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) )		&&
2301								( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) )	&&
2302								( ( p[ 11 ] == '-' ) )							&&
2303								( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) )	&&
2304								( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) )	&&
2305								( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) )	&&
2306								( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) )	&&
2307								( ( p[ 16 ] == '.' ) )							&&
2308								( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) )	&&
2309								( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) )	&&
2310								( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) )	&&
2311								( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
2312								exit, err = WSASERVICE_NOT_FOUND );
2313	}
2314
2315	// It's a reverse lookup
2316
2317	check( err == kNoErr );
2318
2319exit:
2320
2321	return err;
2322}
2323#endif
2324
2325//===========================================================================================================================
2326//	GetScopeId
2327//===========================================================================================================================
2328
2329DEBUG_LOCAL DWORD
2330GetScopeId( DWORD ifIndex )
2331{
2332	DWORD						err;
2333	int							i;
2334	DWORD						flags;
2335	struct ifaddrs *			head;
2336	struct ifaddrs **			next;
2337	IP_ADAPTER_ADDRESSES *		iaaList;
2338	ULONG						iaaListSize;
2339	IP_ADAPTER_ADDRESSES *		iaa;
2340	DWORD						scopeId = 0;
2341
2342	head	= NULL;
2343	next	= &head;
2344	iaaList	= NULL;
2345
2346	require( gGetAdaptersAddressesFunctionPtr, exit );
2347
2348	// Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2349	// This loops to handle the case where the interface changes in the window after getting the size, but before the
2350	// second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2351
2352	flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
2353	i = 0;
2354	for( ;; )
2355	{
2356		iaaListSize = 0;
2357		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
2358		check( err == ERROR_BUFFER_OVERFLOW );
2359		check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
2360
2361		iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
2362		require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
2363
2364		err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
2365		if( err == ERROR_SUCCESS ) break;
2366
2367		free( iaaList );
2368		iaaList = NULL;
2369		++i;
2370		require( i < 100, exit );
2371		dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
2372	}
2373
2374	for( iaa = iaaList; iaa; iaa = iaa->Next )
2375	{
2376		DWORD ipv6IfIndex;
2377
2378		if ( iaa->IfIndex > 0xFFFFFF )
2379		{
2380			continue;
2381		}
2382		if ( iaa->Ipv6IfIndex > 0xFF )
2383		{
2384			continue;
2385		}
2386
2387		// For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
2388		// following code to crash when iterating through the prefix list.  This seems
2389		// to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
2390		// This shouldn't happen according to Microsoft docs which states:
2391		//
2392		//     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
2393		//
2394		// So the data structure seems to be corrupted when we return from
2395		// GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
2396		// sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
2397		// modify iaa to have the correct values.
2398
2399		if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
2400		{
2401			ipv6IfIndex = iaa->Ipv6IfIndex;
2402		}
2403		else
2404		{
2405			ipv6IfIndex	= 0;
2406		}
2407
2408		// Skip psuedo and tunnel interfaces.
2409
2410		if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
2411		{
2412			continue;
2413		}
2414
2415		if ( iaa->IfIndex == ifIndex )
2416		{
2417			scopeId = iaa->Ipv6IfIndex;
2418			break;
2419		}
2420	}
2421
2422exit:
2423
2424	if( iaaList )
2425	{
2426		free( iaaList );
2427	}
2428
2429	return scopeId;
2430}
2431