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