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