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.22 2009/03/30 20:34:51 herscher
21 <rdar://problem/5925472> Current Bonjour code does not compile on Windows
22 <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
24 Revision 1.21 2008/07/16 01:25:10 cheshire
25 <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
27 Revision 1.20 2006/08/14 23:26:10 cheshire
28 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
30 Revision 1.19 2006/06/08 23:09:37 cheshire
31 Updated comment: Correct IPv6LL reverse-mapping domains are '{8,9,A,B}.E.F.ip6.arpa.',
32 not only '0.8.E.F.ip6.arpa.' (Actual code still needs to be fixed.)
34 Revision 1.18 2005/10/17 05:45:36 herscher
35 Fix typo in previous checkin
37 Revision 1.17 2005/10/17 05:30:00 herscher
38 <rdar://problem/4071610> NSP should handle IPv6 AAAA queries for dot-local names
40 Revision 1.16 2005/09/16 22:22:48 herscher
41 <rdar://problem/4261460> No longer set the PATH variable when NSP is loaded.
43 Revision 1.15 2005/07/14 22:12:00 shersche
44 <rdar://problem/4178448> Delay load dnssd.dll so that it gracefully handles library loading problems immediately after installing Bonjour
46 Revision 1.14 2005/03/29 20:35:28 shersche
47 <rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
49 Revision 1.13 2005/03/29 19:42:47 shersche
50 Do label check before checking etc/hosts file
52 Revision 1.12 2005/03/21 00:42:45 shersche
53 <rdar://problem/4021486> Fix build warnings on Win32 platform
55 Revision 1.11 2005/03/16 03:04:51 shersche
56 <rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
58 Revision 1.10 2005/02/23 22:16:07 shersche
59 Unregister the NSP before registering to workaround an installer problem during upgrade installs
61 Revision 1.9 2005/02/01 01:45:55 shersche
62 Change mdnsNSP timeout to 2 seconds
64 Revision 1.8 2005/01/31 23:27:25 shersche
65 <rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
67 Revision 1.7 2005/01/28 23:50:13 shersche
68 <rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
71 Revision 1.6 2004/12/06 01:56:53 shersche
72 <rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
75 Revision 1.5 2004/07/13 21:24:28 rpantos
76 Fix for <rdar://problem/3701120>.
78 Revision 1.4 2004/07/09 18:03:33 shersche
79 removed extraneous DNSServiceQueryRecord call
81 Revision 1.3 2004/07/07 17:03:49 shersche
82 <rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
85 Revision 1.2 2004/06/24 19:18:07 shersche
87 Submitted by: herscher
89 Revision 1.1 2004/06/18 04:13:44 rpantos
92 Revision 1.2 2004/04/08 09:43:43 bradley
93 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
95 Revision 1.1 2004/01/30 03:00:33 bradley
96 mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
97 .local name lookups using Multicast DNS in all Windows apps.
106 #include "ClientCommon.h"
107 #include "CommonServices.h"
108 #include "DebugServices.h"
110 #include <iphlpapi.h>
119 #pragma comment(lib, "DelayImp.lib")
122 #define swprintf _snwprintf
123 #define snprintf _snprintf
126 #define MAX_LABELS 128
129 #pragma mark == Structures ==
132 //===========================================================================================================================
134 //===========================================================================================================================
136 typedef struct Query
* QueryRef
;
137 typedef struct Query Query
;
143 WSAQUERYSETW
* querySet
;
148 HANDLE waitHandles
[ 3 ];
150 DNSServiceRef resolver4
;
151 DNSServiceRef resolver6
;
152 char name
[ kDNSServiceMaxDomainName
];
154 uint8_t numValidAddrs
;
162 #define BUFFER_INITIAL_SIZE 4192
163 #define ALIASES_INITIAL_SIZE 5
165 typedef struct HostsFile
173 typedef struct HostsFileInfo
175 struct hostent m_host
;
176 struct HostsFileInfo
* m_next
;
181 #pragma mark == Prototypes ==
184 //===========================================================================================================================
186 //===========================================================================================================================
190 BOOL WINAPI
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
);
191 STDAPI
DllRegisterServer( void );
192 STDAPI
DllRegisterServer( void );
197 int WSPAPI
NSPCleanup( LPGUID inProviderID
);
199 DEBUG_LOCAL
int WSPAPI
200 NSPLookupServiceBegin(
202 LPWSAQUERYSETW inQuerySet
,
203 LPWSASERVICECLASSINFOW inServiceClassInfo
,
205 LPHANDLE outLookup
);
207 DEBUG_LOCAL
int WSPAPI
208 NSPLookupServiceNext(
211 LPDWORD ioBufferLength
,
212 LPWSAQUERYSETW outResults
);
214 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
);
216 DEBUG_LOCAL
int WSPAPI
219 LPWSASERVICECLASSINFOW inServiceClassInfo
,
220 LPWSAQUERYSETW inRegInfo
,
221 WSAESETSERVICEOP inOperation
,
224 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
);
225 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
);
226 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioBufSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
);
230 #define NSPLock() EnterCriticalSection( &gLock );
231 #define NSPUnlock() LeaveCriticalSection( &gLock );
233 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
);
234 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
);
235 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
);
237 DEBUG_LOCAL
void CALLBACK_COMPAT
238 QueryRecordCallback4(
240 DNSServiceFlags inFlags
,
241 uint32_t inInterfaceIndex
,
242 DNSServiceErrorType inErrorCode
,
246 uint16_t inRDataSize
,
247 const void * inRData
,
251 DEBUG_LOCAL
void CALLBACK_COMPAT
252 QueryRecordCallback6(
254 DNSServiceFlags inFlags
,
255 uint32_t inInterfaceIndex
,
256 DNSServiceErrorType inErrorCode
,
260 uint16_t inRDataSize
,
261 const void * inRData
,
268 const WSAQUERYSETW
* inQuerySet
,
269 DWORD inQuerySetFlags
,
270 WSAQUERYSETW
** outQuerySet
,
276 const WSAQUERYSETW
* inQuerySet
,
277 DWORD inQuerySetFlags
,
278 WSAQUERYSETW
* outQuerySet
);
280 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
);
283 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
);
285 #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
287 #define dlog_query_set( LEVEL, SET )
290 DEBUG_LOCAL BOOL
InHostsTable( const char * name
);
291 DEBUG_LOCAL BOOL
IsLocalName( HostsFileInfo
* node
);
292 DEBUG_LOCAL BOOL
IsSameName( HostsFileInfo
* node
, const char * name
);
293 DEBUG_LOCAL OSStatus
HostsFileOpen( HostsFile
** self
, const char * fname
);
294 DEBUG_LOCAL OSStatus
HostsFileClose( HostsFile
* self
);
295 DEBUG_LOCAL
void HostsFileInfoFree( HostsFileInfo
* info
);
296 DEBUG_LOCAL OSStatus
HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
);
297 DEBUG_LOCAL DWORD
GetScopeId( DWORD ifIndex
);
299 #ifdef ENABLE_REVERSE_LOOKUP
300 DEBUG_LOCAL OSStatus
IsReverseLookup( LPCWSTR name
, size_t size
);
305 #pragma mark == Globals ==
308 //===========================================================================================================================
310 //===========================================================================================================================
312 // {B600E6E9-553B-4a19-8696-335E5C896153}
313 DEBUG_LOCAL HINSTANCE gInstance
= NULL
;
314 DEBUG_LOCAL
wchar_t * gNSPName
= L
"mdnsNSP";
315 DEBUG_LOCAL GUID gNSPGUID
= { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
316 DEBUG_LOCAL LONG gRefCount
= 0;
317 DEBUG_LOCAL CRITICAL_SECTION gLock
;
318 DEBUG_LOCAL
bool gLockInitialized
= false;
319 DEBUG_LOCAL QueryRef gQueryList
= NULL
;
320 DEBUG_LOCAL HostsFileInfo
* gHostsFileInfo
= NULL
;
322 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
326 PIP_ADAPTER_ADDRESSES inAdapter
,
327 PULONG outBufferSize
);
329 DEBUG_LOCAL HMODULE gIPHelperLibraryInstance
= NULL
;
330 DEBUG_LOCAL GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
338 //===========================================================================================================================
340 //===========================================================================================================================
342 BOOL APIENTRY
DllMain( HINSTANCE inInstance
, DWORD inReason
, LPVOID inReserved
)
344 DEBUG_USE_ONLY( inInstance
);
345 DEBUG_UNUSED( inReserved
);
349 case DLL_PROCESS_ATTACH
:
350 gInstance
= inInstance
;
351 gHostsFileInfo
= NULL
;
352 debug_initialize( kDebugOutputTypeWindowsEventLog
, "mDNS NSP", inInstance
);
353 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelNotice
);
354 dlog( kDebugLevelTrace
, "\n" );
355 dlog( kDebugLevelVerbose
, "%s: process attach\n", __ROUTINE__
);
359 case DLL_PROCESS_DETACH
:
360 HostsFileInfoFree( gHostsFileInfo
);
361 gHostsFileInfo
= NULL
;
362 dlog( kDebugLevelVerbose
, "%s: process detach\n", __ROUTINE__
);
365 case DLL_THREAD_ATTACH
:
366 dlog( kDebugLevelVerbose
, "%s: thread attach\n", __ROUTINE__
);
369 case DLL_THREAD_DETACH
:
370 dlog( kDebugLevelVerbose
, "%s: thread detach\n", __ROUTINE__
);
374 dlog( kDebugLevelNotice
, "%s: unknown reason code (%d)\n", __ROUTINE__
, inReason
);
382 //===========================================================================================================================
384 //===========================================================================================================================
386 STDAPI
DllRegisterServer( void )
389 WCHAR path
[ MAX_PATH
];
392 dlog( kDebugLevelTrace
, "DllRegisterServer\n" );
394 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
395 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
396 require_noerr( err
, exit
);
398 // Unregister before registering to workaround an installer
399 // problem during upgrade installs.
401 WSCUnInstallNameSpace( &gNSPGUID
);
403 err
= GetModuleFileNameW( gInstance
, path
, MAX_PATH
);
404 err
= translate_errno( err
!= 0, errno_compat(), kUnknownErr
);
405 require_noerr( err
, exit
);
407 err
= WSCInstallNameSpace( gNSPName
, path
, NS_DNS
, 1, &gNSPGUID
);
408 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
409 require_noerr( err
, exit
);
417 //===========================================================================================================================
418 // DllUnregisterServer
419 //===========================================================================================================================
421 STDAPI
DllUnregisterServer( void )
426 dlog( kDebugLevelTrace
, "DllUnregisterServer\n" );
428 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsd
);
429 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
430 require_noerr( err
, exit
);
432 err
= WSCUnInstallNameSpace( &gNSPGUID
);
433 err
= translate_errno( err
== 0, errno_compat(), WSAEINVAL
);
434 require_noerr( err
, exit
);
443 //===========================================================================================================================
446 // This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
447 //===========================================================================================================================
449 int WSPAPI
NSPStartup( LPGUID inProviderID
, LPNSP_ROUTINE outRoutines
)
453 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
454 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
456 // Only initialize if this is the first time NSPStartup is called.
458 if( InterlockedIncrement( &gRefCount
) != 1 )
464 // Initialize our internal state.
466 InitializeCriticalSection( &gLock
);
467 gLockInitialized
= true;
469 // Set the size to exclude NSPIoctl because we don't implement it.
471 outRoutines
->cbSize
= FIELD_OFFSET( NSP_ROUTINE
, NSPIoctl
);
472 outRoutines
->dwMajorVersion
= 4;
473 outRoutines
->dwMinorVersion
= 4;
474 outRoutines
->NSPCleanup
= NSPCleanup
;
475 outRoutines
->NSPLookupServiceBegin
= NSPLookupServiceBegin
;
476 outRoutines
->NSPLookupServiceNext
= NSPLookupServiceNext
;
477 outRoutines
->NSPLookupServiceEnd
= NSPLookupServiceEnd
;
478 outRoutines
->NSPSetService
= NSPSetService
;
479 outRoutines
->NSPInstallServiceClass
= NSPInstallServiceClass
;
480 outRoutines
->NSPRemoveServiceClass
= NSPRemoveServiceClass
;
481 outRoutines
->NSPGetServiceClassInfo
= NSPGetServiceClassInfo
;
483 // See if we can get the address for the GetAdaptersAddresses() API. This is only in XP, but we want our
484 // code to run on older versions of Windows
486 if ( !gIPHelperLibraryInstance
)
488 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
489 if( gIPHelperLibraryInstance
)
491 gGetAdaptersAddressesFunctionPtr
= (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
498 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
499 if( err
!= NO_ERROR
)
501 NSPCleanup( inProviderID
);
502 SetLastError( (DWORD
) err
);
503 return( SOCKET_ERROR
);
508 //===========================================================================================================================
511 // This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
512 //===========================================================================================================================
514 int WSPAPI
NSPCleanup( LPGUID inProviderID
)
516 DEBUG_USE_ONLY( inProviderID
);
518 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
519 dlog( kDebugLevelTrace
, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__
, inProviderID
, gRefCount
);
521 // Only initialize if this is the first time NSPStartup is called.
523 if( InterlockedDecrement( &gRefCount
) != 0 )
528 // Stop any outstanding queries.
530 if( gLockInitialized
)
536 check_string( gQueryList
->refCount
== 1, "NSPCleanup with outstanding queries!" );
537 QueryRelease( gQueryList
);
539 if( gLockInitialized
)
544 if( gLockInitialized
)
546 gLockInitialized
= false;
547 DeleteCriticalSection( &gLock
);
550 if( gIPHelperLibraryInstance
)
554 ok
= FreeLibrary( gIPHelperLibraryInstance
);
555 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
556 gIPHelperLibraryInstance
= NULL
;
560 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
564 //===========================================================================================================================
565 // NSPLookupServiceBegin
567 // This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
568 // that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
569 // opposed to specifying the query parameters each time.
570 //===========================================================================================================================
572 DEBUG_LOCAL
int WSPAPI
573 NSPLookupServiceBegin(
575 LPWSAQUERYSETW inQuerySet
,
576 LPWSASERVICECLASSINFOW inServiceClassInfo
,
591 DEBUG_UNUSED( inProviderID
);
592 DEBUG_UNUSED( inServiceClassInfo
);
594 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
597 require_action( inQuerySet
, exit
, err
= WSAEINVAL
);
598 name
= inQuerySet
->lpszServiceInstanceName
;
599 require_action_quiet( name
, exit
, err
= WSAEINVAL
);
600 require_action( outLookup
, exit
, err
= WSAEINVAL
);
602 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__
, inFlags
, name
);
603 dlog_query_set( kDebugLevelVerbose
, inQuerySet
);
605 // Check if we can handle this type of request and if we support any of the protocols being requested.
606 // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
608 require_action_quiet( inFlags
& (LUP_RETURN_ADDR
|LUP_RETURN_BLOB
), exit
, err
= WSASERVICE_NOT_FOUND
);
610 type
= inQuerySet
->dwNameSpace
;
611 require_action_quiet( ( type
== NS_DNS
) || ( type
== NS_ALL
), exit
, err
= WSASERVICE_NOT_FOUND
);
613 n
= inQuerySet
->dwNumberOfProtocols
;
616 require_action( inQuerySet
->lpafpProtocols
, exit
, err
= WSAEINVAL
);
617 for( i
= 0; i
< n
; ++i
)
619 family
= inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
;
620 protocol
= inQuerySet
->lpafpProtocols
[ i
].iProtocol
;
621 if( ( family
== AF_INET
) && ( ( protocol
== IPPROTO_UDP
) || ( protocol
== IPPROTO_TCP
) ) )
626 require_action_quiet( i
< n
, exit
, err
= WSASERVICE_NOT_FOUND
);
629 // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
630 // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
631 // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
632 // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
633 // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
635 for( p
= name
; *p
; ++p
) {} // Find end of string
636 size
= (size_t)( p
- name
);
637 require_action_quiet( size
> sizeof_string( ".local" ), exit
, err
= WSASERVICE_NOT_FOUND
);
639 p
= name
+ ( size
- 1 );
640 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".local" ) ) : ( ( p
- sizeof_string( ".local" ) ) + 1 );
641 if ( ( ( p
[ 0 ] != '.' ) ||
642 ( ( p
[ 1 ] != 'L' ) && ( p
[ 1 ] != 'l' ) ) ||
643 ( ( p
[ 2 ] != 'O' ) && ( p
[ 2 ] != 'o' ) ) ||
644 ( ( p
[ 3 ] != 'C' ) && ( p
[ 3 ] != 'c' ) ) ||
645 ( ( p
[ 4 ] != 'A' ) && ( p
[ 4 ] != 'a' ) ) ||
646 ( ( p
[ 5 ] != 'L' ) && ( p
[ 5 ] != 'l' ) ) ) )
648 #ifdef ENABLE_REVERSE_LOOKUP
650 err
= IsReverseLookup( name
, size
);
654 err
= WSASERVICE_NOT_FOUND
;
658 require_noerr( err
, exit
);
662 const char * replyDomain
;
663 char translated
[ kDNSServiceMaxDomainName
];
666 const char * label
[MAX_LABELS
];
669 n
= WideCharToMultiByte( CP_UTF8
, 0, name
, -1, translated
, sizeof( translated
), NULL
, NULL
);
670 require_action( n
> 0, exit
, err
= WSASERVICE_NOT_FOUND
);
672 // <rdar://problem/4050633>
674 // Don't resolve multi-label name
676 // <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
677 // Add checks for GetNextLabel returning NULL, individual labels being greater than
678 // 64 bytes, and the number of labels being greater than MAX_LABELS
679 replyDomain
= translated
;
681 while (replyDomain
&& *replyDomain
&& labels
< MAX_LABELS
)
683 label
[labels
++] = replyDomain
;
684 replyDomain
= GetNextLabel(replyDomain
, text
);
687 require_action( labels
== 2, exit
, err
= WSASERVICE_NOT_FOUND
);
689 // <rdar://problem/3936771>
691 // Check to see if the name of this host is in the hosts table. If so,
692 // don't try and resolve it
694 require_action( InHostsTable( translated
) == FALSE
, exit
, err
= WSASERVICE_NOT_FOUND
);
697 // 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.
701 err
= QueryCreate( inQuerySet
, inFlags
, &obj
);
703 require_noerr( err
, exit
);
705 *outLookup
= (HANDLE
) obj
;
708 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
709 if( err
!= NO_ERROR
)
711 SetLastError( (DWORD
) err
);
712 return( SOCKET_ERROR
);
717 //===========================================================================================================================
718 // NSPLookupServiceNext
720 // This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
721 // query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
722 // in the lpqsResults parameter.
723 //===========================================================================================================================
725 DEBUG_LOCAL
int WSPAPI
726 NSPLookupServiceNext(
730 LPWSAQUERYSETW outResults
)
739 DEBUG_USE_ONLY( inFlags
);
741 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
747 err
= QueryRetain( (QueryRef
) inLookup
);
748 require_noerr( err
, exit
);
749 obj
= (QueryRef
) inLookup
;
750 require_action( ioSize
, exit
, err
= WSAEINVAL
);
751 require_action( outResults
, exit
, err
= WSAEINVAL
);
753 dlog( kDebugLevelTrace
, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__
, inLookup
, inFlags
, *ioSize
);
755 // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
758 waitResult
= WaitForMultipleObjects( obj
->waitCount
, obj
->waitHandles
, FALSE
, 2 * 1000 );
760 require_action_quiet( waitResult
!= ( WAIT_OBJECT_0
), exit
, err
= WSA_E_CANCELLED
);
761 err
= translate_errno( ( waitResult
== WAIT_OBJECT_0
+ 1 ) || ( waitResult
== WAIT_OBJECT_0
+ 2 ), (OSStatus
) GetLastError(), WSASERVICE_NOT_FOUND
);
762 require_noerr_quiet( err
, exit
);
764 // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
766 if ( waitResult
== WAIT_OBJECT_0
+ 1 )
769 data6
= WaitForSingleObject( obj
->data6Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
772 // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
774 else if ( waitResult
== WAIT_OBJECT_0
+ 2 )
776 data4
= WaitForSingleObject( obj
->data4Event
, 100 ) == WAIT_OBJECT_0
? TRUE
: FALSE
;
784 err
= DNSServiceProcessResult(obj
->resolver4
);
786 __except( EXCEPTION_EXECUTE_HANDLER
)
791 require_noerr( err
, exit
);
798 err
= DNSServiceProcessResult( obj
->resolver6
);
800 __except( EXCEPTION_EXECUTE_HANDLER
)
805 require_noerr( err
, exit
);
808 require_action_quiet( obj
->addr4Valid
|| obj
->addr6Valid
, exit
, err
= WSA_E_NO_MORE
);
810 // Copy the externalized query results to the callers buffer (if it fits).
812 size
= QueryCopyQuerySetSize( obj
, obj
->querySet
, obj
->querySetFlags
);
813 require_action( size
<= (size_t) *ioSize
, exit
, err
= WSAEFAULT
);
815 QueryCopyQuerySetTo( obj
, obj
->querySet
, obj
->querySetFlags
, outResults
);
816 outResults
->dwOutputFlags
= RESULT_IS_ADDED
;
817 obj
->addr4Valid
= false;
818 obj
->addr6Valid
= false;
826 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
827 if( err
!= NO_ERROR
)
829 SetLastError( (DWORD
) err
);
830 return( SOCKET_ERROR
);
835 //===========================================================================================================================
836 // NSPLookupServiceEnd
838 // This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
839 // indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
840 // allocated resources associated with the query.
841 //===========================================================================================================================
843 DEBUG_LOCAL
int WSPAPI
NSPLookupServiceEnd( HANDLE inLookup
)
847 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
849 dlog( kDebugLevelTrace
, "%s (lookup=%#p)\n", __ROUTINE__
, inLookup
);
852 err
= QueryRelease( (QueryRef
) inLookup
);
854 require_noerr( err
, exit
);
857 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
858 if( err
!= NO_ERROR
)
860 SetLastError( (DWORD
) err
);
861 return( SOCKET_ERROR
);
866 //===========================================================================================================================
869 // This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
870 // deregister an instance of a server with our service. For registration, the user needs to associate the server with a
871 // service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
872 // contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
873 //===========================================================================================================================
875 DEBUG_LOCAL
int WSPAPI
878 LPWSASERVICECLASSINFOW inServiceClassInfo
,
879 LPWSAQUERYSETW inRegInfo
,
880 WSAESETSERVICEOP inOperation
,
883 DEBUG_UNUSED( inProviderID
);
884 DEBUG_UNUSED( inServiceClassInfo
);
885 DEBUG_UNUSED( inRegInfo
);
886 DEBUG_UNUSED( inOperation
);
887 DEBUG_UNUSED( inFlags
);
889 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
890 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
892 // We don't allow services to be registered so always return an error.
894 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
898 //===========================================================================================================================
899 // NSPInstallServiceClass
901 // This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
902 // is used to define certain characteristics for a group of services. After a service class is registered, an actual
903 // instance of a server may be registered.
904 //===========================================================================================================================
906 DEBUG_LOCAL
int WSPAPI
NSPInstallServiceClass( LPGUID inProviderID
, LPWSASERVICECLASSINFOW inServiceClassInfo
)
908 DEBUG_UNUSED( inProviderID
);
909 DEBUG_UNUSED( inServiceClassInfo
);
911 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
912 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
914 // We don't allow service classes to be installed so always return an error.
916 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
917 return( WSA_INVALID_PARAMETER
);
920 //===========================================================================================================================
921 // NSPRemoveServiceClass
923 // This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
924 // class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
926 //===========================================================================================================================
928 DEBUG_LOCAL
int WSPAPI
NSPRemoveServiceClass( LPGUID inProviderID
, LPGUID inServiceClassID
)
930 DEBUG_UNUSED( inProviderID
);
931 DEBUG_UNUSED( inServiceClassID
);
933 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
934 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
936 // We don't allow service classes to be installed so always return an error.
938 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
939 return( WSATYPE_NOT_FOUND
);
942 //===========================================================================================================================
943 // NSPGetServiceClassInfo
945 // This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
946 // a given service class.
947 //===========================================================================================================================
949 DEBUG_LOCAL
int WSPAPI
NSPGetServiceClassInfo( LPGUID inProviderID
, LPDWORD ioSize
, LPWSASERVICECLASSINFOW ioServiceClassInfo
)
951 DEBUG_UNUSED( inProviderID
);
952 DEBUG_UNUSED( ioSize
);
953 DEBUG_UNUSED( ioServiceClassInfo
);
955 dlog( kDebugLevelTrace
, "%s begin (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
956 dlog( kDebugLevelTrace
, "%s\n", __ROUTINE__
);
958 // We don't allow service classes to be installed so always return an error.
960 dlog( kDebugLevelTrace
, "%s end (ticks=%d)\n", __ROUTINE__
, GetTickCount() );
961 return( WSATYPE_NOT_FOUND
);
968 //===========================================================================================================================
971 // Warning: Assumes the NSP lock is held.
972 //===========================================================================================================================
974 DEBUG_LOCAL OSStatus
QueryCreate( const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
, QueryRef
*outRef
)
978 char name
[ kDNSServiceMaxDomainName
];
986 check( inQuerySet
->lpszServiceInstanceName
);
989 // Convert the wchar_t name to UTF-8.
991 n
= WideCharToMultiByte( CP_UTF8
, 0, inQuerySet
->lpszServiceInstanceName
, -1, name
, sizeof( name
), NULL
, NULL
);
992 err
= translate_errno( n
> 0, (OSStatus
) GetLastError(), WSAEINVAL
);
993 require_noerr( err
, exit
);
995 // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
997 obj
= (QueryRef
) calloc( 1, sizeof( *obj
) );
998 require_action( obj
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1002 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
) {} // Find the end of the list.
1005 // Set up cancel event
1007 obj
->cancelEvent
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1008 require_action( obj
->cancelEvent
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1010 // Set up events to signal when A record data is ready
1012 obj
->data4Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1013 require_action( obj
->data4Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1015 // Start the query. Handle delay loaded DLL errors.
1019 err
= DNSServiceQueryRecord( &obj
->resolver4
, 0, 0, name
, kDNSServiceType_A
, kDNSServiceClass_IN
, QueryRecordCallback4
, obj
);
1021 __except( EXCEPTION_EXECUTE_HANDLER
)
1026 require_noerr( err
, exit
);
1028 // Attach the socket to the event
1032 s4
= DNSServiceRefSockFD(obj
->resolver4
);
1034 __except( EXCEPTION_EXECUTE_HANDLER
)
1036 s4
= INVALID_SOCKET
;
1039 err
= translate_errno( s4
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1040 require_noerr( err
, exit
);
1042 WSAEventSelect(s4
, obj
->data4Event
, FD_READ
|FD_CLOSE
);
1044 // Set up events to signal when AAAA record data is ready
1046 obj
->data6Event
= CreateEvent( NULL
, TRUE
, FALSE
, NULL
);
1047 require_action( obj
->data6Event
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1049 // Start the query. Handle delay loaded DLL errors.
1053 err
= DNSServiceQueryRecord( &obj
->resolver6
, 0, 0, name
, kDNSServiceType_AAAA
, kDNSServiceClass_IN
, QueryRecordCallback6
, obj
);
1055 __except( EXCEPTION_EXECUTE_HANDLER
)
1060 require_noerr( err
, exit
);
1062 // Attach the socket to the event
1066 s6
= DNSServiceRefSockFD(obj
->resolver6
);
1068 __except( EXCEPTION_EXECUTE_HANDLER
)
1070 s6
= INVALID_SOCKET
;
1073 err
= translate_errno( s6
!= INVALID_SOCKET
, errno_compat(), kUnknownErr
);
1074 require_noerr( err
, exit
);
1076 WSAEventSelect(s6
, obj
->data6Event
, FD_READ
|FD_CLOSE
);
1079 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->cancelEvent
;
1080 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data4Event
;
1081 obj
->waitHandles
[ obj
->waitCount
++ ] = obj
->data6Event
;
1083 check( obj
->waitCount
== sizeof_array( obj
->waitHandles
) );
1085 // Copy the QuerySet so it can be returned later.
1087 obj
->querySetFlags
= inQuerySetFlags
;
1088 inQuerySetFlags
= ( inQuerySetFlags
& ~( LUP_RETURN_ADDR
| LUP_RETURN_BLOB
) ) | LUP_RETURN_NAME
;
1089 err
= QueryCopyQuerySet( obj
, inQuerySet
, inQuerySetFlags
, &obj
->querySet
, &obj
->querySetSize
);
1090 require_noerr( err
, exit
);
1101 QueryRelease( obj
);
1106 //===========================================================================================================================
1109 // Warning: Assumes the NSP lock is held.
1110 //===========================================================================================================================
1112 DEBUG_LOCAL OSStatus
QueryRetain( QueryRef inRef
)
1117 for( obj
= gQueryList
; obj
; obj
= obj
->next
)
1124 require_action( obj
, exit
, err
= WSA_INVALID_HANDLE
);
1133 //===========================================================================================================================
1136 // Warning: Assumes the NSP lock is held.
1137 //===========================================================================================================================
1139 DEBUG_LOCAL OSStatus
QueryRelease( QueryRef inRef
)
1145 // Find the item in the list.
1147 for( p
= &gQueryList
; *p
; p
= &( *p
)->next
)
1154 require_action( *p
, exit
, err
= WSA_INVALID_HANDLE
);
1156 // Signal a cancel to unblock any threads waiting for results.
1158 if( inRef
->cancelEvent
)
1160 ok
= SetEvent( inRef
->cancelEvent
);
1161 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1166 if( inRef
->resolver4
)
1170 DNSServiceRefDeallocate( inRef
->resolver4
);
1172 __except( EXCEPTION_EXECUTE_HANDLER
)
1176 inRef
->resolver4
= NULL
;
1179 if ( inRef
->resolver6
)
1183 DNSServiceRefDeallocate( inRef
->resolver6
);
1185 __except( EXCEPTION_EXECUTE_HANDLER
)
1189 inRef
->resolver6
= NULL
;
1192 // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
1194 if( --inRef
->refCount
!= 0 )
1201 // Release resources.
1203 if( inRef
->cancelEvent
)
1205 ok
= CloseHandle( inRef
->cancelEvent
);
1206 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1208 if( inRef
->data4Event
)
1210 ok
= CloseHandle( inRef
->data4Event
);
1211 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1213 if( inRef
->data6Event
)
1215 ok
= CloseHandle( inRef
->data6Event
);
1216 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1218 if( inRef
->querySet
)
1220 free( inRef
->querySet
);
1229 //===========================================================================================================================
1230 // QueryRecordCallback4
1231 //===========================================================================================================================
1233 DEBUG_LOCAL
void CALLBACK_COMPAT
1234 QueryRecordCallback4(
1235 DNSServiceRef inRef
,
1236 DNSServiceFlags inFlags
,
1237 uint32_t inInterfaceIndex
,
1238 DNSServiceErrorType inErrorCode
,
1239 const char * inName
,
1242 uint16_t inRDataSize
,
1243 const void * inRData
,
1252 DEBUG_UNUSED( inFlags
);
1253 DEBUG_UNUSED( inInterfaceIndex
);
1254 DEBUG_UNUSED( inTTL
);
1257 obj
= (QueryRef
) inContext
;
1259 require_noerr( inErrorCode
, exit
);
1260 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1261 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1262 require( inRRType
== kDNSServiceType_A
, exit
);
1263 require( inRDataSize
== 4, exit
);
1265 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1266 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1268 // Copy the name if needed.
1270 if( obj
->name
[ 0 ] == '\0' )
1274 while( *src
!= '\0' )
1279 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1280 check( obj
->nameSize
< sizeof( obj
->name
) );
1285 memcpy( &obj
->addr4
, inRData
, inRDataSize
);
1286 obj
->addr4Valid
= true;
1287 obj
->numValidAddrs
++;
1289 // Signal that a result is ready.
1291 check( obj
->data4Event
);
1292 ok
= SetEvent( obj
->data4Event
);
1293 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1295 // Stop the resolver after the first response.
1299 DNSServiceRefDeallocate( inRef
);
1301 __except( EXCEPTION_EXECUTE_HANDLER
)
1305 obj
->resolver4
= NULL
;
1316 //===========================================================================================================================
1317 // QueryRecordCallback6
1318 //===========================================================================================================================
1320 DEBUG_LOCAL
void CALLBACK_COMPAT
1321 QueryRecordCallback6(
1322 DNSServiceRef inRef
,
1323 DNSServiceFlags inFlags
,
1324 uint32_t inInterfaceIndex
,
1325 DNSServiceErrorType inErrorCode
,
1326 const char * inName
,
1329 uint16_t inRDataSize
,
1330 const void * inRData
,
1339 DEBUG_UNUSED( inFlags
);
1340 DEBUG_UNUSED( inInterfaceIndex
);
1341 DEBUG_UNUSED( inTTL
);
1344 obj
= (QueryRef
) inContext
;
1346 require_noerr( inErrorCode
, exit
);
1347 require_quiet( inFlags
& kDNSServiceFlagsAdd
, exit
);
1348 require( inRRClass
== kDNSServiceClass_IN
, exit
);
1349 require( inRRType
== kDNSServiceType_AAAA
, exit
);
1350 require( inRDataSize
== 16, exit
);
1352 dlog( kDebugLevelTrace
, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
1353 __ROUTINE__
, inFlags
, inName
, inRRType
, inRDataSize
);
1355 // Copy the name if needed.
1357 if( obj
->name
[ 0 ] == '\0' )
1361 while( *src
!= '\0' )
1366 obj
->nameSize
= (size_t)( dst
- obj
->name
);
1367 check( obj
->nameSize
< sizeof( obj
->name
) );
1372 memcpy( &obj
->addr6
, inRData
, inRDataSize
);
1374 obj
->addr6ScopeId
= GetScopeId( inInterfaceIndex
);
1375 require( obj
->addr6ScopeId
, exit
);
1376 obj
->addr6Valid
= true;
1377 obj
->numValidAddrs
++;
1379 // Signal that we're done
1381 check( obj
->data6Event
);
1382 ok
= SetEvent( obj
->data6Event
);
1383 check_translated_errno( ok
, GetLastError(), WSAEINVAL
);
1385 // Stop the resolver after the first response.
1389 DNSServiceRefDeallocate( inRef
);
1391 __except( EXCEPTION_EXECUTE_HANDLER
)
1395 obj
->resolver6
= NULL
;
1405 //===========================================================================================================================
1406 // QueryCopyQuerySet
1408 // Warning: Assumes the NSP lock is held.
1409 //===========================================================================================================================
1411 DEBUG_LOCAL OSStatus
1414 const WSAQUERYSETW
* inQuerySet
,
1415 DWORD inQuerySetFlags
,
1416 WSAQUERYSETW
** outQuerySet
,
1423 check( inQuerySet
);
1424 check( outQuerySet
);
1426 size
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1427 qs
= (WSAQUERYSETW
*) calloc( 1, size
);
1428 require_action( qs
, exit
, err
= WSA_NOT_ENOUGH_MEMORY
);
1430 QueryCopyQuerySetTo( inRef
, inQuerySet
, inQuerySetFlags
, qs
);
1450 //===========================================================================================================================
1451 // QueryCopyQuerySetTo
1453 // Warning: Assumes the NSP lock is held.
1454 //===========================================================================================================================
1457 QueryCopyQuerySetTo(
1459 const WSAQUERYSETW
* inQuerySet
,
1460 DWORD inQuerySetFlags
,
1461 WSAQUERYSETW
* outQuerySet
)
1472 debugSize
= QueryCopyQuerySetSize( inRef
, inQuerySet
, inQuerySetFlags
);
1475 check( inQuerySet
);
1476 check( outQuerySet
);
1478 dst
= (uint8_t *) outQuerySet
;
1480 // Copy the static portion of the results.
1482 *outQuerySet
= *inQuerySet
;
1483 dst
+= sizeof( *inQuerySet
);
1485 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1487 s
= inQuerySet
->lpszServiceInstanceName
;
1490 outQuerySet
->lpszServiceInstanceName
= (LPWSTR
) dst
;
1492 while( ( *q
++ = *s
++ ) != 0 ) {}
1493 dst
= (uint8_t *) q
;
1498 outQuerySet
->lpszServiceInstanceName
= NULL
;
1501 if( inQuerySet
->lpServiceClassId
)
1503 outQuerySet
->lpServiceClassId
= (LPGUID
) dst
;
1504 *outQuerySet
->lpServiceClassId
= *inQuerySet
->lpServiceClassId
;
1505 dst
+= sizeof( *inQuerySet
->lpServiceClassId
);
1508 if( inQuerySet
->lpVersion
)
1510 outQuerySet
->lpVersion
= (LPWSAVERSION
) dst
;
1511 *outQuerySet
->lpVersion
= *inQuerySet
->lpVersion
;
1512 dst
+= sizeof( *inQuerySet
->lpVersion
);
1515 s
= inQuerySet
->lpszComment
;
1518 outQuerySet
->lpszComment
= (LPWSTR
) dst
;
1520 while( ( *q
++ = *s
++ ) != 0 ) {}
1521 dst
= (uint8_t *) q
;
1524 if( inQuerySet
->lpNSProviderId
)
1526 outQuerySet
->lpNSProviderId
= (LPGUID
) dst
;
1527 *outQuerySet
->lpNSProviderId
= *inQuerySet
->lpNSProviderId
;
1528 dst
+= sizeof( *inQuerySet
->lpNSProviderId
);
1531 s
= inQuerySet
->lpszContext
;
1534 outQuerySet
->lpszContext
= (LPWSTR
) dst
;
1536 while( ( *q
++ = *s
++ ) != 0 ) {}
1537 dst
= (uint8_t *) q
;
1540 n
= inQuerySet
->dwNumberOfProtocols
;
1544 check( inQuerySet
->lpafpProtocols
);
1546 outQuerySet
->lpafpProtocols
= (LPAFPROTOCOLS
) dst
;
1547 for( i
= 0; i
< n
; ++i
)
1549 outQuerySet
->lpafpProtocols
[ i
] = inQuerySet
->lpafpProtocols
[ i
];
1550 dst
+= sizeof( *inQuerySet
->lpafpProtocols
);
1554 s
= inQuerySet
->lpszQueryString
;
1557 outQuerySet
->lpszQueryString
= (LPWSTR
) dst
;
1559 while( ( *q
++ = *s
++ ) != 0 ) {}
1560 dst
= (uint8_t *) q
;
1563 // Copy the address(es).
1565 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && ( inRef
->numValidAddrs
> 0 ) )
1567 struct sockaddr_in
* addr4
;
1568 struct sockaddr_in6
* addr6
;
1571 outQuerySet
->dwNumberOfCsAddrs
= inRef
->numValidAddrs
;
1572 outQuerySet
->lpcsaBuffer
= (LPCSADDR_INFO
) dst
;
1573 dst
+= ( sizeof( *outQuerySet
->lpcsaBuffer
) ) * ( inRef
->numValidAddrs
) ;
1576 if ( inRef
->addr4Valid
)
1578 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1579 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1581 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1582 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in
);
1584 addr4
= (struct sockaddr_in
*) dst
;
1585 memset( addr4
, 0, sizeof( *addr4
) );
1586 addr4
->sin_family
= AF_INET
;
1587 memcpy( &addr4
->sin_addr
, &inRef
->addr4
, 4 );
1588 dst
+= sizeof( *addr4
);
1590 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET
; // Emulate Tcpip NSP
1591 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1596 if ( inRef
->addr6Valid
)
1598 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.lpSockaddr
= NULL
;
1599 outQuerySet
->lpcsaBuffer
[ index
].LocalAddr
.iSockaddrLength
= 0;
1601 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.lpSockaddr
= (LPSOCKADDR
) dst
;
1602 outQuerySet
->lpcsaBuffer
[ index
].RemoteAddr
.iSockaddrLength
= sizeof( struct sockaddr_in6
);
1604 addr6
= (struct sockaddr_in6
*) dst
;
1605 memset( addr6
, 0, sizeof( *addr6
) );
1606 addr6
->sin6_family
= AF_INET6
;
1607 addr6
->sin6_scope_id
= inRef
->addr6ScopeId
;
1608 memcpy( &addr6
->sin6_addr
, &inRef
->addr6
, 16 );
1609 dst
+= sizeof( *addr6
);
1611 outQuerySet
->lpcsaBuffer
[ index
].iSocketType
= AF_INET6
; // Emulate Tcpip NSP
1612 outQuerySet
->lpcsaBuffer
[ index
].iProtocol
= IPPROTO_UDP
; // Emulate Tcpip NSP
1617 outQuerySet
->dwNumberOfCsAddrs
= 0;
1618 outQuerySet
->lpcsaBuffer
= NULL
;
1621 // Copy the hostent blob.
1623 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1626 struct hostent
* he
;
1629 outQuerySet
->lpBlob
= (LPBLOB
) dst
;
1630 dst
+= sizeof( *outQuerySet
->lpBlob
);
1633 he
= (struct hostent
*) dst
;
1634 dst
+= sizeof( *he
);
1636 he
->h_name
= (char *)( dst
- base
);
1637 memcpy( dst
, inRef
->name
, inRef
->nameSize
+ 1 );
1638 dst
+= ( inRef
->nameSize
+ 1 );
1640 he
->h_aliases
= (char **)( dst
- base
);
1641 p
= (uintptr_t *) dst
;
1643 dst
= (uint8_t *) p
;
1645 he
->h_addrtype
= AF_INET
;
1648 he
->h_addr_list
= (char **)( dst
- base
);
1649 p
= (uintptr_t *) dst
;
1650 dst
+= ( 2 * sizeof( *p
) );
1651 *p
++ = (uintptr_t)( dst
- base
);
1653 p
= (uintptr_t *) dst
;
1654 *p
++ = (uintptr_t) inRef
->addr4
;
1655 dst
= (uint8_t *) p
;
1657 outQuerySet
->lpBlob
->cbSize
= (ULONG
)( dst
- base
);
1658 outQuerySet
->lpBlob
->pBlobData
= (BYTE
*) base
;
1660 dlog_query_set( kDebugLevelVerbose
, outQuerySet
);
1662 check( (size_t)( dst
- ( (uint8_t *) outQuerySet
) ) == debugSize
);
1665 //===========================================================================================================================
1666 // QueryCopyQuerySetSize
1668 // Warning: Assumes the NSP lock is held.
1669 //===========================================================================================================================
1671 DEBUG_LOCAL
size_t QueryCopyQuerySetSize( QueryRef inRef
, const WSAQUERYSETW
*inQuerySet
, DWORD inQuerySetFlags
)
1678 check( inQuerySet
);
1680 // Calculate the size of the static portion of the results.
1682 size
= sizeof( *inQuerySet
);
1684 if( inQuerySetFlags
& LUP_RETURN_NAME
)
1686 s
= inQuerySet
->lpszServiceInstanceName
;
1689 for( p
= s
; *p
; ++p
) {}
1690 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1694 if( inQuerySet
->lpServiceClassId
)
1696 size
+= sizeof( *inQuerySet
->lpServiceClassId
);
1699 if( inQuerySet
->lpVersion
)
1701 size
+= sizeof( *inQuerySet
->lpVersion
);
1704 s
= inQuerySet
->lpszComment
;
1707 for( p
= s
; *p
; ++p
) {}
1708 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1711 if( inQuerySet
->lpNSProviderId
)
1713 size
+= sizeof( *inQuerySet
->lpNSProviderId
);
1716 s
= inQuerySet
->lpszContext
;
1719 for( p
= s
; *p
; ++p
) {}
1720 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1723 size
+= ( inQuerySet
->dwNumberOfProtocols
* sizeof( *inQuerySet
->lpafpProtocols
) );
1725 s
= inQuerySet
->lpszQueryString
;
1728 for( p
= s
; *p
; ++p
) {}
1729 size
+= (size_t)( ( ( p
- s
) + 1 ) * sizeof( *p
) );
1732 // Calculate the size of the address(es).
1734 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr4Valid
)
1736 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1737 size
+= sizeof( struct sockaddr_in
);
1740 if( ( inQuerySetFlags
& LUP_RETURN_ADDR
) && inRef
->addr6Valid
)
1742 size
+= sizeof( *inQuerySet
->lpcsaBuffer
);
1743 size
+= sizeof( struct sockaddr_in6
);
1746 // Calculate the size of the hostent blob.
1748 if( ( inQuerySetFlags
& LUP_RETURN_BLOB
) && inRef
->addr4Valid
)
1750 size
+= sizeof( *inQuerySet
->lpBlob
); // Blob ptr/size structure
1751 size
+= sizeof( struct hostent
); // Old-style hostent structure
1752 size
+= ( inRef
->nameSize
+ 1 ); // Name and null terminator
1753 size
+= 4; // Alias list terminator (0 offset)
1754 size
+= 4; // Offset to address.
1755 size
+= 4; // Address list terminator (0 offset)
1756 size
+= 4; // IPv4 address
1766 //===========================================================================================================================
1767 // DebugDumpQuerySet
1768 //===========================================================================================================================
1770 #define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
1771 ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
1773 #define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
1774 ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
1776 #define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
1778 void DebugDumpQuerySet( DebugLevel inLevel
, const WSAQUERYSETW
*inQuerySet
)
1782 check( inQuerySet
);
1784 // Fixed portion of the QuerySet.
1786 dlog( inLevel
, "QuerySet:\n" );
1787 dlog( inLevel
, " dwSize: %d (expected %d)\n", inQuerySet
->dwSize
, sizeof( *inQuerySet
) );
1788 if( inQuerySet
->lpszServiceInstanceName
)
1790 dlog( inLevel
, " lpszServiceInstanceName: %S\n", inQuerySet
->lpszServiceInstanceName
);
1794 dlog( inLevel
, " lpszServiceInstanceName: <null>\n" );
1796 if( inQuerySet
->lpServiceClassId
)
1798 dlog( inLevel
, " lpServiceClassId: %U\n", inQuerySet
->lpServiceClassId
);
1802 dlog( inLevel
, " lpServiceClassId: <null>\n" );
1804 if( inQuerySet
->lpVersion
)
1806 dlog( inLevel
, " lpVersion:\n" );
1807 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->dwVersion
);
1808 dlog( inLevel
, " dwVersion: %d\n", inQuerySet
->lpVersion
->ecHow
);
1812 dlog( inLevel
, " lpVersion: <null>\n" );
1814 if( inQuerySet
->lpszComment
)
1816 dlog( inLevel
, " lpszComment: %S\n", inQuerySet
->lpszComment
);
1820 dlog( inLevel
, " lpszComment: <null>\n" );
1822 dlog( inLevel
, " dwNameSpace: %d %s\n", inQuerySet
->dwNameSpace
,
1823 DebugNameSpaceToString( inQuerySet
->dwNameSpace
) );
1824 if( inQuerySet
->lpNSProviderId
)
1826 dlog( inLevel
, " lpNSProviderId: %U\n", inQuerySet
->lpNSProviderId
);
1830 dlog( inLevel
, " lpNSProviderId: <null>\n" );
1832 if( inQuerySet
->lpszContext
)
1834 dlog( inLevel
, " lpszContext: %S\n", inQuerySet
->lpszContext
);
1838 dlog( inLevel
, " lpszContext: <null>\n" );
1840 dlog( inLevel
, " dwNumberOfProtocols: %d\n", inQuerySet
->dwNumberOfProtocols
);
1841 dlog( inLevel
, " lpafpProtocols: %s\n", inQuerySet
->lpafpProtocols
? "" : "<null>" );
1842 for( i
= 0; i
< inQuerySet
->dwNumberOfProtocols
; ++i
)
1846 dlog( inLevel
, "\n" );
1848 dlog( inLevel
, " iAddressFamily: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
,
1849 DebugSocketFamilyToString( inQuerySet
->lpafpProtocols
[ i
].iAddressFamily
) );
1850 dlog( inLevel
, " iProtocol: %d %s\n", inQuerySet
->lpafpProtocols
[ i
].iProtocol
,
1851 DebugSocketProtocolToString( inQuerySet
->lpafpProtocols
[ i
].iProtocol
) );
1853 if( inQuerySet
->lpszQueryString
)
1855 dlog( inLevel
, " lpszQueryString: %S\n", inQuerySet
->lpszQueryString
);
1859 dlog( inLevel
, " lpszQueryString: <null>\n" );
1861 dlog( inLevel
, " dwNumberOfCsAddrs: %d\n", inQuerySet
->dwNumberOfCsAddrs
);
1862 dlog( inLevel
, " lpcsaBuffer: %s\n", inQuerySet
->lpcsaBuffer
? "" : "<null>" );
1863 for( i
= 0; i
< inQuerySet
->dwNumberOfCsAddrs
; ++i
)
1867 dlog( inLevel
, "\n" );
1869 if( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
&&
1870 ( inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.iSockaddrLength
> 0 ) )
1872 dlog( inLevel
, " LocalAddr: %##a\n",
1873 inQuerySet
->lpcsaBuffer
[ i
].LocalAddr
.lpSockaddr
);
1877 dlog( inLevel
, " LocalAddr: <null/empty>\n" );
1879 if( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
&&
1880 ( inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.iSockaddrLength
> 0 ) )
1882 dlog( inLevel
, " RemoteAddr: %##a\n",
1883 inQuerySet
->lpcsaBuffer
[ i
].RemoteAddr
.lpSockaddr
);
1887 dlog( inLevel
, " RemoteAddr: <null/empty>\n" );
1889 dlog( inLevel
, " iSocketType: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iSocketType
);
1890 dlog( inLevel
, " iProtocol: %d\n", inQuerySet
->lpcsaBuffer
[ i
].iProtocol
);
1892 dlog( inLevel
, " dwOutputFlags: %d\n", inQuerySet
->dwOutputFlags
);
1894 // Blob portion of the QuerySet.
1896 if( inQuerySet
->lpBlob
)
1898 dlog( inLevel
, " lpBlob:\n" );
1899 dlog( inLevel
, " cbSize: %ld\n", inQuerySet
->lpBlob
->cbSize
);
1900 dlog( inLevel
, " pBlobData: %#p\n", inQuerySet
->lpBlob
->pBlobData
);
1901 dloghex( inLevel
, 12, NULL
, 0, 0, NULL
, 0,
1902 inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->pBlobData
, inQuerySet
->lpBlob
->cbSize
,
1903 kDebugFlagsNone
, NULL
, 0 );
1907 dlog( inLevel
, " lpBlob: <null>\n" );
1913 //===========================================================================================================================
1915 //===========================================================================================================================
1918 InHostsTable( const char * name
)
1920 HostsFileInfo
* node
;
1926 if ( gHostsFileInfo
== NULL
)
1928 TCHAR systemDirectory
[MAX_PATH
];
1929 TCHAR hFileName
[MAX_PATH
];
1932 GetSystemDirectory( systemDirectory
, sizeof( systemDirectory
) );
1933 sprintf( hFileName
, "%s\\drivers\\etc\\hosts", systemDirectory
);
1934 err
= HostsFileOpen( &hFile
, hFileName
);
1935 require_noerr( err
, exit
);
1937 while ( HostsFileNext( hFile
, &node
) == 0 )
1939 if ( IsLocalName( node
) )
1941 node
->m_next
= gHostsFileInfo
;
1942 gHostsFileInfo
= node
;
1946 HostsFileInfoFree( node
);
1950 HostsFileClose( hFile
);
1953 for ( node
= gHostsFileInfo
; node
; node
= node
->m_next
)
1955 if ( IsSameName( node
, name
) )
1968 //===========================================================================================================================
1970 //===========================================================================================================================
1973 IsLocalName( HostsFileInfo
* node
)
1979 if ( strstr( node
->m_host
.h_name
, ".local" ) == NULL
)
1983 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
1985 if ( strstr( node
->m_host
.h_aliases
[i
], ".local" ) )
2000 //===========================================================================================================================
2002 //===========================================================================================================================
2005 IsSameName( HostsFileInfo
* node
, const char * name
)
2012 if ( strcmp( node
->m_host
.h_name
, name
) != 0 )
2016 for ( i
= 0; node
->m_host
.h_aliases
[i
]; i
++ )
2018 if ( strcmp( node
->m_host
.h_aliases
[i
], name
) == 0 )
2033 //===========================================================================================================================
2035 //===========================================================================================================================
2037 DEBUG_LOCAL OSStatus
2038 HostsFileOpen( HostsFile
** self
, const char * fname
)
2040 OSStatus err
= kNoErr
;
2042 *self
= (HostsFile
*) malloc( sizeof( HostsFile
) );
2043 require_action( *self
, exit
, err
= kNoMemoryErr
);
2044 memset( *self
, 0, sizeof( HostsFile
) );
2046 (*self
)->m_bufferSize
= BUFFER_INITIAL_SIZE
;
2047 (*self
)->m_buffer
= (char*) malloc( (*self
)->m_bufferSize
);
2048 require_action( (*self
)->m_buffer
, exit
, err
= kNoMemoryErr
);
2052 (*self
)->m_fp
= fopen( fname
, "r" );
2053 require_action( (*self
)->m_fp
, exit
, err
= kUnknownErr
);
2059 HostsFileClose( *self
);
2067 //===========================================================================================================================
2069 //===========================================================================================================================
2071 DEBUG_LOCAL OSStatus
2072 HostsFileClose( HostsFile
* self
)
2076 if ( self
->m_buffer
)
2078 free( self
->m_buffer
);
2079 self
->m_buffer
= NULL
;
2084 fclose( self
->m_fp
);
2094 //===========================================================================================================================
2095 // HostsFileInfoFree
2096 //===========================================================================================================================
2099 HostsFileInfoFree( HostsFileInfo
* info
)
2103 HostsFileInfo
* next
= info
->m_next
;
2105 if ( info
->m_host
.h_addr_list
)
2107 if ( info
->m_host
.h_addr_list
[0] )
2109 free( info
->m_host
.h_addr_list
[0] );
2110 info
->m_host
.h_addr_list
[0] = NULL
;
2113 free( info
->m_host
.h_addr_list
);
2114 info
->m_host
.h_addr_list
= NULL
;
2117 if ( info
->m_host
.h_aliases
)
2121 for ( i
= 0; info
->m_host
.h_aliases
[i
]; i
++ )
2123 free( info
->m_host
.h_aliases
[i
] );
2126 free( info
->m_host
.h_aliases
);
2129 if ( info
->m_host
.h_name
)
2131 free( info
->m_host
.h_name
);
2132 info
->m_host
.h_name
= NULL
;
2142 //===========================================================================================================================
2144 //===========================================================================================================================
2146 DEBUG_LOCAL OSStatus
2147 HostsFileNext( HostsFile
* self
, HostsFileInfo
** hInfo
)
2149 struct sockaddr_in6 addr_6
;
2150 struct sockaddr_in addr_4
;
2151 int numAliases
= ALIASES_INITIAL_SIZE
;
2158 OSStatus err
= kNoErr
;
2161 check( self
->m_fp
);
2166 *hInfo
= (HostsFileInfo
*) malloc( sizeof( HostsFileInfo
) );
2167 require_action( *hInfo
, exit
, err
= kNoMemoryErr
);
2168 memset( *hInfo
, 0, sizeof( HostsFileInfo
) );
2172 line
= fgets( self
->m_buffer
+ idx
, self
->m_bufferSize
- idx
, self
->m_fp
);
2180 // If there's no eol and no eof, then we didn't get the whole line
2182 if ( !strchr( line
, '\n' ) && !feof( self
->m_fp
) )
2187 /* Try and allocate space for longer line */
2189 bufferSize
= self
->m_bufferSize
* 2;
2190 buffer
= (char*) realloc( self
->m_buffer
, bufferSize
);
2191 require_action( buffer
, exit
, err
= kNoMemoryErr
);
2192 self
->m_bufferSize
= bufferSize
;
2193 self
->m_buffer
= buffer
;
2194 idx
= (int) strlen( self
->m_buffer
);
2199 line
= self
->m_buffer
;
2207 // Get rid of either comments or eol characters
2209 if (( tok
= strpbrk(line
, "#\n")) != NULL
)
2214 // Make sure there is some whitespace on this line
2216 if (( tok
= strpbrk(line
, " \t")) == NULL
)
2221 // Create two strings, where p == the IP Address and tok is the name list
2225 while ( *tok
== ' ' || *tok
== '\t')
2230 // Now we have the name
2232 (*hInfo
)->m_host
.h_name
= (char*) malloc( strlen( tok
) + 1 );
2233 require_action( (*hInfo
)->m_host
.h_name
, exit
, err
= kNoMemoryErr
);
2234 strcpy( (*hInfo
)->m_host
.h_name
, tok
);
2236 // Now create the address (IPv6/IPv4)
2238 addr_6
.sin6_family
= family
= AF_INET6
;
2239 dwSize
= sizeof( addr_6
);
2241 if ( WSAStringToAddress( line
, AF_INET6
, NULL
, ( struct sockaddr
*) &addr_6
, &dwSize
) != 0 )
2243 addr_4
.sin_family
= family
= AF_INET
;
2244 dwSize
= sizeof( addr_4
);
2246 if (WSAStringToAddress( line
, AF_INET
, NULL
, ( struct sockaddr
*) &addr_4
, &dwSize
) != 0 )
2252 (*hInfo
)->m_host
.h_addr_list
= (char**) malloc( sizeof( char**) * 2 );
2253 require_action( (*hInfo
)->m_host
.h_addr_list
, exit
, err
= kNoMemoryErr
);
2255 if ( family
== AF_INET6
)
2257 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_6
.sin6_addr
);
2258 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2259 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2260 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_6
.sin6_addr
, sizeof( addr_6
.sin6_addr
) );
2265 (*hInfo
)->m_host
.h_length
= (short) sizeof( addr_4
.sin_addr
);
2266 (*hInfo
)->m_host
.h_addr_list
[0] = (char*) malloc( (*hInfo
)->m_host
.h_length
);
2267 require_action( (*hInfo
)->m_host
.h_addr_list
[0], exit
, err
= kNoMemoryErr
);
2268 memmove( (*hInfo
)->m_host
.h_addr_list
[0], &addr_4
.sin_addr
, sizeof( addr_4
.sin_addr
) );
2271 (*hInfo
)->m_host
.h_addr_list
[1] = NULL
;
2272 (*hInfo
)->m_host
.h_addrtype
= family
;
2274 // Now get the aliases
2276 if ((tok
= strpbrk(tok
, " \t")) != NULL
)
2283 (*hInfo
)->m_host
.h_aliases
= (char**) malloc( sizeof(char**) * numAliases
);
2284 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2285 (*hInfo
)->m_host
.h_aliases
[0] = NULL
;
2287 while ( tok
&& *tok
)
2289 // Skip over the whitespace, waiting for the start of the next alias name
2291 if (*tok
== ' ' || *tok
== '\t')
2297 // Check to make sure we don't exhaust the alias buffer
2299 if ( i
>= ( numAliases
- 1 ) )
2301 numAliases
= numAliases
* 2;
2302 (*hInfo
)->m_host
.h_aliases
= (char**) realloc( (*hInfo
)->m_host
.h_aliases
, numAliases
* sizeof( char** ) );
2303 require_action( (*hInfo
)->m_host
.h_aliases
, exit
, err
= kNoMemoryErr
);
2306 (*hInfo
)->m_host
.h_aliases
[i
] = (char*) malloc( strlen( tok
) + 1 );
2307 require_action( (*hInfo
)->m_host
.h_aliases
[i
], exit
, err
= kNoMemoryErr
);
2309 strcpy( (*hInfo
)->m_host
.h_aliases
[i
], tok
);
2311 if (( tok
= strpbrk( tok
, " \t")) != NULL
)
2316 (*hInfo
)->m_host
.h_aliases
[++i
] = NULL
;
2324 if ( err
&& ( *hInfo
) )
2326 HostsFileInfoFree( *hInfo
);
2334 #ifdef ENABLE_REVERSE_LOOKUP
2335 //===========================================================================================================================
2337 //===========================================================================================================================
2339 DEBUG_LOCAL OSStatus
2340 IsReverseLookup( LPCWSTR name
, size_t size
)
2343 OSStatus err
= kNoErr
;
2345 // IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
2346 require_action_quiet( size
> sizeof_string( ".0.8.e.f.ip6.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2348 p
= name
+ ( size
- 1 );
2349 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p
- sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
2351 if ( ( ( p
[ 0 ] != '.' ) ||
2352 ( ( p
[ 1 ] != '0' ) ) ||
2353 ( ( p
[ 2 ] != '.' ) ) ||
2354 ( ( p
[ 3 ] != '8' ) ) ||
2355 ( ( p
[ 4 ] != '.' ) ) ||
2356 ( ( p
[ 5 ] != 'E' ) && ( p
[ 5 ] != 'e' ) ) ||
2357 ( ( p
[ 6 ] != '.' ) ) ||
2358 ( ( p
[ 7 ] != 'F' ) && ( p
[ 7 ] != 'f' ) ) ||
2359 ( ( p
[ 8 ] != '.' ) ) ||
2360 ( ( p
[ 9 ] != 'I' ) && ( p
[ 9 ] != 'i' ) ) ||
2361 ( ( p
[ 10 ] != 'P' ) && ( p
[ 10 ] != 'p' ) ) ||
2362 ( ( p
[ 11 ] != '6' ) ) ||
2363 ( ( p
[ 12 ] != '.' ) ) ||
2364 ( ( p
[ 13 ] != 'A' ) && ( p
[ 13 ] != 'a' ) ) ||
2365 ( ( p
[ 14 ] != 'R' ) && ( p
[ 14 ] != 'r' ) ) ||
2366 ( ( p
[ 15 ] != 'P' ) && ( p
[ 15 ] != 'p' ) ) ||
2367 ( ( p
[ 16 ] != 'A' ) && ( p
[ 16 ] != 'a' ) ) ) )
2369 require_action_quiet( size
> sizeof_string( ".254.169.in-addr.arpa" ), exit
, err
= WSASERVICE_NOT_FOUND
);
2371 p
= name
+ ( size
- 1 );
2372 p
= ( *p
== '.' ) ? ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p
- sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
2374 require_action_quiet( ( ( p
[ 0 ] == '.' ) &&
2375 ( ( p
[ 1 ] == '2' ) ) &&
2376 ( ( p
[ 2 ] == '5' ) ) &&
2377 ( ( p
[ 3 ] == '4' ) ) &&
2378 ( ( p
[ 4 ] == '.' ) ) &&
2379 ( ( p
[ 5 ] == '1' ) ) &&
2380 ( ( p
[ 6 ] == '6' ) ) &&
2381 ( ( p
[ 7 ] == '9' ) ) &&
2382 ( ( p
[ 8 ] == '.' ) ) &&
2383 ( ( p
[ 9 ] == 'I' ) || ( p
[ 9 ] == 'i' ) ) &&
2384 ( ( p
[ 10 ] == 'N' ) || ( p
[ 10 ] == 'n' ) ) &&
2385 ( ( p
[ 11 ] == '-' ) ) &&
2386 ( ( p
[ 12 ] == 'A' ) || ( p
[ 12 ] == 'a' ) ) &&
2387 ( ( p
[ 13 ] == 'D' ) || ( p
[ 13 ] == 'd' ) ) &&
2388 ( ( p
[ 14 ] == 'D' ) || ( p
[ 14 ] == 'd' ) ) &&
2389 ( ( p
[ 15 ] == 'R' ) || ( p
[ 15 ] == 'r' ) ) &&
2390 ( ( p
[ 16 ] == '.' ) ) &&
2391 ( ( p
[ 17 ] == 'A' ) || ( p
[ 17 ] == 'a' ) ) &&
2392 ( ( p
[ 18 ] == 'R' ) || ( p
[ 18 ] == 'r' ) ) &&
2393 ( ( p
[ 19 ] == 'P' ) || ( p
[ 19 ] == 'p' ) ) &&
2394 ( ( p
[ 20 ] == 'A' ) || ( p
[ 20 ] == 'a' ) ) ),
2395 exit
, err
= WSASERVICE_NOT_FOUND
);
2398 // It's a reverse lookup
2400 check( err
== kNoErr
);
2408 //===========================================================================================================================
2410 //===========================================================================================================================
2413 GetScopeId( DWORD ifIndex
)
2418 struct ifaddrs
* head
;
2419 struct ifaddrs
** next
;
2420 IP_ADAPTER_ADDRESSES
* iaaList
;
2422 IP_ADAPTER_ADDRESSES
* iaa
;
2429 require( gGetAdaptersAddressesFunctionPtr
, exit
);
2431 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
2432 // This loops to handle the case where the interface changes in the window after getting the size, but before the
2433 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
2435 flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
2440 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
2441 check( err
== ERROR_BUFFER_OVERFLOW
);
2442 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
2444 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
2445 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
2447 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
2448 if( err
== ERROR_SUCCESS
) break;
2453 require( i
< 100, exit
);
2454 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
2457 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
2461 if ( iaa
->IfIndex
> 0xFFFFFF )
2465 if ( iaa
->Ipv6IfIndex
> 0xFF )
2470 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
2471 // following code to crash when iterating through the prefix list. This seems
2472 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
2473 // This shouldn't happen according to Microsoft docs which states:
2475 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
2477 // So the data structure seems to be corrupted when we return from
2478 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
2479 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
2480 // modify iaa to have the correct values.
2482 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
2484 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
2491 // Skip psuedo and tunnel interfaces.
2493 if( ( ipv6IfIndex
== 1 ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
2498 if ( iaa
->IfIndex
== ifIndex
)
2500 scopeId
= iaa
->Ipv6IfIndex
;