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