1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.20 2006/08/14 23:26:10 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.19 2006/06/08 23:09:37 cheshire
24 Updated comment: Correct IPv6LL reverse-mapping domains are '{8,9,A,B}.E.F.ip6.arpa.',
25 not only '0.8.E.F.ip6.arpa.' (Actual code still needs to be fixed.)
27 Revision 1.18 2005/10/17 05:45:36 herscher
28 Fix typo in previous checkin
30 Revision 1.17 2005/10/17 05:30:00 herscher
31 <rdar://problem/4071610> NSP should handle IPv6 AAAA queries for dot-local names
33 Revision 1.16 2005/09/16 22:22:48 herscher
34 <rdar://problem/4261460> No longer set the PATH variable when NSP is loaded.
36 Revision 1.15 2005/07/14 22:12:00 shersche
37 <rdar://problem/4178448> Delay load dnssd.dll so that it gracefully handles library loading problems immediately after installing Bonjour
39 Revision 1.14 2005/03/29 20:35:28 shersche
40 <rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
42 Revision 1.13 2005/03/29 19:42:47 shersche
43 Do label check before checking etc/hosts file
45 Revision 1.12 2005/03/21 00:42:45 shersche
46 <rdar://problem/4021486> Fix build warnings on Win32 platform
48 Revision 1.11 2005/03/16 03:04:51 shersche
49 <rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
51 Revision 1.10 2005/02/23 22:16:07 shersche
52 Unregister the NSP before registering to workaround an installer problem during upgrade installs
54 Revision 1.9 2005/02/01 01:45:55 shersche
55 Change mdnsNSP timeout to 2 seconds
57 Revision 1.8 2005/01/31 23:27:25 shersche
58 <rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
60 Revision 1.7 2005/01/28 23:50:13 shersche
61 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
64 Revision 1.6 2004/12/06 01:56:53 shersche
65 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
68 Revision 1.5 2004/07/13 21:24:28 rpantos
69 Fix for <rdar://problem/3701120>.
71 Revision 1.4 2004/07/09 18:03:33 shersche
72 removed extraneous DNSServiceQueryRecord call
74 Revision 1.3 2004/07/07 17:03:49 shersche
75 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
78 Revision 1.2 2004/06/24 19:18:07 shersche
80 Submitted by: herscher
82 Revision 1.1 2004/06/18 04:13:44 rpantos
85 Revision 1.2 2004/04/08 09:43:43 bradley
86 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
88 Revision 1.1 2004/01/30 03:00:33 bradley
89 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
90 .local name lookups using Multicast DNS in all Windows apps.
99 #include "CommonServices.h"
100 #include "DebugServices.h"
102 #include <iphlpapi.h>
111 #pragma comment(lib, "DelayImp.lib")
114 #define swprintf _snwprintf
115 #define snprintf _snprintf
119 #pragma mark == Structures ==
122 //===========================================================================================================================
124 //===========================================================================================================================
126 typedef struct Query
* QueryRef
;
127 typedef struct Query Query
;
133 WSAQUERYSETW
* querySet
;
138 HANDLE waitHandles
[ 3 ];
140 DNSServiceRef resolver4
;
141 DNSServiceRef resolver6
;
142 char name
[ kDNSServiceMaxDomainName
];
144 uint8_t numValidAddrs
;
152 #define BUFFER_INITIAL_SIZE 4192
153 #define ALIASES_INITIAL_SIZE 5
155 typedef struct HostsFile
163 typedef struct HostsFileInfo
165 struct hostent m_host
;
166 struct HostsFileInfo
* m_next
;
171 #pragma mark == Prototypes ==
174 //===========================================================================================================================
176 //===========================================================================================================================
180 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
181 STDAPI
DllRegisterServer( void );
182 STDAPI
DllRegisterServer( void );
187 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
189 DEBUG_LOCAL
int WSPAPI
190 NSPLookupServiceBegin(
192 LPWSAQUERYSETW inQuerySet
,
193 LPWSASERVICECLASSINFOW inServiceClassInfo
,
195 LPHANDLE outLookup
);
197 DEBUG_LOCAL
int WSPAPI
198 NSPLookupServiceNext(
201 LPDWORD ioBufferLength
,
202 LPWSAQUERYSETW outResults
);
204 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
206 DEBUG_LOCAL
int WSPAPI
209 LPWSASERVICECLASSINFOW inServiceClassInfo
,
210 LPWSAQUERYSETW inRegInfo
,
211 WSAESETSERVICEOP inOperation
,
214 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
);
215 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
);
216 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioBufSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
);
220 #define NSPLock() EnterCriticalSection( &gLock );
221 #define NSPUnlock() LeaveCriticalSection( &gLock );
223 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
);
224 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
);
225 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
);
227 DEBUG_LOCAL
void CALLBACK_COMPAT
228 QueryRecordCallback4(
230 DNSServiceFlags inFlags
,
231 uint32_t inInterfaceIndex
,
232 DNSServiceErrorType inErrorCode
,
236 uint16_t inRDataSize
,
237 const void * inRData
,
241 DEBUG_LOCAL
void CALLBACK_COMPAT
242 QueryRecordCallback6(
244 DNSServiceFlags inFlags
,
245 uint32_t inInterfaceIndex
,
246 DNSServiceErrorType inErrorCode
,
250 uint16_t inRDataSize
,
251 const void * inRData
,
258 const WSAQUERYSETW
* inQuerySet
,
259 DWORD inQuerySetFlags
,
260 WSAQUERYSETW
** outQuerySet
,
266 const WSAQUERYSETW
* inQuerySet
,
267 DWORD inQuerySetFlags
,
268 WSAQUERYSETW
* outQuerySet
);
270 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
273 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
275 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
277 #define dlog_query_set( LEVEL, SET )
280 DEBUG_LOCAL BOOL
InHostsTable( const char * name
);
281 DEBUG_LOCAL BOOL
IsLocalName( HostsFileInfo
* node
);
282 DEBUG_LOCAL BOOL
IsSameName( HostsFileInfo
* node
, const char * name
);
283 DEBUG_LOCAL OSStatus
HostsFileOpen( HostsFile
** self
, const char * fname
);
284 DEBUG_LOCAL OSStatus
HostsFileClose( HostsFile
* self
);
285 DEBUG_LOCAL
void HostsFileInfoFree( HostsFileInfo
* info
);
286 DEBUG_LOCAL OSStatus
HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
);
287 DEBUG_LOCAL
const char * GetNextLabel( const char *cstr
, char label
[64] );
288 DEBUG_LOCAL DWORD
GetScopeId( DWORD ifIndex
);
290 #ifdef ENABLE_REVERSE_LOOKUP
291 DEBUG_LOCAL OSStatus
IsReverseLookup( LPCWSTR name
, size_t size
);
296 #pragma mark == Globals ==
299 //===========================================================================================================================
301 //===========================================================================================================================
303 // {B600E6E9-553B-4a19-8696-335E5C896153}
304 DEBUG_LOCAL HINSTANCE gInstance
= NULL
;
305 DEBUG_LOCAL
wchar_t * gNSPName
= L
"mdnsNSP";
306 DEBUG_LOCAL GUID gNSPGUID
= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
307 DEBUG_LOCAL LONG gRefCount
= 0;
308 DEBUG_LOCAL CRITICAL_SECTION gLock
;
309 DEBUG_LOCAL
bool gLockInitialized
= false;
310 DEBUG_LOCAL QueryRef gQueryList
= NULL
;
311 DEBUG_LOCAL HostsFileInfo
* gHostsFileInfo
= NULL
;
313 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
317 PIP_ADAPTER_ADDRESSES inAdapter
,
318 PULONG outBufferSize
);
320 DEBUG_LOCAL HMODULE gIPHelperLibraryInstance
= NULL
;
321 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
329 //===========================================================================================================================
331 //===========================================================================================================================
333 BOOL APIENTRY
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
335 DEBUG_USE_ONLY( inInstance
);
336 DEBUG_UNUSED( inReserved
);
340 case DLL_PROCESS_ATTACH
:
341 gInstance
= inInstance
;
342 gHostsFileInfo
= NULL
;
343 debug_initialize( kDebugOutputTypeWindowsEventLog
, "mDNS NSP", inInstance
);
344 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelNotice
);
345 dlog( kDebugLevelTrace
, "\n" );
346 dlog( kDebugLevelVerbose
, "%s: process attach\n", __ROUTINE__
);
350 case DLL_PROCESS_DETACH
:
351 HostsFileInfoFree( gHostsFileInfo
);
352 gHostsFileInfo
= NULL
;
353 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
356 case DLL_THREAD_ATTACH
:
357 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
360 case DLL_THREAD_DETACH
:
361 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
365 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
373 //===========================================================================================================================
375 //===========================================================================================================================
377 STDAPI
DllRegisterServer( void )
380 WCHAR path
[ MAX_PATH
];
383 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
385 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
386 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
387 require_noerr( err
, exit
);
389 // Unregister before registering to workaround an installer
390 // problem during upgrade installs.
392 WSCUnInstallNameSpace( &gNSPGUID
);
394 err
= GetModuleFileNameW( gInstance
, path
, sizeof( path
) );
395 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
396 require_noerr( err
, exit
);
398 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
399 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
400 require_noerr( err
, exit
);
408 //===========================================================================================================================
409 // DllUnregisterServer
410 //===========================================================================================================================
412 STDAPI
DllUnregisterServer( void )
417 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
419 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
420 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
421 require_noerr( err
, exit
);
423 err
= WSCUnInstallNameSpace( &gNSPGUID
);
424 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
425 require_noerr( err
, exit
);
434 //===========================================================================================================================
437 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
438 //===========================================================================================================================
440 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
444 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
445 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
447 // Only initialize if this is the first time NSPStartup is called.
449 if( InterlockedIncrement( &gRefCount
) != 1 )
455 // Initialize our internal state.
457 InitializeCriticalSection( &gLock
);
458 gLockInitialized
= true;
460 // Set the size to exclude NSPIoctl because we don't implement it.
462 outRoutines
->cbSize
= FIELD_OFFSET( NSP_ROUTINE
, NSPIoctl
);
463 outRoutines
->dwMajorVersion
= 4;
464 outRoutines
->dwMinorVersion
= 4;
465 outRoutines
->NSPCleanup
= NSPCleanup
;
466 outRoutines
->NSPLookupServiceBegin
= NSPLookupServiceBegin
;
467 outRoutines
->NSPLookupServiceNext
= NSPLookupServiceNext
;
468 outRoutines
->NSPLookupServiceEnd
= NSPLookupServiceEnd
;
469 outRoutines
->NSPSetService
= NSPSetService
;
470 outRoutines
->NSPInstallServiceClass
= NSPInstallServiceClass
;
471 outRoutines
->NSPRemoveServiceClass
= NSPRemoveServiceClass
;
472 outRoutines
->NSPGetServiceClassInfo
= NSPGetServiceClassInfo
;
474 // See if we can get the address for the GetAdaptersAddresses() API. This is only in XP, but we want our
475 // code to run on older versions of Windows
477 if ( !gIPHelperLibraryInstance
)
479 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
480 if( gIPHelperLibraryInstance
)
482 gGetAdaptersAddressesFunctionPtr
= (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
489 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
490 if( err
!= NO_ERROR
)
492 NSPCleanup( inProviderID
);
493 SetLastError( (DWORD
) err
);
494 return( SOCKET_ERROR
);
499 //===========================================================================================================================
502 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
503 //===========================================================================================================================
505 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
507 DEBUG_USE_ONLY( inProviderID
);
509 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
510 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
512 // Only initialize if this is the first time NSPStartup is called.
514 if( InterlockedDecrement( &gRefCount
) != 0 )
519 // Stop any outstanding queries.
521 if( gLockInitialized
)
527 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
528 QueryRelease( gQueryList
);
530 if( gLockInitialized
)
535 if( gLockInitialized
)
537 gLockInitialized
= false;
538 DeleteCriticalSection( &gLock
);
541 if( gIPHelperLibraryInstance
)
545 ok
= FreeLibrary( gIPHelperLibraryInstance
);
546 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
547 gIPHelperLibraryInstance
= NULL
;
551 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
555 //===========================================================================================================================
556 // NSPLookupServiceBegin
558 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
559 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
560 // opposed to specifying the query parameters each time.
561 //===========================================================================================================================
563 DEBUG_LOCAL
int WSPAPI
564 NSPLookupServiceBegin(
566 LPWSAQUERYSETW inQuerySet
,
567 LPWSASERVICECLASSINFOW inServiceClassInfo
,
582 DEBUG_UNUSED( inProviderID
);
583 DEBUG_UNUSED( inServiceClassInfo
);
585 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
588 require_action( inQuerySet
, exit
, err
= WSAEINVAL
);
589 name
= inQuerySet
->lpszServiceInstanceName
;
590 require_action_quiet( name
, exit
, err
= WSAEINVAL
);
591 require_action( outLookup
, exit
, err
= WSAEINVAL
);
593 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__
, inFlags
, name
);
594 dlog_query_set( kDebugLevelVerbose
, inQuerySet
);
596 // Check if we can handle this type of request and if we support any of the protocols being requested.
597 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
599 require_action_quiet( inFlags
& (LUP_RETURN_ADDR
|LUP_RETURN_BLOB
), exit
, err
= WSASERVICE_NOT_FOUND
);
601 type
= inQuerySet
->dwNameSpace
;
602 require_action_quiet( ( type
== NS_DNS
) || ( type
== NS_ALL
), exit
, err
= WSASERVICE_NOT_FOUND
);
604 n
= inQuerySet
->dwNumberOfProtocols
;
607 require_action( inQuerySet
->lpafpProtocols
, exit
, err
= WSAEINVAL
);
608 for( i
= 0; i
< n
; ++i
)
610 family
= inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
;
611 protocol
= inQuerySet
->lpafpProtocols
[ i
].iProtocol
;
612 if( ( family
== AF_INET
) && ( ( protocol
== IPPROTO_UDP
) || ( protocol
== IPPROTO_TCP
) ) )
617 require_action_quiet( i
< n
, exit
, err
= WSASERVICE_NOT_FOUND
);
620 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
621 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
622 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
623 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
624 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
626 for( p
= name
; *p
; ++p
) {} // Find end of string
627 size
= (size_t)( p
- name
);
628 require_action_quiet( size
> sizeof_string( ".local" ), exit
, err
= WSASERVICE_NOT_FOUND
);
630 p
= name
+ ( size
- 1 );
631 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".local" ) ) : ( ( p
- sizeof_string( ".local" ) ) + 1 );
632 if ( ( ( p
[ 0 ] != '.' ) ||
633 ( ( p
[ 1 ] != 'L' ) && ( p
[ 1 ] != 'l' ) ) ||
634 ( ( p
[ 2 ] != 'O' ) && ( p
[ 2 ] != 'o' ) ) ||
635 ( ( p
[ 3 ] != 'C' ) && ( p
[ 3 ] != 'c' ) ) ||
636 ( ( p
[ 4 ] != 'A' ) && ( p
[ 4 ] != 'a' ) ) ||
637 ( ( p
[ 5 ] != 'L' ) && ( p
[ 5 ] != 'l' ) ) ) )
639 #ifdef ENABLE_REVERSE_LOOKUP
641 err
= IsReverseLookup( name
, size
);
645 err
= WSASERVICE_NOT_FOUND
;
649 require_noerr( err
, exit
);
653 const char * replyDomain
;
654 char translated
[ kDNSServiceMaxDomainName
];
657 const char * label
[128];
660 n
= WideCharToMultiByte( CP_UTF8
, 0, name
, -1, translated
, sizeof( translated
), NULL
, NULL
);
661 require_action( n
> 0, exit
, err
= WSASERVICE_NOT_FOUND
);
663 // <rdar://problem/4050633>
665 // Don't resolve multi-label name
667 replyDomain
= translated
;
669 while ( *replyDomain
)
671 label
[labels
++] = replyDomain
;
672 replyDomain
= GetNextLabel(replyDomain
, text
);
675 require_action( labels
== 2, exit
, err
= WSASERVICE_NOT_FOUND
);
677 // <rdar://problem/3936771>
679 // Check to see if the name of this host is in the hosts table. If so,
680 // don't try and resolve it
682 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
685 // The name ends in .local ( and isn't in the hosts table ), {8,9,A,B}.E.F.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
689 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
691 require_noerr( err
, exit
);
693 *outLookup
= (HANDLE
) obj
;
696 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
697 if( err
!= NO_ERROR
)
699 SetLastError( (DWORD
) err
);
700 return( SOCKET_ERROR
);
705 //===========================================================================================================================
706 // NSPLookupServiceNext
708 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
709 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
710 // in the lpqsResults parameter.
711 //===========================================================================================================================
713 DEBUG_LOCAL
int WSPAPI
714 NSPLookupServiceNext(
718 LPWSAQUERYSETW outResults
)
727 DEBUG_USE_ONLY( inFlags
);
729 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
735 err
= QueryRetain( (QueryRef
) inLookup
);
736 require_noerr( err
, exit
);
737 obj
= (QueryRef
) inLookup
;
738 require_action( ioSize
, exit
, err
= WSAEINVAL
);
739 require_action( outResults
, exit
, err
= WSAEINVAL
);
741 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
743 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
746 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
748 require_action_quiet( waitResult
!= ( WAIT_OBJECT_0
), exit
, err
= WSA_E_CANCELLED
);
749 err
= translate_errno( ( waitResult
== WAIT_OBJECT_0
+ 1 ) || ( waitResult
== WAIT_OBJECT_0
+ 2 ), (OSStatus
) GetLastError(), WSASERVICE_NOT_FOUND
);
750 require_noerr_quiet( err
, exit
);
752 // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
754 if ( waitResult
== WAIT_OBJECT_0
+ 1 )
757 data6
= WaitForSingleObject( obj
->data6Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
760 // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
762 else if ( waitResult
== WAIT_OBJECT_0
+ 2 )
764 data4
= WaitForSingleObject( obj
->data4Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
772 err
= DNSServiceProcessResult(obj
->resolver4
);
774 __except( EXCEPTION_EXECUTE_HANDLER
)
779 require_noerr( err
, exit
);
786 err
= DNSServiceProcessResult( obj
->resolver6
);
788 __except( EXCEPTION_EXECUTE_HANDLER
)
793 require_noerr( err
, exit
);
796 require_action_quiet( obj
->addr4Valid
|| obj
->addr6Valid
, exit
, err
= WSA_E_NO_MORE
);
798 // Copy the externalized query results to the callers buffer (if it fits).
800 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
801 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
803 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
804 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
805 obj
->addr4Valid
= false;
806 obj
->addr6Valid
= false;
814 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
815 if( err
!= NO_ERROR
)
817 SetLastError( (DWORD
) err
);
818 return( SOCKET_ERROR
);
823 //===========================================================================================================================
824 // NSPLookupServiceEnd
826 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
827 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
828 // allocated resources associated with the query.
829 //===========================================================================================================================
831 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
835 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
837 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
840 err
= QueryRelease( (QueryRef
) inLookup
);
842 require_noerr( err
, exit
);
845 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
846 if( err
!= NO_ERROR
)
848 SetLastError( (DWORD
) err
);
849 return( SOCKET_ERROR
);
854 //===========================================================================================================================
857 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
858 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
859 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
860 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
861 //===========================================================================================================================
863 DEBUG_LOCAL
int WSPAPI
866 LPWSASERVICECLASSINFOW inServiceClassInfo
,
867 LPWSAQUERYSETW inRegInfo
,
868 WSAESETSERVICEOP inOperation
,
871 DEBUG_UNUSED( inProviderID
);
872 DEBUG_UNUSED( inServiceClassInfo
);
873 DEBUG_UNUSED( inRegInfo
);
874 DEBUG_UNUSED( inOperation
);
875 DEBUG_UNUSED( inFlags
);
877 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
878 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
880 // We don't allow services to be registered so always return an error.
882 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
886 //===========================================================================================================================
887 // NSPInstallServiceClass
889 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
890 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
891 // instance of a server may be registered.
892 //===========================================================================================================================
894 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
896 DEBUG_UNUSED( inProviderID
);
897 DEBUG_UNUSED( inServiceClassInfo
);
899 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
900 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
902 // We don't allow service classes to be installed so always return an error.
904 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
905 return( WSA_INVALID_PARAMETER
);
908 //===========================================================================================================================
909 // NSPRemoveServiceClass
911 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
912 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
914 //===========================================================================================================================
916 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
918 DEBUG_UNUSED( inProviderID
);
919 DEBUG_UNUSED( inServiceClassID
);
921 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
922 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
924 // We don't allow service classes to be installed so always return an error.
926 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
927 return( WSATYPE_NOT_FOUND
);
930 //===========================================================================================================================
931 // NSPGetServiceClassInfo
933 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
934 // a given service class.
935 //===========================================================================================================================
937 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
939 DEBUG_UNUSED( inProviderID
);
940 DEBUG_UNUSED( ioSize
);
941 DEBUG_UNUSED( ioServiceClassInfo
);
943 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
944 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
946 // We don't allow service classes to be installed so always return an error.
948 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
949 return( WSATYPE_NOT_FOUND
);
956 //===========================================================================================================================
959 // Warning: Assumes the NSP lock is held.
960 //===========================================================================================================================
962 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
966 char name
[ kDNSServiceMaxDomainName
];
974 check( inQuerySet
->lpszServiceInstanceName
);
977 // Convert the wchar_t name to UTF-8.
979 n
= WideCharToMultiByte( CP_UTF8
, 0, inQuerySet
->lpszServiceInstanceName
, -1, name
, sizeof( name
), NULL
, NULL
);
980 err
= translate_errno( n
> 0, (OSStatus
) GetLastError(), WSAEINVAL
);
981 require_noerr( err
, exit
);
983 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
985 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
986 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
990 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
993 // Set up cancel event
995 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
996 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
998 // Set up events to signal when A record data is ready
1000 obj
->data4Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1001 require_action( obj
->data4Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1003 // Start the query. Handle delay loaded DLL errors.
1007 err
= DNSServiceQueryRecord( &obj
->resolver4
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
, QueryRecordCallback4
, obj
);
1009 __except( EXCEPTION_EXECUTE_HANDLER
)
1014 require_noerr( err
, exit
);
1016 // Attach the socket to the event
1020 s4
= DNSServiceRefSockFD(obj
->resolver4
);
1022 __except( EXCEPTION_EXECUTE_HANDLER
)
1024 s4
= INVALID_SOCKET
;
1027 err
= translate_errno( s4
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1028 require_noerr( err
, exit
);
1030 WSAEventSelect(s4
, obj
->data4Event
, FD_READ
|FD_CLOSE
);
1032 // Set up events to signal when AAAA record data is ready
1034 obj
->data6Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1035 require_action( obj
->data6Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1037 // Start the query. Handle delay loaded DLL errors.
1041 err
= DNSServiceQueryRecord( &obj
->resolver6
, 0, 0, name
, kDNSServiceType_AAAA
, kDNSServiceClass_IN
, QueryRecordCallback6
, obj
);
1043 __except( EXCEPTION_EXECUTE_HANDLER
)
1048 require_noerr( err
, exit
);
1050 // Attach the socket to the event
1054 s6
= DNSServiceRefSockFD(obj
->resolver6
);
1056 __except( EXCEPTION_EXECUTE_HANDLER
)
1058 s6
= INVALID_SOCKET
;
1061 err
= translate_errno( s6
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1062 require_noerr( err
, exit
);
1064 WSAEventSelect(s6
, obj
->data6Event
, FD_READ
|FD_CLOSE
);
1067 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
1068 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data4Event
;
1069 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data6Event
;
1071 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
1073 // Copy the QuerySet so it can be returned later.
1075 obj
->querySetFlags
= inQuerySetFlags
;
1076 inQuerySetFlags
= ( inQuerySetFlags
& ~( LUP_RETURN_ADDR
| LUP_RETURN_BLOB
) ) | LUP_RETURN_NAME
;
1077 err
= QueryCopyQuerySet( obj
, inQuerySet
, inQuerySetFlags
, &obj
->querySet
, &obj
->querySetSize
);
1078 require_noerr( err
, exit
);
1089 QueryRelease( obj
);
1094 //===========================================================================================================================
1097 // Warning: Assumes the NSP lock is held.
1098 //===========================================================================================================================
1100 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
1105 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
1112 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
1121 //===========================================================================================================================
1124 // Warning: Assumes the NSP lock is held.
1125 //===========================================================================================================================
1127 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
1133 // Find the item in the list.
1135 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
1142 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
1144 // Signal a cancel to unblock any threads waiting for results.
1146 if( inRef
->cancelEvent
)
1148 ok
= SetEvent( inRef
->cancelEvent
);
1149 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1154 if( inRef
->resolver4
)
1158 DNSServiceRefDeallocate( inRef
->resolver4
);
1160 __except( EXCEPTION_EXECUTE_HANDLER
)
1164 inRef
->resolver4
= NULL
;
1167 if ( inRef
->resolver6
)
1171 DNSServiceRefDeallocate( inRef
->resolver6
);
1173 __except( EXCEPTION_EXECUTE_HANDLER
)
1177 inRef
->resolver6
= NULL
;
1180 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
1182 if( --inRef
->refCount
!= 0 )
1189 // Release resources.
1191 if( inRef
->cancelEvent
)
1193 ok
= CloseHandle( inRef
->cancelEvent
);
1194 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1196 if( inRef
->data4Event
)
1198 ok
= CloseHandle( inRef
->data4Event
);
1199 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1201 if( inRef
->data6Event
)
1203 ok
= CloseHandle( inRef
->data6Event
);
1204 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1206 if( inRef
->querySet
)
1208 free( inRef
->querySet
);
1217 //===========================================================================================================================
1218 // QueryRecordCallback4
1219 //===========================================================================================================================
1221 DEBUG_LOCAL
void CALLBACK_COMPAT
1222 QueryRecordCallback4(
1223 DNSServiceRef inRef
,
1224 DNSServiceFlags inFlags
,
1225 uint32_t inInterfaceIndex
,
1226 DNSServiceErrorType inErrorCode
,
1227 const char * inName
,
1230 uint16_t inRDataSize
,
1231 const void * inRData
,
1240 DEBUG_UNUSED( inFlags
);
1241 DEBUG_UNUSED( inInterfaceIndex
);
1242 DEBUG_UNUSED( inTTL
);
1245 obj
= (QueryRef
) inContext
;
1247 require_noerr( inErrorCode
, exit
);
1248 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1249 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1250 require( inRRType
== kDNSServiceType_A
, exit
);
1251 require( inRDataSize
== 4, exit
);
1253 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1254 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1256 // Copy the name if needed.
1258 if( obj
->name
[ 0 ] == '\0' )
1262 while( *src
!= '\0' )
1267 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1268 check( obj
->nameSize
< sizeof( obj
->name
) );
1273 memcpy( &obj
->addr4
, inRData
, inRDataSize
);
1274 obj
->addr4Valid
= true;
1275 obj
->numValidAddrs
++;
1277 // Signal that a result is ready.
1279 check( obj
->data4Event
);
1280 ok
= SetEvent( obj
->data4Event
);
1281 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1283 // Stop the resolver after the first response.
1287 DNSServiceRefDeallocate( inRef
);
1289 __except( EXCEPTION_EXECUTE_HANDLER
)
1293 obj
->resolver4
= NULL
;
1304 //===========================================================================================================================
1305 // QueryRecordCallback6
1306 //===========================================================================================================================
1308 DEBUG_LOCAL
void CALLBACK_COMPAT
1309 QueryRecordCallback6(
1310 DNSServiceRef inRef
,
1311 DNSServiceFlags inFlags
,
1312 uint32_t inInterfaceIndex
,
1313 DNSServiceErrorType inErrorCode
,
1314 const char * inName
,
1317 uint16_t inRDataSize
,
1318 const void * inRData
,
1327 DEBUG_UNUSED( inFlags
);
1328 DEBUG_UNUSED( inInterfaceIndex
);
1329 DEBUG_UNUSED( inTTL
);
1332 obj
= (QueryRef
) inContext
;
1334 require_noerr( inErrorCode
, exit
);
1335 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1336 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1337 require( inRRType
== kDNSServiceType_AAAA
, exit
);
1338 require( inRDataSize
== 16, exit
);
1340 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1341 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1343 // Copy the name if needed.
1345 if( obj
->name
[ 0 ] == '\0' )
1349 while( *src
!= '\0' )
1354 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1355 check( obj
->nameSize
< sizeof( obj
->name
) );
1360 memcpy( &obj
->addr6
, inRData
, inRDataSize
);
1362 obj
->addr6ScopeId
= GetScopeId( inInterfaceIndex
);
1363 require( obj
->addr6ScopeId
, exit
);
1364 obj
->addr6Valid
= true;
1365 obj
->numValidAddrs
++;
1367 // Signal that we're done
1369 check( obj
->data6Event
);
1370 ok
= SetEvent( obj
->data6Event
);
1371 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1373 // Stop the resolver after the first response.
1377 DNSServiceRefDeallocate( inRef
);
1379 __except( EXCEPTION_EXECUTE_HANDLER
)
1383 obj
->resolver6
= NULL
;
1393 //===========================================================================================================================
1394 // QueryCopyQuerySet
1396 // Warning: Assumes the NSP lock is held.
1397 //===========================================================================================================================
1399 DEBUG_LOCAL OSStatus
1402 const WSAQUERYSETW
* inQuerySet
,
1403 DWORD inQuerySetFlags
,
1404 WSAQUERYSETW
** outQuerySet
,
1411 check( inQuerySet
);
1412 check( outQuerySet
);
1414 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1415 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1416 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1418 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1438 //===========================================================================================================================
1439 // QueryCopyQuerySetTo
1441 // Warning: Assumes the NSP lock is held.
1442 //===========================================================================================================================
1445 QueryCopyQuerySetTo(
1447 const WSAQUERYSETW
* inQuerySet
,
1448 DWORD inQuerySetFlags
,
1449 WSAQUERYSETW
* outQuerySet
)
1460 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1463 check( inQuerySet
);
1464 check( outQuerySet
);
1466 dst
= (uint8_t *) outQuerySet
;
1468 // Copy the static portion of the results.
1470 *outQuerySet
= *inQuerySet
;
1471 dst
+= sizeof( *inQuerySet
);
1473 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1475 s
= inQuerySet
->lpszServiceInstanceName
;
1478 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1480 while( ( *q
++ = *s
++ ) != 0 ) {}
1481 dst
= (uint8_t *) q
;
1486 outQuerySet
->lpszServiceInstanceName
= NULL
;
1489 if( inQuerySet
->lpServiceClassId
)
1491 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1492 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1493 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1496 if( inQuerySet
->lpVersion
)
1498 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1499 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1500 dst
+= sizeof( *inQuerySet
->lpVersion
);
1503 s
= inQuerySet
->lpszComment
;
1506 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1508 while( ( *q
++ = *s
++ ) != 0 ) {}
1509 dst
= (uint8_t *) q
;
1512 if( inQuerySet
->lpNSProviderId
)
1514 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1515 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1516 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1519 s
= inQuerySet
->lpszContext
;
1522 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1524 while( ( *q
++ = *s
++ ) != 0 ) {}
1525 dst
= (uint8_t *) q
;
1528 n
= inQuerySet
->dwNumberOfProtocols
;
1532 check( inQuerySet
->lpafpProtocols
);
1534 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1535 for( i
= 0; i
< n
; ++i
)
1537 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1538 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1542 s
= inQuerySet
->lpszQueryString
;
1545 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1547 while( ( *q
++ = *s
++ ) != 0 ) {}
1548 dst
= (uint8_t *) q
;
1551 // Copy the address(es).
1553 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && ( inRef
->numValidAddrs
> 0 ) )
1555 struct sockaddr_in
* addr4
;
1556 struct sockaddr_in6
* addr6
;
1559 outQuerySet
->dwNumberOfCsAddrs
= inRef
->numValidAddrs
;
1560 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1561 dst
+= ( sizeof( *outQuerySet
->lpcsaBuffer
) ) * ( inRef
->numValidAddrs
) ;
1564 if ( inRef
->addr4Valid
)
1566 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1567 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1569 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1570 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
1572 addr4
= (struct sockaddr_in
*) dst
;
1573 memset( addr4
, 0, sizeof( *addr4
) );
1574 addr4
->sin_family
= AF_INET
;
1575 memcpy( &addr4
->sin_addr
, &inRef
->addr4
, 4 );
1576 dst
+= sizeof( *addr4
);
1578 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1579 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1584 if ( inRef
->addr6Valid
)
1586 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1587 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1589 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1590 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in6
);
1592 addr6
= (struct sockaddr_in6
*) dst
;
1593 memset( addr6
, 0, sizeof( *addr6
) );
1594 addr6
->sin6_family
= AF_INET6
;
1595 addr6
->sin6_scope_id
= inRef
->addr6ScopeId
;
1596 memcpy( &addr6
->sin6_addr
, &inRef
->addr6
, 16 );
1597 dst
+= sizeof( *addr6
);
1599 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET6
; // Emulate Tcpip NSP
1600 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1605 outQuerySet
->dwNumberOfCsAddrs
= 0;
1606 outQuerySet
->lpcsaBuffer
= NULL
;
1609 // Copy the hostent blob.
1611 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1614 struct hostent
* he
;
1617 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1618 dst
+= sizeof( *outQuerySet
->lpBlob
);
1621 he
= (struct hostent
*) dst
;
1622 dst
+= sizeof( *he
);
1624 he
->h_name
= (char *)( dst
- base
);
1625 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1626 dst
+= ( inRef
->nameSize
+ 1 );
1628 he
->h_aliases
= (char **)( dst
- base
);
1629 p
= (uintptr_t *) dst
;
1631 dst
= (uint8_t *) p
;
1633 he
->h_addrtype
= AF_INET
;
1636 he
->h_addr_list
= (char **)( dst
- base
);
1637 p
= (uintptr_t *) dst
;
1638 dst
+= ( 2 * sizeof( *p
) );
1639 *p
++ = (uintptr_t)( dst
- base
);
1641 p
= (uintptr_t *) dst
;
1642 *p
++ = (uintptr_t) inRef
->addr4
;
1643 dst
= (uint8_t *) p
;
1645 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1646 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1648 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1650 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1653 //===========================================================================================================================
1654 // QueryCopyQuerySetSize
1656 // Warning: Assumes the NSP lock is held.
1657 //===========================================================================================================================
1659 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1666 check( inQuerySet
);
1668 // Calculate the size of the static portion of the results.
1670 size
= sizeof( *inQuerySet
);
1672 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1674 s
= inQuerySet
->lpszServiceInstanceName
;
1677 for( p
= s
; *p
; ++p
) {}
1678 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1682 if( inQuerySet
->lpServiceClassId
)
1684 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1687 if( inQuerySet
->lpVersion
)
1689 size
+= sizeof( *inQuerySet
->lpVersion
);
1692 s
= inQuerySet
->lpszComment
;
1695 for( p
= s
; *p
; ++p
) {}
1696 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1699 if( inQuerySet
->lpNSProviderId
)
1701 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1704 s
= inQuerySet
->lpszContext
;
1707 for( p
= s
; *p
; ++p
) {}
1708 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1711 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1713 s
= inQuerySet
->lpszQueryString
;
1716 for( p
= s
; *p
; ++p
) {}
1717 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1720 // Calculate the size of the address(es).
1722 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr4Valid
)
1724 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1725 size
+= sizeof( struct sockaddr_in
);
1728 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr6Valid
)
1730 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1731 size
+= sizeof( struct sockaddr_in6
);
1734 // Calculate the size of the hostent blob.
1736 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1738 size
+= sizeof( *inQuerySet
->lpBlob
); // Blob ptr/size structure
1739 size
+= sizeof( struct hostent
); // Old-style hostent structure
1740 size
+= ( inRef
->nameSize
+ 1 ); // Name and null terminator
1741 size
+= 4; // Alias list terminator (0 offset)
1742 size
+= 4; // Offset to address.
1743 size
+= 4; // Address list terminator (0 offset)
1744 size
+= 4; // IPv4 address
1754 //===========================================================================================================================
1755 // DebugDumpQuerySet
1756 //===========================================================================================================================
1758 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1759 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1761 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1762 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1764 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1766 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1770 check( inQuerySet
);
1772 // Fixed portion of the QuerySet.
1774 dlog( inLevel
, "QuerySet:\n" );
1775 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1776 if( inQuerySet
->lpszServiceInstanceName
)
1778 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1782 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1784 if( inQuerySet
->lpServiceClassId
)
1786 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1790 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1792 if( inQuerySet
->lpVersion
)
1794 dlog( inLevel
, " lpVersion:\n" );
1795 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1796 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1800 dlog( inLevel
, " lpVersion: <null>\n" );
1802 if( inQuerySet
->lpszComment
)
1804 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1808 dlog( inLevel
, " lpszComment: <null>\n" );
1810 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1811 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1812 if( inQuerySet
->lpNSProviderId
)
1814 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1818 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1820 if( inQuerySet
->lpszContext
)
1822 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1826 dlog( inLevel
, " lpszContext: <null>\n" );
1828 dlog( inLevel
, " dwNumberOfProtocols: %d\n", inQuerySet
->dwNumberOfProtocols
);
1829 dlog( inLevel
, " lpafpProtocols: %s\n", inQuerySet
->lpafpProtocols
? "" : "<null>" );
1830 for( i
= 0; i
< inQuerySet
->dwNumberOfProtocols
; ++i
)
1834 dlog( inLevel
, "\n" );
1836 dlog( inLevel
, " iAddressFamily: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
,
1837 DebugSocketFamilyToString( inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
) );
1838 dlog( inLevel
, " iProtocol: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iProtocol
,
1839 DebugSocketProtocolToString( inQuerySet
->lpafpProtocols
[ i
].iProtocol
) );
1841 if( inQuerySet
->lpszQueryString
)
1843 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1847 dlog( inLevel
, " lpszQueryString: <null>\n" );
1849 dlog( inLevel
, " dwNumberOfCsAddrs: %d\n", inQuerySet
->dwNumberOfCsAddrs
);
1850 dlog( inLevel
, " lpcsaBuffer: %s\n", inQuerySet
->lpcsaBuffer
? "" : "<null>" );
1851 for( i
= 0; i
< inQuerySet
->dwNumberOfCsAddrs
; ++i
)
1855 dlog( inLevel
, "\n" );
1857 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1858 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1860 dlog( inLevel
, " LocalAddr: %##a\n",
1861 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1865 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1867 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1868 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1870 dlog( inLevel
, " RemoteAddr: %##a\n",
1871 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1875 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1877 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1878 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1880 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1882 // Blob portion of the QuerySet.
1884 if( inQuerySet
->lpBlob
)
1886 dlog( inLevel
, " lpBlob:\n" );
1887 dlog( inLevel
, " cbSize: %ld\n", inQuerySet
->lpBlob
->cbSize
);
1888 dlog( inLevel
, " pBlobData: %#p\n", inQuerySet
->lpBlob
->pBlobData
);
1889 dloghex( inLevel
, 12, NULL
, 0, 0, NULL
, 0,
1890 inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->cbSize
,
1891 kDebugFlagsNone
, NULL
, 0 );
1895 dlog( inLevel
, " lpBlob: <null>\n" );
1901 //===========================================================================================================================
1903 //===========================================================================================================================
1906 InHostsTable( const char * name
)
1908 HostsFileInfo
* node
;
1914 if ( gHostsFileInfo
== NULL
)
1916 TCHAR systemDirectory
[MAX_PATH
];
1917 TCHAR hFileName
[MAX_PATH
];
1920 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1921 sprintf( hFileName
, "%s\\drivers\\etc\\hosts", systemDirectory
);
1922 err
= HostsFileOpen( &hFile
, hFileName
);
1923 require_noerr( err
, exit
);
1925 while ( HostsFileNext( hFile
, &node
) == 0 )
1927 if ( IsLocalName( node
) )
1929 node
->m_next
= gHostsFileInfo
;
1930 gHostsFileInfo
= node
;
1934 HostsFileInfoFree( node
);
1938 HostsFileClose( hFile
);
1941 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1943 if ( IsSameName( node
, name
) )
1956 //===========================================================================================================================
1958 //===========================================================================================================================
1961 IsLocalName( HostsFileInfo
* node
)
1967 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1971 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1973 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
1988 //===========================================================================================================================
1990 //===========================================================================================================================
1993 IsSameName( HostsFileInfo
* node
, const char * name
)
2000 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
2004 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
2006 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
2021 //===========================================================================================================================
2023 //===========================================================================================================================
2025 DEBUG_LOCAL OSStatus
2026 HostsFileOpen( HostsFile
** self
, const char * fname
)
2028 OSStatus err
= kNoErr
;
2030 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
2031 require_action( *self
, exit
, err
= kNoMemoryErr
);
2032 memset( *self
, 0, sizeof( HostsFile
) );
2034 (*self
)->m_bufferSize
= BUFFER_INITIAL_SIZE
;
2035 (*self
)->m_buffer
= (char*) malloc( (*self
)->m_bufferSize
);
2036 require_action( (*self
)->m_buffer
, exit
, err
= kNoMemoryErr
);
2040 (*self
)->m_fp
= fopen( fname
, "r" );
2041 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
2047 HostsFileClose( *self
);
2055 //===========================================================================================================================
2057 //===========================================================================================================================
2059 DEBUG_LOCAL OSStatus
2060 HostsFileClose( HostsFile
* self
)
2064 if ( self
->m_buffer
)
2066 free( self
->m_buffer
);
2067 self
->m_buffer
= NULL
;
2072 fclose( self
->m_fp
);
2082 //===========================================================================================================================
2083 // HostsFileInfoFree
2084 //===========================================================================================================================
2087 HostsFileInfoFree( HostsFileInfo
* info
)
2091 HostsFileInfo
* next
= info
->m_next
;
2093 if ( info
->m_host
.h_addr_list
)
2095 if ( info
->m_host
.h_addr_list
[0] )
2097 free( info
->m_host
.h_addr_list
[0] );
2098 info
->m_host
.h_addr_list
[0] = NULL
;
2101 free( info
->m_host
.h_addr_list
);
2102 info
->m_host
.h_addr_list
= NULL
;
2105 if ( info
->m_host
.h_aliases
)
2109 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
2111 free( info
->m_host
.h_aliases
[i
] );
2114 free( info
->m_host
.h_aliases
);
2117 if ( info
->m_host
.h_name
)
2119 free( info
->m_host
.h_name
);
2120 info
->m_host
.h_name
= NULL
;
2130 //===========================================================================================================================
2132 //===========================================================================================================================
2134 DEBUG_LOCAL OSStatus
2135 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
2137 struct sockaddr_in6 addr_6
;
2138 struct sockaddr_in addr_4
;
2139 int numAliases
= ALIASES_INITIAL_SIZE
;
2146 OSStatus err
= kNoErr
;
2149 check( self
->m_fp
);
2154 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
2155 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
2156 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
2160 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
2168 // If there's no eol and no eof, then we didn't get the whole line
2170 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
2175 /* Try and allocate space for longer line */
2177 bufferSize
= self
->m_bufferSize
* 2;
2178 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
2179 require_action( buffer
, exit
, err
= kNoMemoryErr
);
2180 self
->m_bufferSize
= bufferSize
;
2181 self
->m_buffer
= buffer
;
2182 idx
= (int) strlen( self
->m_buffer
);
2187 line
= self
->m_buffer
;
2195 // Get rid of either comments or eol characters
2197 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
2202 // Make sure there is some whitespace on this line
2204 if (( tok
= strpbrk(line
, " \t")) == NULL
)
2209 // Create two strings, where p == the IP Address and tok is the name list
2213 while ( *tok
== ' ' || *tok
== '\t')
2218 // Now we have the name
2220 (*hInfo
)->m_host
.h_name
= (char*) malloc( strlen( tok
) + 1 );
2221 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
2222 strcpy( (*hInfo
)->m_host
.h_name
, tok
);
2224 // Now create the address (IPv6/IPv4)
2226 addr_6
.sin6_family
= family
= AF_INET6
;
2227 dwSize
= sizeof( addr_6
);
2229 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
2231 addr_4
.sin_family
= family
= AF_INET
;
2232 dwSize
= sizeof( addr_4
);
2234 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
2240 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
2241 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
2243 if ( family
== AF_INET6
)
2245 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
2246 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2247 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2248 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
2253 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
2254 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2255 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2256 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
2259 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
2260 (*hInfo
)->m_host
.h_addrtype
= family
;
2262 // Now get the aliases
2264 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
2271 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
2272 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2273 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
2275 while ( tok
&& *tok
)
2277 // Skip over the whitespace, waiting for the start of the next alias name
2279 if (*tok
== ' ' || *tok
== '\t')
2285 // Check to make sure we don't exhaust the alias buffer
2287 if ( i
>= ( numAliases
- 1 ) )
2289 numAliases
= numAliases
* 2;
2290 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
2291 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2294 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( strlen( tok
) + 1 );
2295 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
2297 strcpy( (*hInfo
)->m_host
.h_aliases
[i
], tok
);
2299 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
2304 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
2312 if ( err
&& ( *hInfo
) )
2314 HostsFileInfoFree( *hInfo
);
2322 //===========================================================================================================================
2324 //===========================================================================================================================
2325 DEBUG_LOCAL
const char*
2326 GetNextLabel(const char *cstr
, char label
[64])
2329 while (*cstr
&& *cstr
!= '.') // While we have characters in the label...
2335 if (isdigit(cstr
[-1]) && isdigit(cstr
[0]) && isdigit(cstr
[1]))
2337 int v0
= cstr
[-1] - '0'; // then interpret as three-digit decimal
2338 int v1
= cstr
[ 0] - '0';
2339 int v2
= cstr
[ 1] - '0';
2340 int val
= v0
* 100 + v1
* 10 + v2
;
2341 if (val
<= 255) { c
= (char)val
; cstr
+= 2; } // If valid three-digit decimal value, use it
2345 if (ptr
>= label
+64) return(NULL
);
2347 if (*cstr
) cstr
++; // Skip over the trailing dot (if present)
2353 #ifdef ENABLE_REVERSE_LOOKUP
2354 //===========================================================================================================================
2356 //===========================================================================================================================
2358 DEBUG_LOCAL OSStatus
2359 IsReverseLookup( LPCWSTR name
, size_t size
)
2362 OSStatus err
= kNoErr
;
2364 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2366 p
= name
+ ( size
- 1 );
2367 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2369 if ( ( ( p
[ 0 ] != '.' ) ||
2370 ( ( p
[ 1 ] != '0' ) ) ||
2371 ( ( p
[ 2 ] != '.' ) ) ||
2372 ( ( p
[ 3 ] != '8' ) ) ||
2373 ( ( p
[ 4 ] != '.' ) ) ||
2374 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
2375 ( ( p
[ 6 ] != '.' ) ) ||
2376 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
2377 ( ( p
[ 8 ] != '.' ) ) ||
2378 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
2379 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
2380 ( ( p
[ 11 ] != '6' ) ) ||
2381 ( ( p
[ 12 ] != '.' ) ) ||
2382 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
2383 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
2384 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
2385 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
2387 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2389 p
= name
+ ( size
- 1 );
2390 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2392 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
2393 ( ( p
[ 1 ] == '2' ) ) &&
2394 ( ( p
[ 2 ] == '5' ) ) &&
2395 ( ( p
[ 3 ] == '4' ) ) &&
2396 ( ( p
[ 4 ] == '.' ) ) &&
2397 ( ( p
[ 5 ] == '1' ) ) &&
2398 ( ( p
[ 6 ] == '6' ) ) &&
2399 ( ( p
[ 7 ] == '9' ) ) &&
2400 ( ( p
[ 8 ] == '.' ) ) &&
2401 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
2402 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
2403 ( ( p
[ 11 ] == '-' ) ) &&
2404 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
2405 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
2406 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
2407 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
2408 ( ( p
[ 16 ] == '.' ) ) &&
2409 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
2410 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
2411 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
2412 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
2413 exit
, err
= WSASERVICE_NOT_FOUND
);
2416 // It's a reverse lookup
2418 check( err
== kNoErr
);
2426 //===========================================================================================================================
2428 //===========================================================================================================================
2431 GetScopeId( DWORD ifIndex
)
2436 struct ifaddrs
* head
;
2437 struct ifaddrs
** next
;
2438 IP_ADAPTER_ADDRESSES
* iaaList
;
2440 IP_ADAPTER_ADDRESSES
* iaa
;
2447 require( gGetAdaptersAddressesFunctionPtr
, exit
);
2449 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2450 // This loops to handle the case where the interface changes in the window after getting the size, but before the
2451 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2453 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
2458 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
2459 check( err
== ERROR_BUFFER_OVERFLOW
);
2460 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
2462 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
2463 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
2465 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
2466 if( err
== ERROR_SUCCESS
) break;
2471 require( i
< 100, exit
);
2472 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
2475 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
2479 if ( iaa
->IfIndex
> 0xFFFFFF )
2483 if ( iaa
->Ipv6IfIndex
> 0xFF )
2488 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
2489 // following code to crash when iterating through the prefix list. This seems
2490 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
2491 // This shouldn't happen according to Microsoft docs which states:
2493 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
2495 // So the data structure seems to be corrupted when we return from
2496 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
2497 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
2498 // modify iaa to have the correct values.
2500 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
2502 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
2509 // Skip psuedo and tunnel interfaces.
2511 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
2516 if ( iaa
->IfIndex
== ifIndex
)
2518 scopeId
= iaa
->Ipv6IfIndex
;