2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.18 2005/10/17 05:45:36 herscher
27 Fix typo in previous checkin
29 Revision 1.17 2005/10/17 05:30:00 herscher
30 <rdar://problem/4071610> NSP should handle IPv6 AAAA queries for dot-local names
32 Revision 1.16 2005/09/16 22:22:48 herscher
33 <rdar://problem/4261460> No longer set the PATH variable when NSP is loaded.
35 Revision 1.15 2005/07/14 22:12:00 shersche
36 <rdar://problem/4178448> Delay load dnssd.dll so that it gracefully handles library loading problems immediately after installing Bonjour
38 Revision 1.14 2005/03/29 20:35:28 shersche
39 <rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
41 Revision 1.13 2005/03/29 19:42:47 shersche
42 Do label check before checking etc/hosts file
44 Revision 1.12 2005/03/21 00:42:45 shersche
45 <rdar://problem/4021486> Fix build warnings on Win32 platform
47 Revision 1.11 2005/03/16 03:04:51 shersche
48 <rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
50 Revision 1.10 2005/02/23 22:16:07 shersche
51 Unregister the NSP before registering to workaround an installer problem during upgrade installs
53 Revision 1.9 2005/02/01 01:45:55 shersche
54 Change mdnsNSP timeout to 2 seconds
56 Revision 1.8 2005/01/31 23:27:25 shersche
57 <rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
59 Revision 1.7 2005/01/28 23:50:13 shersche
60 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
63 Revision 1.6 2004/12/06 01:56:53 shersche
64 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
67 Revision 1.5 2004/07/13 21:24:28 rpantos
68 Fix for <rdar://problem/3701120>.
70 Revision 1.4 2004/07/09 18:03:33 shersche
71 removed extraneous DNSServiceQueryRecord call
73 Revision 1.3 2004/07/07 17:03:49 shersche
74 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
77 Revision 1.2 2004/06/24 19:18:07 shersche
79 Submitted by: herscher
81 Revision 1.1 2004/06/18 04:13:44 rpantos
84 Revision 1.2 2004/04/08 09:43:43 bradley
85 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
87 Revision 1.1 2004/01/30 03:00:33 bradley
88 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
89 .local name lookups using Multicast DNS in all Windows apps.
98 #include "CommonServices.h"
99 #include "DebugServices.h"
101 #include <iphlpapi.h>
110 #pragma comment(lib, "DelayImp.lib")
113 #define swprintf _snwprintf
114 #define snprintf _snprintf
118 #pragma mark == Structures ==
121 //===========================================================================================================================
123 //===========================================================================================================================
125 typedef struct Query
* QueryRef
;
126 typedef struct Query Query
;
132 WSAQUERYSETW
* querySet
;
137 HANDLE waitHandles
[ 3 ];
139 DNSServiceRef resolver4
;
140 DNSServiceRef resolver6
;
141 char name
[ kDNSServiceMaxDomainName
];
143 uint8_t numValidAddrs
;
151 #define BUFFER_INITIAL_SIZE 4192
152 #define ALIASES_INITIAL_SIZE 5
154 typedef struct HostsFile
162 typedef struct HostsFileInfo
164 struct hostent m_host
;
165 struct HostsFileInfo
* m_next
;
170 #pragma mark == Prototypes ==
173 //===========================================================================================================================
175 //===========================================================================================================================
179 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
180 STDAPI
DllRegisterServer( void );
181 STDAPI
DllRegisterServer( void );
186 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
188 DEBUG_LOCAL
int WSPAPI
189 NSPLookupServiceBegin(
191 LPWSAQUERYSETW inQuerySet
,
192 LPWSASERVICECLASSINFOW inServiceClassInfo
,
194 LPHANDLE outLookup
);
196 DEBUG_LOCAL
int WSPAPI
197 NSPLookupServiceNext(
200 LPDWORD ioBufferLength
,
201 LPWSAQUERYSETW outResults
);
203 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
205 DEBUG_LOCAL
int WSPAPI
208 LPWSASERVICECLASSINFOW inServiceClassInfo
,
209 LPWSAQUERYSETW inRegInfo
,
210 WSAESETSERVICEOP inOperation
,
213 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
);
214 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
);
215 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioBufSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
);
219 #define NSPLock() EnterCriticalSection( &gLock );
220 #define NSPUnlock() LeaveCriticalSection( &gLock );
222 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
);
223 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
);
224 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
);
226 DEBUG_LOCAL
void CALLBACK_COMPAT
227 QueryRecordCallback4(
229 DNSServiceFlags inFlags
,
230 uint32_t inInterfaceIndex
,
231 DNSServiceErrorType inErrorCode
,
235 uint16_t inRDataSize
,
236 const void * inRData
,
240 DEBUG_LOCAL
void CALLBACK_COMPAT
241 QueryRecordCallback6(
243 DNSServiceFlags inFlags
,
244 uint32_t inInterfaceIndex
,
245 DNSServiceErrorType inErrorCode
,
249 uint16_t inRDataSize
,
250 const void * inRData
,
257 const WSAQUERYSETW
* inQuerySet
,
258 DWORD inQuerySetFlags
,
259 WSAQUERYSETW
** outQuerySet
,
265 const WSAQUERYSETW
* inQuerySet
,
266 DWORD inQuerySetFlags
,
267 WSAQUERYSETW
* outQuerySet
);
269 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
272 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
274 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
276 #define dlog_query_set( LEVEL, SET )
279 DEBUG_LOCAL BOOL
InHostsTable( const char * name
);
280 DEBUG_LOCAL BOOL
IsLocalName( HostsFileInfo
* node
);
281 DEBUG_LOCAL BOOL
IsSameName( HostsFileInfo
* node
, const char * name
);
282 DEBUG_LOCAL OSStatus
HostsFileOpen( HostsFile
** self
, const char * fname
);
283 DEBUG_LOCAL OSStatus
HostsFileClose( HostsFile
* self
);
284 DEBUG_LOCAL
void HostsFileInfoFree( HostsFileInfo
* info
);
285 DEBUG_LOCAL OSStatus
HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
);
286 DEBUG_LOCAL
const char * GetNextLabel( const char *cstr
, char label
[64] );
287 DEBUG_LOCAL DWORD
GetScopeId( DWORD ifIndex
);
289 #ifdef ENABLE_REVERSE_LOOKUP
290 DEBUG_LOCAL OSStatus
IsReverseLookup( LPCWSTR name
, size_t size
);
295 #pragma mark == Globals ==
298 //===========================================================================================================================
300 //===========================================================================================================================
302 // {B600E6E9-553B-4a19-8696-335E5C896153}
303 DEBUG_LOCAL HINSTANCE gInstance
= NULL
;
304 DEBUG_LOCAL
wchar_t * gNSPName
= L
"mdnsNSP";
305 DEBUG_LOCAL GUID gNSPGUID
= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
306 DEBUG_LOCAL LONG gRefCount
= 0;
307 DEBUG_LOCAL CRITICAL_SECTION gLock
;
308 DEBUG_LOCAL
bool gLockInitialized
= false;
309 DEBUG_LOCAL QueryRef gQueryList
= NULL
;
310 DEBUG_LOCAL HostsFileInfo
* gHostsFileInfo
= NULL
;
312 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
316 PIP_ADAPTER_ADDRESSES inAdapter
,
317 PULONG outBufferSize
);
319 DEBUG_LOCAL HMODULE gIPHelperLibraryInstance
= NULL
;
320 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
328 //===========================================================================================================================
330 //===========================================================================================================================
332 BOOL APIENTRY
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
334 DEBUG_USE_ONLY( inInstance
);
335 DEBUG_UNUSED( inReserved
);
339 case DLL_PROCESS_ATTACH
:
340 gInstance
= inInstance
;
341 gHostsFileInfo
= NULL
;
342 debug_initialize( kDebugOutputTypeWindowsEventLog
, "mDNS NSP", inInstance
);
343 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelNotice
);
344 dlog( kDebugLevelTrace
, "\n" );
345 dlog( kDebugLevelVerbose
, "%s: process attach\n", __ROUTINE__
);
349 case DLL_PROCESS_DETACH
:
350 HostsFileInfoFree( gHostsFileInfo
);
351 gHostsFileInfo
= NULL
;
352 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
355 case DLL_THREAD_ATTACH
:
356 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
359 case DLL_THREAD_DETACH
:
360 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
364 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
372 //===========================================================================================================================
374 //===========================================================================================================================
376 STDAPI
DllRegisterServer( void )
379 WCHAR path
[ MAX_PATH
];
382 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
384 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
385 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
386 require_noerr( err
, exit
);
388 // Unregister before registering to workaround an installer
389 // problem during upgrade installs.
391 WSCUnInstallNameSpace( &gNSPGUID
);
393 err
= GetModuleFileNameW( gInstance
, path
, sizeof( path
) );
394 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
395 require_noerr( err
, exit
);
397 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
398 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
399 require_noerr( err
, exit
);
407 //===========================================================================================================================
408 // DllUnregisterServer
409 //===========================================================================================================================
411 STDAPI
DllUnregisterServer( void )
416 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
418 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
419 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
420 require_noerr( err
, exit
);
422 err
= WSCUnInstallNameSpace( &gNSPGUID
);
423 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
424 require_noerr( err
, exit
);
433 //===========================================================================================================================
436 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
437 //===========================================================================================================================
439 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
443 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
444 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
446 // Only initialize if this is the first time NSPStartup is called.
448 if( InterlockedIncrement( &gRefCount
) != 1 )
454 // Initialize our internal state.
456 InitializeCriticalSection( &gLock
);
457 gLockInitialized
= true;
459 // Set the size to exclude NSPIoctl because we don't implement it.
461 outRoutines
->cbSize
= FIELD_OFFSET( NSP_ROUTINE
, NSPIoctl
);
462 outRoutines
->dwMajorVersion
= 4;
463 outRoutines
->dwMinorVersion
= 4;
464 outRoutines
->NSPCleanup
= NSPCleanup
;
465 outRoutines
->NSPLookupServiceBegin
= NSPLookupServiceBegin
;
466 outRoutines
->NSPLookupServiceNext
= NSPLookupServiceNext
;
467 outRoutines
->NSPLookupServiceEnd
= NSPLookupServiceEnd
;
468 outRoutines
->NSPSetService
= NSPSetService
;
469 outRoutines
->NSPInstallServiceClass
= NSPInstallServiceClass
;
470 outRoutines
->NSPRemoveServiceClass
= NSPRemoveServiceClass
;
471 outRoutines
->NSPGetServiceClassInfo
= NSPGetServiceClassInfo
;
473 // See if we can get the address for the GetAdaptersAddresses() API. This is only in XP, but we want our
474 // code to run on older versions of Windows
476 if ( !gIPHelperLibraryInstance
)
478 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
479 if( gIPHelperLibraryInstance
)
481 gGetAdaptersAddressesFunctionPtr
= (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
488 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
489 if( err
!= NO_ERROR
)
491 NSPCleanup( inProviderID
);
492 SetLastError( (DWORD
) err
);
493 return( SOCKET_ERROR
);
498 //===========================================================================================================================
501 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
502 //===========================================================================================================================
504 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
506 DEBUG_USE_ONLY( inProviderID
);
508 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
509 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
511 // Only initialize if this is the first time NSPStartup is called.
513 if( InterlockedDecrement( &gRefCount
) != 0 )
518 // Stop any outstanding queries.
520 if( gLockInitialized
)
526 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
527 QueryRelease( gQueryList
);
529 if( gLockInitialized
)
534 if( gLockInitialized
)
536 gLockInitialized
= false;
537 DeleteCriticalSection( &gLock
);
540 if( gIPHelperLibraryInstance
)
544 ok
= FreeLibrary( gIPHelperLibraryInstance
);
545 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
546 gIPHelperLibraryInstance
= NULL
;
550 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
554 //===========================================================================================================================
555 // NSPLookupServiceBegin
557 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
558 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
559 // opposed to specifying the query parameters each time.
560 //===========================================================================================================================
562 DEBUG_LOCAL
int WSPAPI
563 NSPLookupServiceBegin(
565 LPWSAQUERYSETW inQuerySet
,
566 LPWSASERVICECLASSINFOW inServiceClassInfo
,
581 DEBUG_UNUSED( inProviderID
);
582 DEBUG_UNUSED( inServiceClassInfo
);
584 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
587 require_action( inQuerySet
, exit
, err
= WSAEINVAL
);
588 name
= inQuerySet
->lpszServiceInstanceName
;
589 require_action_quiet( name
, exit
, err
= WSAEINVAL
);
590 require_action( outLookup
, exit
, err
= WSAEINVAL
);
592 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__
, inFlags
, name
);
593 dlog_query_set( kDebugLevelVerbose
, inQuerySet
);
595 // Check if we can handle this type of request and if we support any of the protocols being requested.
596 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
598 require_action_quiet( inFlags
& (LUP_RETURN_ADDR
|LUP_RETURN_BLOB
), exit
, err
= WSASERVICE_NOT_FOUND
);
600 type
= inQuerySet
->dwNameSpace
;
601 require_action_quiet( ( type
== NS_DNS
) || ( type
== NS_ALL
), exit
, err
= WSASERVICE_NOT_FOUND
);
603 n
= inQuerySet
->dwNumberOfProtocols
;
606 require_action( inQuerySet
->lpafpProtocols
, exit
, err
= WSAEINVAL
);
607 for( i
= 0; i
< n
; ++i
)
609 family
= inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
;
610 protocol
= inQuerySet
->lpafpProtocols
[ i
].iProtocol
;
611 if( ( family
== AF_INET
) && ( ( protocol
== IPPROTO_UDP
) || ( protocol
== IPPROTO_TCP
) ) )
616 require_action_quiet( i
< n
, exit
, err
= WSASERVICE_NOT_FOUND
);
619 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
620 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
621 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
622 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
623 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
625 for( p
= name
; *p
; ++p
) {} // Find end of string
626 size
= (size_t)( p
- name
);
627 require_action_quiet( size
> sizeof_string( ".local" ), exit
, err
= WSASERVICE_NOT_FOUND
);
629 p
= name
+ ( size
- 1 );
630 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".local" ) ) : ( ( p
- sizeof_string( ".local" ) ) + 1 );
631 if ( ( ( p
[ 0 ] != '.' ) ||
632 ( ( p
[ 1 ] != 'L' ) && ( p
[ 1 ] != 'l' ) ) ||
633 ( ( p
[ 2 ] != 'O' ) && ( p
[ 2 ] != 'o' ) ) ||
634 ( ( p
[ 3 ] != 'C' ) && ( p
[ 3 ] != 'c' ) ) ||
635 ( ( p
[ 4 ] != 'A' ) && ( p
[ 4 ] != 'a' ) ) ||
636 ( ( p
[ 5 ] != 'L' ) && ( p
[ 5 ] != 'l' ) ) ) )
638 #ifdef ENABLE_REVERSE_LOOKUP
640 err
= IsReverseLookup( name
, size
);
644 err
= WSASERVICE_NOT_FOUND
;
648 require_noerr( err
, exit
);
652 const char * replyDomain
;
653 char translated
[ kDNSServiceMaxDomainName
];
656 const char * label
[128];
659 n
= WideCharToMultiByte( CP_UTF8
, 0, name
, -1, translated
, sizeof( translated
), NULL
, NULL
);
660 require_action( n
> 0, exit
, err
= WSASERVICE_NOT_FOUND
);
662 // <rdar://problem/4050633>
664 // Don't resolve multi-label name
666 replyDomain
= translated
;
668 while ( *replyDomain
)
670 label
[labels
++] = replyDomain
;
671 replyDomain
= GetNextLabel(replyDomain
, text
);
674 require_action( labels
== 2, exit
, err
= WSASERVICE_NOT_FOUND
);
676 // <rdar://problem/3936771>
678 // Check to see if the name of this host is in the hosts table. If so,
679 // don't try and resolve it
681 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
684 // 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.
688 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
690 require_noerr( err
, exit
);
692 *outLookup
= (HANDLE
) obj
;
695 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
696 if( err
!= NO_ERROR
)
698 SetLastError( (DWORD
) err
);
699 return( SOCKET_ERROR
);
704 //===========================================================================================================================
705 // NSPLookupServiceNext
707 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
708 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
709 // in the lpqsResults parameter.
710 //===========================================================================================================================
712 DEBUG_LOCAL
int WSPAPI
713 NSPLookupServiceNext(
717 LPWSAQUERYSETW outResults
)
726 DEBUG_USE_ONLY( inFlags
);
728 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
734 err
= QueryRetain( (QueryRef
) inLookup
);
735 require_noerr( err
, exit
);
736 obj
= (QueryRef
) inLookup
;
737 require_action( ioSize
, exit
, err
= WSAEINVAL
);
738 require_action( outResults
, exit
, err
= WSAEINVAL
);
740 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
742 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
745 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
747 require_action_quiet( waitResult
!= ( WAIT_OBJECT_0
), exit
, err
= WSA_E_CANCELLED
);
748 err
= translate_errno( ( waitResult
== WAIT_OBJECT_0
+ 1 ) || ( waitResult
== WAIT_OBJECT_0
+ 2 ), (OSStatus
) GetLastError(), WSASERVICE_NOT_FOUND
);
749 require_noerr_quiet( err
, exit
);
751 // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
753 if ( waitResult
== WAIT_OBJECT_0
+ 1 )
756 data6
= WaitForSingleObject( obj
->data6Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
759 // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
761 else if ( waitResult
== WAIT_OBJECT_0
+ 2 )
763 data4
= WaitForSingleObject( obj
->data4Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
771 err
= DNSServiceProcessResult(obj
->resolver4
);
773 __except( EXCEPTION_EXECUTE_HANDLER
)
778 require_noerr( err
, exit
);
785 err
= DNSServiceProcessResult( obj
->resolver6
);
787 __except( EXCEPTION_EXECUTE_HANDLER
)
792 require_noerr( err
, exit
);
795 require_action_quiet( obj
->addr4Valid
|| obj
->addr6Valid
, exit
, err
= WSA_E_NO_MORE
);
797 // Copy the externalized query results to the callers buffer (if it fits).
799 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
800 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
802 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
803 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
804 obj
->addr4Valid
= false;
805 obj
->addr6Valid
= false;
813 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
814 if( err
!= NO_ERROR
)
816 SetLastError( (DWORD
) err
);
817 return( SOCKET_ERROR
);
822 //===========================================================================================================================
823 // NSPLookupServiceEnd
825 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
826 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
827 // allocated resources associated with the query.
828 //===========================================================================================================================
830 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
834 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
836 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
839 err
= QueryRelease( (QueryRef
) inLookup
);
841 require_noerr( err
, exit
);
844 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
845 if( err
!= NO_ERROR
)
847 SetLastError( (DWORD
) err
);
848 return( SOCKET_ERROR
);
853 //===========================================================================================================================
856 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
857 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
858 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
859 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
860 //===========================================================================================================================
862 DEBUG_LOCAL
int WSPAPI
865 LPWSASERVICECLASSINFOW inServiceClassInfo
,
866 LPWSAQUERYSETW inRegInfo
,
867 WSAESETSERVICEOP inOperation
,
870 DEBUG_UNUSED( inProviderID
);
871 DEBUG_UNUSED( inServiceClassInfo
);
872 DEBUG_UNUSED( inRegInfo
);
873 DEBUG_UNUSED( inOperation
);
874 DEBUG_UNUSED( inFlags
);
876 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
877 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
879 // We don't allow services to be registered so always return an error.
881 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
885 //===========================================================================================================================
886 // NSPInstallServiceClass
888 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
889 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
890 // instance of a server may be registered.
891 //===========================================================================================================================
893 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
895 DEBUG_UNUSED( inProviderID
);
896 DEBUG_UNUSED( inServiceClassInfo
);
898 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
899 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
901 // We don't allow service classes to be installed so always return an error.
903 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
904 return( WSA_INVALID_PARAMETER
);
907 //===========================================================================================================================
908 // NSPRemoveServiceClass
910 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
911 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
913 //===========================================================================================================================
915 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
917 DEBUG_UNUSED( inProviderID
);
918 DEBUG_UNUSED( inServiceClassID
);
920 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
921 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
923 // We don't allow service classes to be installed so always return an error.
925 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
926 return( WSATYPE_NOT_FOUND
);
929 //===========================================================================================================================
930 // NSPGetServiceClassInfo
932 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
933 // a given service class.
934 //===========================================================================================================================
936 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
938 DEBUG_UNUSED( inProviderID
);
939 DEBUG_UNUSED( ioSize
);
940 DEBUG_UNUSED( ioServiceClassInfo
);
942 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
943 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
945 // We don't allow service classes to be installed so always return an error.
947 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
948 return( WSATYPE_NOT_FOUND
);
955 //===========================================================================================================================
958 // Warning: Assumes the NSP lock is held.
959 //===========================================================================================================================
961 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
965 char name
[ kDNSServiceMaxDomainName
];
973 check( inQuerySet
->lpszServiceInstanceName
);
976 // Convert the wchar_t name to UTF-8.
978 n
= WideCharToMultiByte( CP_UTF8
, 0, inQuerySet
->lpszServiceInstanceName
, -1, name
, sizeof( name
), NULL
, NULL
);
979 err
= translate_errno( n
> 0, (OSStatus
) GetLastError(), WSAEINVAL
);
980 require_noerr( err
, exit
);
982 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
984 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
985 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
989 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
992 // Set up cancel event
994 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
995 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
997 // Set up events to signal when A record data is ready
999 obj
->data4Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1000 require_action( obj
->data4Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1002 // Start the query. Handle delay loaded DLL errors.
1006 err
= DNSServiceQueryRecord( &obj
->resolver4
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
, QueryRecordCallback4
, obj
);
1008 __except( EXCEPTION_EXECUTE_HANDLER
)
1013 require_noerr( err
, exit
);
1015 // Attach the socket to the event
1019 s4
= DNSServiceRefSockFD(obj
->resolver4
);
1021 __except( EXCEPTION_EXECUTE_HANDLER
)
1023 s4
= INVALID_SOCKET
;
1026 err
= translate_errno( s4
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1027 require_noerr( err
, exit
);
1029 WSAEventSelect(s4
, obj
->data4Event
, FD_READ
|FD_CLOSE
);
1031 // Set up events to signal when AAAA record data is ready
1033 obj
->data6Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1034 require_action( obj
->data6Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1036 // Start the query. Handle delay loaded DLL errors.
1040 err
= DNSServiceQueryRecord( &obj
->resolver6
, 0, 0, name
, kDNSServiceType_AAAA
, kDNSServiceClass_IN
, QueryRecordCallback6
, obj
);
1042 __except( EXCEPTION_EXECUTE_HANDLER
)
1047 require_noerr( err
, exit
);
1049 // Attach the socket to the event
1053 s6
= DNSServiceRefSockFD(obj
->resolver6
);
1055 __except( EXCEPTION_EXECUTE_HANDLER
)
1057 s6
= INVALID_SOCKET
;
1060 err
= translate_errno( s6
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1061 require_noerr( err
, exit
);
1063 WSAEventSelect(s6
, obj
->data6Event
, FD_READ
|FD_CLOSE
);
1066 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
1067 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data4Event
;
1068 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data6Event
;
1070 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
1072 // Copy the QuerySet so it can be returned later.
1074 obj
->querySetFlags
= inQuerySetFlags
;
1075 inQuerySetFlags
= ( inQuerySetFlags
& ~( LUP_RETURN_ADDR
| LUP_RETURN_BLOB
) ) | LUP_RETURN_NAME
;
1076 err
= QueryCopyQuerySet( obj
, inQuerySet
, inQuerySetFlags
, &obj
->querySet
, &obj
->querySetSize
);
1077 require_noerr( err
, exit
);
1088 QueryRelease( obj
);
1093 //===========================================================================================================================
1096 // Warning: Assumes the NSP lock is held.
1097 //===========================================================================================================================
1099 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
1104 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
1111 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
1120 //===========================================================================================================================
1123 // Warning: Assumes the NSP lock is held.
1124 //===========================================================================================================================
1126 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
1132 // Find the item in the list.
1134 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
1141 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
1143 // Signal a cancel to unblock any threads waiting for results.
1145 if( inRef
->cancelEvent
)
1147 ok
= SetEvent( inRef
->cancelEvent
);
1148 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1153 if( inRef
->resolver4
)
1157 DNSServiceRefDeallocate( inRef
->resolver4
);
1159 __except( EXCEPTION_EXECUTE_HANDLER
)
1163 inRef
->resolver4
= NULL
;
1166 if ( inRef
->resolver6
)
1170 DNSServiceRefDeallocate( inRef
->resolver6
);
1172 __except( EXCEPTION_EXECUTE_HANDLER
)
1176 inRef
->resolver6
= NULL
;
1179 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
1181 if( --inRef
->refCount
!= 0 )
1188 // Release resources.
1190 if( inRef
->cancelEvent
)
1192 ok
= CloseHandle( inRef
->cancelEvent
);
1193 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1195 if( inRef
->data4Event
)
1197 ok
= CloseHandle( inRef
->data4Event
);
1198 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1200 if( inRef
->data6Event
)
1202 ok
= CloseHandle( inRef
->data6Event
);
1203 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1205 if( inRef
->querySet
)
1207 free( inRef
->querySet
);
1216 //===========================================================================================================================
1217 // QueryRecordCallback4
1218 //===========================================================================================================================
1220 DEBUG_LOCAL
void CALLBACK_COMPAT
1221 QueryRecordCallback4(
1222 DNSServiceRef inRef
,
1223 DNSServiceFlags inFlags
,
1224 uint32_t inInterfaceIndex
,
1225 DNSServiceErrorType inErrorCode
,
1226 const char * inName
,
1229 uint16_t inRDataSize
,
1230 const void * inRData
,
1239 DEBUG_UNUSED( inFlags
);
1240 DEBUG_UNUSED( inInterfaceIndex
);
1241 DEBUG_UNUSED( inTTL
);
1244 obj
= (QueryRef
) inContext
;
1246 require_noerr( inErrorCode
, exit
);
1247 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1248 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1249 require( inRRType
== kDNSServiceType_A
, exit
);
1250 require( inRDataSize
== 4, exit
);
1252 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1253 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1255 // Copy the name if needed.
1257 if( obj
->name
[ 0 ] == '\0' )
1261 while( *src
!= '\0' )
1266 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1267 check( obj
->nameSize
< sizeof( obj
->name
) );
1272 memcpy( &obj
->addr4
, inRData
, inRDataSize
);
1273 obj
->addr4Valid
= true;
1274 obj
->numValidAddrs
++;
1276 // Signal that a result is ready.
1278 check( obj
->data4Event
);
1279 ok
= SetEvent( obj
->data4Event
);
1280 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1282 // Stop the resolver after the first response.
1286 DNSServiceRefDeallocate( inRef
);
1288 __except( EXCEPTION_EXECUTE_HANDLER
)
1292 obj
->resolver4
= NULL
;
1303 //===========================================================================================================================
1304 // QueryRecordCallback6
1305 //===========================================================================================================================
1307 DEBUG_LOCAL
void CALLBACK_COMPAT
1308 QueryRecordCallback6(
1309 DNSServiceRef inRef
,
1310 DNSServiceFlags inFlags
,
1311 uint32_t inInterfaceIndex
,
1312 DNSServiceErrorType inErrorCode
,
1313 const char * inName
,
1316 uint16_t inRDataSize
,
1317 const void * inRData
,
1326 DEBUG_UNUSED( inFlags
);
1327 DEBUG_UNUSED( inInterfaceIndex
);
1328 DEBUG_UNUSED( inTTL
);
1331 obj
= (QueryRef
) inContext
;
1333 require_noerr( inErrorCode
, exit
);
1334 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1335 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1336 require( inRRType
== kDNSServiceType_AAAA
, exit
);
1337 require( inRDataSize
== 16, exit
);
1339 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1340 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1342 // Copy the name if needed.
1344 if( obj
->name
[ 0 ] == '\0' )
1348 while( *src
!= '\0' )
1353 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1354 check( obj
->nameSize
< sizeof( obj
->name
) );
1359 memcpy( &obj
->addr6
, inRData
, inRDataSize
);
1361 obj
->addr6ScopeId
= GetScopeId( inInterfaceIndex
);
1362 require( obj
->addr6ScopeId
, exit
);
1363 obj
->addr6Valid
= true;
1364 obj
->numValidAddrs
++;
1366 // Signal that we're done
1368 check( obj
->data6Event
);
1369 ok
= SetEvent( obj
->data6Event
);
1370 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1372 // Stop the resolver after the first response.
1376 DNSServiceRefDeallocate( inRef
);
1378 __except( EXCEPTION_EXECUTE_HANDLER
)
1382 obj
->resolver6
= NULL
;
1392 //===========================================================================================================================
1393 // QueryCopyQuerySet
1395 // Warning: Assumes the NSP lock is held.
1396 //===========================================================================================================================
1398 DEBUG_LOCAL OSStatus
1401 const WSAQUERYSETW
* inQuerySet
,
1402 DWORD inQuerySetFlags
,
1403 WSAQUERYSETW
** outQuerySet
,
1410 check( inQuerySet
);
1411 check( outQuerySet
);
1413 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1414 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1415 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1417 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1437 //===========================================================================================================================
1438 // QueryCopyQuerySetTo
1440 // Warning: Assumes the NSP lock is held.
1441 //===========================================================================================================================
1444 QueryCopyQuerySetTo(
1446 const WSAQUERYSETW
* inQuerySet
,
1447 DWORD inQuerySetFlags
,
1448 WSAQUERYSETW
* outQuerySet
)
1459 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1462 check( inQuerySet
);
1463 check( outQuerySet
);
1465 dst
= (uint8_t *) outQuerySet
;
1467 // Copy the static portion of the results.
1469 *outQuerySet
= *inQuerySet
;
1470 dst
+= sizeof( *inQuerySet
);
1472 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1474 s
= inQuerySet
->lpszServiceInstanceName
;
1477 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1479 while( ( *q
++ = *s
++ ) != 0 ) {}
1480 dst
= (uint8_t *) q
;
1485 outQuerySet
->lpszServiceInstanceName
= NULL
;
1488 if( inQuerySet
->lpServiceClassId
)
1490 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1491 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1492 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1495 if( inQuerySet
->lpVersion
)
1497 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1498 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1499 dst
+= sizeof( *inQuerySet
->lpVersion
);
1502 s
= inQuerySet
->lpszComment
;
1505 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1507 while( ( *q
++ = *s
++ ) != 0 ) {}
1508 dst
= (uint8_t *) q
;
1511 if( inQuerySet
->lpNSProviderId
)
1513 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1514 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1515 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1518 s
= inQuerySet
->lpszContext
;
1521 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1523 while( ( *q
++ = *s
++ ) != 0 ) {}
1524 dst
= (uint8_t *) q
;
1527 n
= inQuerySet
->dwNumberOfProtocols
;
1531 check( inQuerySet
->lpafpProtocols
);
1533 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1534 for( i
= 0; i
< n
; ++i
)
1536 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1537 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1541 s
= inQuerySet
->lpszQueryString
;
1544 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1546 while( ( *q
++ = *s
++ ) != 0 ) {}
1547 dst
= (uint8_t *) q
;
1550 // Copy the address(es).
1552 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && ( inRef
->numValidAddrs
> 0 ) )
1554 struct sockaddr_in
* addr4
;
1555 struct sockaddr_in6
* addr6
;
1558 outQuerySet
->dwNumberOfCsAddrs
= inRef
->numValidAddrs
;
1559 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1560 dst
+= ( sizeof( *outQuerySet
->lpcsaBuffer
) ) * ( inRef
->numValidAddrs
) ;
1563 if ( inRef
->addr4Valid
)
1565 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1566 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1568 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1569 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
1571 addr4
= (struct sockaddr_in
*) dst
;
1572 memset( addr4
, 0, sizeof( *addr4
) );
1573 addr4
->sin_family
= AF_INET
;
1574 memcpy( &addr4
->sin_addr
, &inRef
->addr4
, 4 );
1575 dst
+= sizeof( *addr4
);
1577 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1578 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1583 if ( inRef
->addr6Valid
)
1585 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1586 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1588 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1589 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in6
);
1591 addr6
= (struct sockaddr_in6
*) dst
;
1592 memset( addr6
, 0, sizeof( *addr6
) );
1593 addr6
->sin6_family
= AF_INET6
;
1594 addr6
->sin6_scope_id
= inRef
->addr6ScopeId
;
1595 memcpy( &addr6
->sin6_addr
, &inRef
->addr6
, 16 );
1596 dst
+= sizeof( *addr6
);
1598 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET6
; // Emulate Tcpip NSP
1599 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1604 outQuerySet
->dwNumberOfCsAddrs
= 0;
1605 outQuerySet
->lpcsaBuffer
= NULL
;
1608 // Copy the hostent blob.
1610 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1613 struct hostent
* he
;
1616 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1617 dst
+= sizeof( *outQuerySet
->lpBlob
);
1620 he
= (struct hostent
*) dst
;
1621 dst
+= sizeof( *he
);
1623 he
->h_name
= (char *)( dst
- base
);
1624 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1625 dst
+= ( inRef
->nameSize
+ 1 );
1627 he
->h_aliases
= (char **)( dst
- base
);
1628 p
= (uintptr_t *) dst
;
1630 dst
= (uint8_t *) p
;
1632 he
->h_addrtype
= AF_INET
;
1635 he
->h_addr_list
= (char **)( dst
- base
);
1636 p
= (uintptr_t *) dst
;
1637 dst
+= ( 2 * sizeof( *p
) );
1638 *p
++ = (uintptr_t)( dst
- base
);
1640 p
= (uintptr_t *) dst
;
1641 *p
++ = (uintptr_t) inRef
->addr4
;
1642 dst
= (uint8_t *) p
;
1644 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1645 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1647 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1649 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1652 //===========================================================================================================================
1653 // QueryCopyQuerySetSize
1655 // Warning: Assumes the NSP lock is held.
1656 //===========================================================================================================================
1658 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1665 check( inQuerySet
);
1667 // Calculate the size of the static portion of the results.
1669 size
= sizeof( *inQuerySet
);
1671 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1673 s
= inQuerySet
->lpszServiceInstanceName
;
1676 for( p
= s
; *p
; ++p
) {}
1677 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1681 if( inQuerySet
->lpServiceClassId
)
1683 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1686 if( inQuerySet
->lpVersion
)
1688 size
+= sizeof( *inQuerySet
->lpVersion
);
1691 s
= inQuerySet
->lpszComment
;
1694 for( p
= s
; *p
; ++p
) {}
1695 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1698 if( inQuerySet
->lpNSProviderId
)
1700 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1703 s
= inQuerySet
->lpszContext
;
1706 for( p
= s
; *p
; ++p
) {}
1707 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1710 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1712 s
= inQuerySet
->lpszQueryString
;
1715 for( p
= s
; *p
; ++p
) {}
1716 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1719 // Calculate the size of the address(es).
1721 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr4Valid
)
1723 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1724 size
+= sizeof( struct sockaddr_in
);
1727 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr6Valid
)
1729 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1730 size
+= sizeof( struct sockaddr_in6
);
1733 // Calculate the size of the hostent blob.
1735 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1737 size
+= sizeof( *inQuerySet
->lpBlob
); // Blob ptr/size structure
1738 size
+= sizeof( struct hostent
); // Old-style hostent structure
1739 size
+= ( inRef
->nameSize
+ 1 ); // Name and null terminator
1740 size
+= 4; // Alias list terminator (0 offset)
1741 size
+= 4; // Offset to address.
1742 size
+= 4; // Address list terminator (0 offset)
1743 size
+= 4; // IPv4 address
1753 //===========================================================================================================================
1754 // DebugDumpQuerySet
1755 //===========================================================================================================================
1757 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1758 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1760 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1761 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1763 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1765 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1769 check( inQuerySet
);
1771 // Fixed portion of the QuerySet.
1773 dlog( inLevel
, "QuerySet:\n" );
1774 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1775 if( inQuerySet
->lpszServiceInstanceName
)
1777 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1781 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1783 if( inQuerySet
->lpServiceClassId
)
1785 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1789 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1791 if( inQuerySet
->lpVersion
)
1793 dlog( inLevel
, " lpVersion:\n" );
1794 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1795 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1799 dlog( inLevel
, " lpVersion: <null>\n" );
1801 if( inQuerySet
->lpszComment
)
1803 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1807 dlog( inLevel
, " lpszComment: <null>\n" );
1809 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1810 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1811 if( inQuerySet
->lpNSProviderId
)
1813 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1817 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1819 if( inQuerySet
->lpszContext
)
1821 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1825 dlog( inLevel
, " lpszContext: <null>\n" );
1827 dlog( inLevel
, " dwNumberOfProtocols: %d\n", inQuerySet
->dwNumberOfProtocols
);
1828 dlog( inLevel
, " lpafpProtocols: %s\n", inQuerySet
->lpafpProtocols
? "" : "<null>" );
1829 for( i
= 0; i
< inQuerySet
->dwNumberOfProtocols
; ++i
)
1833 dlog( inLevel
, "\n" );
1835 dlog( inLevel
, " iAddressFamily: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
,
1836 DebugSocketFamilyToString( inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
) );
1837 dlog( inLevel
, " iProtocol: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iProtocol
,
1838 DebugSocketProtocolToString( inQuerySet
->lpafpProtocols
[ i
].iProtocol
) );
1840 if( inQuerySet
->lpszQueryString
)
1842 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1846 dlog( inLevel
, " lpszQueryString: <null>\n" );
1848 dlog( inLevel
, " dwNumberOfCsAddrs: %d\n", inQuerySet
->dwNumberOfCsAddrs
);
1849 dlog( inLevel
, " lpcsaBuffer: %s\n", inQuerySet
->lpcsaBuffer
? "" : "<null>" );
1850 for( i
= 0; i
< inQuerySet
->dwNumberOfCsAddrs
; ++i
)
1854 dlog( inLevel
, "\n" );
1856 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1857 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1859 dlog( inLevel
, " LocalAddr: %##a\n",
1860 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1864 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1866 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1867 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1869 dlog( inLevel
, " RemoteAddr: %##a\n",
1870 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1874 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1876 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1877 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1879 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1881 // Blob portion of the QuerySet.
1883 if( inQuerySet
->lpBlob
)
1885 dlog( inLevel
, " lpBlob:\n" );
1886 dlog( inLevel
, " cbSize: %ld\n", inQuerySet
->lpBlob
->cbSize
);
1887 dlog( inLevel
, " pBlobData: %#p\n", inQuerySet
->lpBlob
->pBlobData
);
1888 dloghex( inLevel
, 12, NULL
, 0, 0, NULL
, 0,
1889 inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->cbSize
,
1890 kDebugFlagsNone
, NULL
, 0 );
1894 dlog( inLevel
, " lpBlob: <null>\n" );
1900 //===========================================================================================================================
1902 //===========================================================================================================================
1905 InHostsTable( const char * name
)
1907 HostsFileInfo
* node
;
1913 if ( gHostsFileInfo
== NULL
)
1915 TCHAR systemDirectory
[MAX_PATH
];
1916 TCHAR hFileName
[MAX_PATH
];
1919 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1920 sprintf( hFileName
, "%s\\drivers\\etc\\hosts", systemDirectory
);
1921 err
= HostsFileOpen( &hFile
, hFileName
);
1922 require_noerr( err
, exit
);
1924 while ( HostsFileNext( hFile
, &node
) == 0 )
1926 if ( IsLocalName( node
) )
1928 node
->m_next
= gHostsFileInfo
;
1929 gHostsFileInfo
= node
;
1933 HostsFileInfoFree( node
);
1937 HostsFileClose( hFile
);
1940 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1942 if ( IsSameName( node
, name
) )
1955 //===========================================================================================================================
1957 //===========================================================================================================================
1960 IsLocalName( HostsFileInfo
* node
)
1966 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1970 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1972 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
1987 //===========================================================================================================================
1989 //===========================================================================================================================
1992 IsSameName( HostsFileInfo
* node
, const char * name
)
1999 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
2003 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
2005 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
2020 //===========================================================================================================================
2022 //===========================================================================================================================
2024 DEBUG_LOCAL OSStatus
2025 HostsFileOpen( HostsFile
** self
, const char * fname
)
2027 OSStatus err
= kNoErr
;
2029 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
2030 require_action( *self
, exit
, err
= kNoMemoryErr
);
2031 memset( *self
, 0, sizeof( HostsFile
) );
2033 (*self
)->m_bufferSize
= BUFFER_INITIAL_SIZE
;
2034 (*self
)->m_buffer
= (char*) malloc( (*self
)->m_bufferSize
);
2035 require_action( (*self
)->m_buffer
, exit
, err
= kNoMemoryErr
);
2039 (*self
)->m_fp
= fopen( fname
, "r" );
2040 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
2046 HostsFileClose( *self
);
2054 //===========================================================================================================================
2056 //===========================================================================================================================
2058 DEBUG_LOCAL OSStatus
2059 HostsFileClose( HostsFile
* self
)
2063 if ( self
->m_buffer
)
2065 free( self
->m_buffer
);
2066 self
->m_buffer
= NULL
;
2071 fclose( self
->m_fp
);
2081 //===========================================================================================================================
2082 // HostsFileInfoFree
2083 //===========================================================================================================================
2086 HostsFileInfoFree( HostsFileInfo
* info
)
2090 HostsFileInfo
* next
= info
->m_next
;
2092 if ( info
->m_host
.h_addr_list
)
2094 if ( info
->m_host
.h_addr_list
[0] )
2096 free( info
->m_host
.h_addr_list
[0] );
2097 info
->m_host
.h_addr_list
[0] = NULL
;
2100 free( info
->m_host
.h_addr_list
);
2101 info
->m_host
.h_addr_list
= NULL
;
2104 if ( info
->m_host
.h_aliases
)
2108 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
2110 free( info
->m_host
.h_aliases
[i
] );
2113 free( info
->m_host
.h_aliases
);
2116 if ( info
->m_host
.h_name
)
2118 free( info
->m_host
.h_name
);
2119 info
->m_host
.h_name
= NULL
;
2129 //===========================================================================================================================
2131 //===========================================================================================================================
2133 DEBUG_LOCAL OSStatus
2134 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
2136 struct sockaddr_in6 addr_6
;
2137 struct sockaddr_in addr_4
;
2138 int numAliases
= ALIASES_INITIAL_SIZE
;
2145 OSStatus err
= kNoErr
;
2148 check( self
->m_fp
);
2153 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
2154 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
2155 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
2159 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
2167 // If there's no eol and no eof, then we didn't get the whole line
2169 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
2174 /* Try and allocate space for longer line */
2176 bufferSize
= self
->m_bufferSize
* 2;
2177 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
2178 require_action( buffer
, exit
, err
= kNoMemoryErr
);
2179 self
->m_bufferSize
= bufferSize
;
2180 self
->m_buffer
= buffer
;
2181 idx
= (int) strlen( self
->m_buffer
);
2186 line
= self
->m_buffer
;
2194 // Get rid of either comments or eol characters
2196 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
2201 // Make sure there is some whitespace on this line
2203 if (( tok
= strpbrk(line
, " \t")) == NULL
)
2208 // Create two strings, where p == the IP Address and tok is the name list
2212 while ( *tok
== ' ' || *tok
== '\t')
2217 // Now we have the name
2219 (*hInfo
)->m_host
.h_name
= (char*) malloc( strlen( tok
) + 1 );
2220 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
2221 strcpy( (*hInfo
)->m_host
.h_name
, tok
);
2223 // Now create the address (IPv6/IPv4)
2225 addr_6
.sin6_family
= family
= AF_INET6
;
2226 dwSize
= sizeof( addr_6
);
2228 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
2230 addr_4
.sin_family
= family
= AF_INET
;
2231 dwSize
= sizeof( addr_4
);
2233 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
2239 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
2240 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
2242 if ( family
== AF_INET6
)
2244 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
2245 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2246 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2247 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
2252 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
2253 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2254 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2255 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
2258 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
2259 (*hInfo
)->m_host
.h_addrtype
= family
;
2261 // Now get the aliases
2263 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
2270 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
2271 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2272 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
2274 while ( tok
&& *tok
)
2276 // Skip over the whitespace, waiting for the start of the next alias name
2278 if (*tok
== ' ' || *tok
== '\t')
2284 // Check to make sure we don't exhaust the alias buffer
2286 if ( i
>= ( numAliases
- 1 ) )
2288 numAliases
= numAliases
* 2;
2289 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
2290 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2293 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( strlen( tok
) + 1 );
2294 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
2296 strcpy( (*hInfo
)->m_host
.h_aliases
[i
], tok
);
2298 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
2303 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
2311 if ( err
&& ( *hInfo
) )
2313 HostsFileInfoFree( *hInfo
);
2321 //===========================================================================================================================
2323 //===========================================================================================================================
2324 DEBUG_LOCAL
const char*
2325 GetNextLabel(const char *cstr
, char label
[64])
2328 while (*cstr
&& *cstr
!= '.') // While we have characters in the label...
2334 if (isdigit(cstr
[-1]) && isdigit(cstr
[0]) && isdigit(cstr
[1]))
2336 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
2337 int v1
= cstr
[ 0] - '0';
2338 int v2
= cstr
[ 1] - '0';
2339 int val
= v0
* 100 + v1
* 10 + v2
;
2340 if (val
<= 255) { c
= (char)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
2344 if (ptr
>= label
+64) return(NULL
);
2346 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
2352 #ifdef ENABLE_REVERSE_LOOKUP
2353 //===========================================================================================================================
2355 //===========================================================================================================================
2357 DEBUG_LOCAL OSStatus
2358 IsReverseLookup( LPCWSTR name
, size_t size
)
2361 OSStatus err
= kNoErr
;
2363 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2365 p
= name
+ ( size
- 1 );
2366 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2368 if ( ( ( p
[ 0 ] != '.' ) ||
2369 ( ( p
[ 1 ] != '0' ) ) ||
2370 ( ( p
[ 2 ] != '.' ) ) ||
2371 ( ( p
[ 3 ] != '8' ) ) ||
2372 ( ( p
[ 4 ] != '.' ) ) ||
2373 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
2374 ( ( p
[ 6 ] != '.' ) ) ||
2375 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
2376 ( ( p
[ 8 ] != '.' ) ) ||
2377 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
2378 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
2379 ( ( p
[ 11 ] != '6' ) ) ||
2380 ( ( p
[ 12 ] != '.' ) ) ||
2381 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
2382 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
2383 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
2384 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
2386 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2388 p
= name
+ ( size
- 1 );
2389 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2391 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
2392 ( ( p
[ 1 ] == '2' ) ) &&
2393 ( ( p
[ 2 ] == '5' ) ) &&
2394 ( ( p
[ 3 ] == '4' ) ) &&
2395 ( ( p
[ 4 ] == '.' ) ) &&
2396 ( ( p
[ 5 ] == '1' ) ) &&
2397 ( ( p
[ 6 ] == '6' ) ) &&
2398 ( ( p
[ 7 ] == '9' ) ) &&
2399 ( ( p
[ 8 ] == '.' ) ) &&
2400 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
2401 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
2402 ( ( p
[ 11 ] == '-' ) ) &&
2403 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
2404 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
2405 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
2406 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
2407 ( ( p
[ 16 ] == '.' ) ) &&
2408 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
2409 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
2410 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
2411 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
2412 exit
, err
= WSASERVICE_NOT_FOUND
);
2415 // It's a reverse lookup
2417 check( err
== kNoErr
);
2425 //===========================================================================================================================
2427 //===========================================================================================================================
2430 GetScopeId( DWORD ifIndex
)
2435 struct ifaddrs
* head
;
2436 struct ifaddrs
** next
;
2437 IP_ADAPTER_ADDRESSES
* iaaList
;
2439 IP_ADAPTER_ADDRESSES
* iaa
;
2446 require( gGetAdaptersAddressesFunctionPtr
, exit
);
2448 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2449 // This loops to handle the case where the interface changes in the window after getting the size, but before the
2450 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2452 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
2457 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
2458 check( err
== ERROR_BUFFER_OVERFLOW
);
2459 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
2461 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
2462 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
2464 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
2465 if( err
== ERROR_SUCCESS
) break;
2470 require( i
< 100, exit
);
2471 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
2474 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
2478 if ( iaa
->IfIndex
> 0xFFFFFF )
2482 if ( iaa
->Ipv6IfIndex
> 0xFF )
2487 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
2488 // following code to crash when iterating through the prefix list. This seems
2489 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
2490 // This shouldn't happen according to Microsoft docs which states:
2492 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
2494 // So the data structure seems to be corrupted when we return from
2495 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
2496 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
2497 // modify iaa to have the correct values.
2499 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
2501 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
2508 // Skip psuedo and tunnel interfaces.
2510 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
2515 if ( iaa
->IfIndex
== ifIndex
)
2517 scopeId
= iaa
->Ipv6IfIndex
;