• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
53 typedef struct	Query *		QueryRef;
54 typedef struct	Query		Query;
55 struct	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 
82 typedef struct HostsFile
83 {
84 	int			m_bufferSize;
85 	char	*	m_buffer;
86 	FILE	*	m_fp;
87 } HostsFile;
88 
89 
90 typedef 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 
107 BOOL WINAPI		DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
108 STDAPI			DllRegisterServer( void );
109 STDAPI			DllRegisterServer( void );
110 
111 
112 // NSP SPIs
113 
114 int	WSPAPI	NSPCleanup( LPGUID inProviderID );
115 
116 DEBUG_LOCAL int WSPAPI
117 	NSPLookupServiceBegin(
118 		LPGUID					inProviderID,
119 		LPWSAQUERYSETW			inQuerySet,
120 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
121 		DWORD					inFlags,
122 		LPHANDLE				outLookup );
123 
124 DEBUG_LOCAL int WSPAPI
125 	NSPLookupServiceNext(
126 		HANDLE			inLookup,
127 		DWORD			inFlags,
128 		LPDWORD			ioBufferLength,
129 		LPWSAQUERYSETW	outResults );
130 
131 DEBUG_LOCAL int WSPAPI	NSPLookupServiceEnd( HANDLE inLookup );
132 
133 DEBUG_LOCAL int WSPAPI
134 	NSPSetService(
135 		LPGUID					inProviderID,
136 		LPWSASERVICECLASSINFOW	inServiceClassInfo,
137 		LPWSAQUERYSETW			inRegInfo,
138 		WSAESETSERVICEOP		inOperation,
139 		DWORD					inFlags );
140 
141 DEBUG_LOCAL int WSPAPI	NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
142 DEBUG_LOCAL int WSPAPI	NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
143 DEBUG_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 
150 DEBUG_LOCAL OSStatus	QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
151 DEBUG_LOCAL OSStatus	QueryRetain( QueryRef inRef );
152 DEBUG_LOCAL OSStatus	QueryRelease( QueryRef inRef );
153 
154 DEBUG_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 
168 DEBUG_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 
182 DEBUG_LOCAL OSStatus
183 	QueryCopyQuerySet(
184 		QueryRef 				inRef,
185 		const WSAQUERYSETW *	inQuerySet,
186 		DWORD 					inQuerySetFlags,
187 		WSAQUERYSETW **			outQuerySet,
188 		size_t *				outSize );
189 
190 DEBUG_LOCAL void
191 	QueryCopyQuerySetTo(
192 		QueryRef 				inRef,
193 		const WSAQUERYSETW *	inQuerySet,
194 		DWORD 					inQuerySetFlags,
195 		WSAQUERYSETW *			outQuerySet );
196 
197 DEBUG_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 
207 DEBUG_LOCAL BOOL		InHostsTable( const char * name );
208 DEBUG_LOCAL BOOL		IsLocalName( HostsFileInfo * node );
209 DEBUG_LOCAL BOOL		IsSameName( HostsFileInfo * node, const char * name );
210 DEBUG_LOCAL OSStatus	HostsFileOpen( HostsFile ** self, const char * fname );
211 DEBUG_LOCAL OSStatus	HostsFileClose( HostsFile * self );
212 DEBUG_LOCAL void		HostsFileInfoFree( HostsFileInfo * info );
213 DEBUG_LOCAL OSStatus	HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo );
214 DEBUG_LOCAL DWORD		GetScopeId( DWORD ifIndex );
215 
216 #ifdef ENABLE_REVERSE_LOOKUP
217 DEBUG_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}
230 DEBUG_LOCAL HINSTANCE				gInstance			= NULL;
231 DEBUG_LOCAL wchar_t				*	gNSPName			= L"mdnsNSP";
232 DEBUG_LOCAL GUID					gNSPGUID			= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
233 DEBUG_LOCAL LONG					gRefCount			= 0;
234 DEBUG_LOCAL CRITICAL_SECTION		gLock;
235 DEBUG_LOCAL bool					gLockInitialized 	= false;
236 DEBUG_LOCAL QueryRef				gQueryList	 		= NULL;
237 DEBUG_LOCAL HostsFileInfo		*	gHostsFileInfo		= NULL;
238 typedef DWORD
239 	( WINAPI * GetAdaptersAddressesFunctionPtr )(
240 			ULONG 					inFamily,
241 			DWORD 					inFlags,
242 			PVOID 					inReserved,
243 			PIP_ADAPTER_ADDRESSES 	inAdapter,
244 			PULONG					outBufferSize );
245 
246 DEBUG_LOCAL HMODULE								gIPHelperLibraryInstance			= NULL;
247 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr		gGetAdaptersAddressesFunctionPtr	= NULL;
248 
249 
250 
251 #if 0
252 #pragma mark -
253 #endif
254 
255 //===========================================================================================================================
256 //	DllMain
257 //===========================================================================================================================
258 
DllMain(HINSTANCE inInstance,DWORD inReason,LPVOID inReserved)259 BOOL 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 
DllRegisterServer(void)303 STDAPI	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 
328 exit:
329 
330 	WSACleanup();
331 	return( err );
332 }
333 
334 //===========================================================================================================================
335 //	DllUnregisterServer
336 //===========================================================================================================================
337 
DllUnregisterServer(void)338 STDAPI	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 
353 exit:
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 
NSPStartup(LPGUID inProviderID,LPNSP_ROUTINE outRoutines)366 int 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 
414 exit:
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 
NSPCleanup(LPGUID inProviderID)431 int	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 
476 exit:
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 
489 DEBUG_LOCAL int WSPAPI
NSPLookupServiceBegin(LPGUID inProviderID,LPWSAQUERYSETW inQuerySet,LPWSASERVICECLASSINFOW inServiceClassInfo,DWORD inFlags,LPHANDLE outLookup)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 
624 exit:
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 
642 DEBUG_LOCAL int WSPAPI
NSPLookupServiceNext(HANDLE inLookup,DWORD inFlags,LPDWORD ioSize,LPWSAQUERYSETW outResults)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 
737 exit:
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 
NSPLookupServiceEnd(HANDLE inLookup)760 DEBUG_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 
773 exit:
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 
792 DEBUG_LOCAL int WSPAPI
NSPSetService(LPGUID inProviderID,LPWSASERVICECLASSINFOW inServiceClassInfo,LPWSAQUERYSETW inRegInfo,WSAESETSERVICEOP inOperation,DWORD inFlags)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 
NSPInstallServiceClass(LPGUID inProviderID,LPWSASERVICECLASSINFOW inServiceClassInfo)823 DEBUG_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 
NSPRemoveServiceClass(LPGUID inProviderID,LPGUID inServiceClassID)845 DEBUG_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 
NSPGetServiceClassInfo(LPGUID inProviderID,LPDWORD ioSize,LPWSASERVICECLASSINFOW ioServiceClassInfo)866 DEBUG_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 
QueryCreate(const WSAQUERYSETW * inQuerySet,DWORD inQuerySetFlags,QueryRef * outRef)891 DEBUG_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 
1015 exit:
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 
QueryRetain(QueryRef inRef)1029 DEBUG_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 
1046 exit:
1047 	return( err );
1048 }
1049 
1050 //===========================================================================================================================
1051 //	QueryRelease
1052 //
1053 //	Warning: Assumes the NSP lock is held.
1054 //===========================================================================================================================
1055 
QueryRelease(QueryRef inRef)1056 DEBUG_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 
1142 exit:
1143 	return( err );
1144 }
1145 
1146 //===========================================================================================================================
1147 //	QueryRecordCallback4
1148 //===========================================================================================================================
1149 
1150 DEBUG_LOCAL void CALLBACK_COMPAT
QueryRecordCallback4(DNSServiceRef inRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceErrorType inErrorCode,const char * inName,uint16_t inRRType,uint16_t inRRClass,uint16_t inRDataSize,const void * inRData,uint32_t inTTL,void * inContext)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 
1224 exit:
1225 	NSPUnlock();
1226 }
1227 
1228 #if 0
1229 #pragma mark -
1230 #endif
1231 
1232 
1233 //===========================================================================================================================
1234 //	QueryRecordCallback6
1235 //===========================================================================================================================
1236 
1237 DEBUG_LOCAL void CALLBACK_COMPAT
QueryRecordCallback6(DNSServiceRef inRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceErrorType inErrorCode,const char * inName,uint16_t inRRType,uint16_t inRRClass,uint16_t inRDataSize,const void * inRData,uint32_t inTTL,void * inContext)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 
1314 exit:
1315 
1316 
1317 
1318 	NSPUnlock();
1319 }
1320 
1321 
1322 //===========================================================================================================================
1323 //	QueryCopyQuerySet
1324 //
1325 //	Warning: Assumes the NSP lock is held.
1326 //===========================================================================================================================
1327 
1328 DEBUG_LOCAL OSStatus
QueryCopyQuerySet(QueryRef inRef,const WSAQUERYSETW * inQuerySet,DWORD inQuerySetFlags,WSAQUERYSETW ** outQuerySet,size_t * outSize)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 
1357 exit:
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 
1373 DEBUG_LOCAL void
QueryCopyQuerySetTo(QueryRef inRef,const WSAQUERYSETW * inQuerySet,DWORD inQuerySetFlags,WSAQUERYSETW * outQuerySet)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 
QueryCopyQuerySetSize(QueryRef inRef,const WSAQUERYSETW * inQuerySet,DWORD inQuerySetFlags)1588 DEBUG_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 
DebugDumpQuerySet(DebugLevel inLevel,const WSAQUERYSETW * inQuerySet)1695 void	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 
1834 DEBUG_LOCAL BOOL
InHostsTable(const char * name)1835 InHostsTable( 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 
1879 exit:
1880 
1881 	return ret;
1882 }
1883 
1884 
1885 //===========================================================================================================================
1886 //	IsLocalName
1887 //===========================================================================================================================
1888 
1889 DEBUG_LOCAL BOOL
IsLocalName(HostsFileInfo * node)1890 IsLocalName( 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 
1911 exit:
1912 
1913 	return ret;
1914 }
1915 
1916 
1917 //===========================================================================================================================
1918 //	IsSameName
1919 //===========================================================================================================================
1920 
1921 DEBUG_LOCAL BOOL
IsSameName(HostsFileInfo * node,const char * name)1922 IsSameName( 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 
1944 exit:
1945 
1946 	return ret;
1947 }
1948 
1949 
1950 //===========================================================================================================================
1951 //	HostsFileOpen
1952 //===========================================================================================================================
1953 
1954 DEBUG_LOCAL OSStatus
HostsFileOpen(HostsFile ** self,const char * fname)1955 HostsFileOpen( 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 
1972 exit:
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 
1988 DEBUG_LOCAL OSStatus
HostsFileClose(HostsFile * self)1989 HostsFileClose( 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 
2015 DEBUG_LOCAL void
HostsFileInfoFree(HostsFileInfo * info)2016 HostsFileInfoFree( 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 
2063 DEBUG_LOCAL OSStatus
HostsFileNext(HostsFile * self,HostsFileInfo ** hInfo)2064 HostsFileNext( 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 
2239 exit:
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 
2256 DEBUG_LOCAL OSStatus
IsReverseLookup(LPCWSTR name,size_t size)2257 IsReverseLookup( 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 
2319 exit:
2320 
2321 	return err;
2322 }
2323 #endif
2324 
2325 //===========================================================================================================================
2326 //	GetScopeId
2327 //===========================================================================================================================
2328 
2329 DEBUG_LOCAL DWORD
GetScopeId(DWORD ifIndex)2330 GetScopeId( 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 
2422 exit:
2423 
2424 	if( iaaList )
2425 	{
2426 		free( iaaList );
2427 	}
2428 
2429 	return scopeId;
2430 }
2431