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