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 sprintf( 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 OSStatus err = kNoErr; 2076 2077 check( self ); 2078 check( self->m_fp ); 2079 check( hInfo ); 2080 2081 idx = 0; 2082 2083 *hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) ); 2084 require_action( *hInfo, exit, err = kNoMemoryErr ); 2085 memset( *hInfo, 0, sizeof( HostsFileInfo ) ); 2086 2087 for ( ; ; ) 2088 { 2089 line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp ); 2090 2091 if ( line == NULL ) 2092 { 2093 err = 1; 2094 goto exit; 2095 } 2096 2097 // If there's no eol and no eof, then we didn't get the whole line 2098 2099 if ( !strchr( line, '\n' ) && !feof( self->m_fp ) ) 2100 { 2101 int bufferSize; 2102 char * buffer; 2103 2104 /* Try and allocate space for longer line */ 2105 2106 bufferSize = self->m_bufferSize * 2; 2107 buffer = (char*) realloc( self->m_buffer, bufferSize ); 2108 require_action( buffer, exit, err = kNoMemoryErr ); 2109 self->m_bufferSize = bufferSize; 2110 self->m_buffer = buffer; 2111 idx = (int) strlen( self->m_buffer ); 2112 2113 continue; 2114 } 2115 2116 line = self->m_buffer; 2117 idx = 0; 2118 2119 if (*line == '#') 2120 { 2121 continue; 2122 } 2123 2124 // Get rid of either comments or eol characters 2125 2126 if (( tok = strpbrk(line, "#\n")) != NULL ) 2127 { 2128 *tok = '\0'; 2129 } 2130 2131 // Make sure there is some whitespace on this line 2132 2133 if (( tok = strpbrk(line, " \t")) == NULL ) 2134 { 2135 continue; 2136 } 2137 2138 // Create two strings, where p == the IP Address and tok is the name list 2139 2140 *tok++ = '\0'; 2141 2142 while ( *tok == ' ' || *tok == '\t') 2143 { 2144 tok++; 2145 } 2146 2147 // Now we have the name 2148 2149 (*hInfo)->m_host.h_name = (char*) malloc( strlen( tok ) + 1 ); 2150 require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr ); 2151 strcpy( (*hInfo)->m_host.h_name, tok ); 2152 2153 // Now create the address (IPv6/IPv4) 2154 2155 addr_6.sin6_family = family = AF_INET6; 2156 dwSize = sizeof( addr_6 ); 2157 2158 if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 ) 2159 { 2160 addr_4.sin_family = family = AF_INET; 2161 dwSize = sizeof( addr_4 ); 2162 2163 if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 ) 2164 { 2165 continue; 2166 } 2167 } 2168 2169 (*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 ); 2170 require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr ); 2171 2172 if ( family == AF_INET6 ) 2173 { 2174 (*hInfo)->m_host.h_length = (short) sizeof( addr_6.sin6_addr ); 2175 (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length ); 2176 require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr ); 2177 memmove( (*hInfo)->m_host.h_addr_list[0], &addr_6.sin6_addr, sizeof( addr_6.sin6_addr ) ); 2178 2179 } 2180 else 2181 { 2182 (*hInfo)->m_host.h_length = (short) sizeof( addr_4.sin_addr ); 2183 (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length ); 2184 require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr ); 2185 memmove( (*hInfo)->m_host.h_addr_list[0], &addr_4.sin_addr, sizeof( addr_4.sin_addr ) ); 2186 } 2187 2188 (*hInfo)->m_host.h_addr_list[1] = NULL; 2189 (*hInfo)->m_host.h_addrtype = family; 2190 2191 // Now get the aliases 2192 2193 if ((tok = strpbrk(tok, " \t")) != NULL) 2194 { 2195 *tok++ = '\0'; 2196 } 2197 2198 i = 0; 2199 2200 (*hInfo)->m_host.h_aliases = (char**) malloc( sizeof(char**) * numAliases ); 2201 require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr ); 2202 (*hInfo)->m_host.h_aliases[0] = NULL; 2203 2204 while ( tok && *tok ) 2205 { 2206 // Skip over the whitespace, waiting for the start of the next alias name 2207 2208 if (*tok == ' ' || *tok == '\t') 2209 { 2210 tok++; 2211 continue; 2212 } 2213 2214 // Check to make sure we don't exhaust the alias buffer 2215 2216 if ( i >= ( numAliases - 1 ) ) 2217 { 2218 numAliases = numAliases * 2; 2219 (*hInfo)->m_host.h_aliases = (char**) realloc( (*hInfo)->m_host.h_aliases, numAliases * sizeof( char** ) ); 2220 require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr ); 2221 } 2222 2223 (*hInfo)->m_host.h_aliases[i] = (char*) malloc( strlen( tok ) + 1 ); 2224 require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr ); 2225 2226 strcpy( (*hInfo)->m_host.h_aliases[i], tok ); 2227 2228 if (( tok = strpbrk( tok, " \t")) != NULL ) 2229 { 2230 *tok++ = '\0'; 2231 } 2232 2233 (*hInfo)->m_host.h_aliases[++i] = NULL; 2234 } 2235 2236 break; 2237 } 2238 2239 exit: 2240 2241 if ( err && ( *hInfo ) ) 2242 { 2243 HostsFileInfoFree( *hInfo ); 2244 *hInfo = NULL; 2245 } 2246 2247 return err; 2248 } 2249 2250 2251 #ifdef ENABLE_REVERSE_LOOKUP 2252 //=========================================================================================================================== 2253 // IsReverseLookup 2254 //=========================================================================================================================== 2255 2256 DEBUG_LOCAL OSStatus 2257 IsReverseLookup( LPCWSTR name, size_t size ) 2258 { 2259 LPCWSTR p; 2260 OSStatus err = kNoErr; 2261 2262 // IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa 2263 require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND ); 2264 2265 p = name + ( size - 1 ); 2266 p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 ); 2267 2268 if ( ( ( p[ 0 ] != '.' ) || 2269 ( ( p[ 1 ] != '0' ) ) || 2270 ( ( p[ 2 ] != '.' ) ) || 2271 ( ( p[ 3 ] != '8' ) ) || 2272 ( ( p[ 4 ] != '.' ) ) || 2273 ( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) ) || 2274 ( ( p[ 6 ] != '.' ) ) || 2275 ( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) ) || 2276 ( ( p[ 8 ] != '.' ) ) || 2277 ( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) ) || 2278 ( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) ) || 2279 ( ( p[ 11 ] != '6' ) ) || 2280 ( ( p[ 12 ] != '.' ) ) || 2281 ( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) ) || 2282 ( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) ) || 2283 ( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) ) || 2284 ( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) ) 2285 { 2286 require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND ); 2287 2288 p = name + ( size - 1 ); 2289 p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 ); 2290 2291 require_action_quiet( ( ( p[ 0 ] == '.' ) && 2292 ( ( p[ 1 ] == '2' ) ) && 2293 ( ( p[ 2 ] == '5' ) ) && 2294 ( ( p[ 3 ] == '4' ) ) && 2295 ( ( p[ 4 ] == '.' ) ) && 2296 ( ( p[ 5 ] == '1' ) ) && 2297 ( ( p[ 6 ] == '6' ) ) && 2298 ( ( p[ 7 ] == '9' ) ) && 2299 ( ( p[ 8 ] == '.' ) ) && 2300 ( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) ) && 2301 ( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) ) && 2302 ( ( p[ 11 ] == '-' ) ) && 2303 ( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) ) && 2304 ( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) ) && 2305 ( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) ) && 2306 ( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) ) && 2307 ( ( p[ 16 ] == '.' ) ) && 2308 ( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) ) && 2309 ( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) ) && 2310 ( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) ) && 2311 ( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ), 2312 exit, err = WSASERVICE_NOT_FOUND ); 2313 } 2314 2315 // It's a reverse lookup 2316 2317 check( err == kNoErr ); 2318 2319 exit: 2320 2321 return err; 2322 } 2323 #endif 2324 2325 //=========================================================================================================================== 2326 // GetScopeId 2327 //=========================================================================================================================== 2328 2329 DEBUG_LOCAL DWORD 2330 GetScopeId( DWORD ifIndex ) 2331 { 2332 DWORD err; 2333 int i; 2334 DWORD flags; 2335 struct ifaddrs * head; 2336 struct ifaddrs ** next; 2337 IP_ADAPTER_ADDRESSES * iaaList; 2338 ULONG iaaListSize; 2339 IP_ADAPTER_ADDRESSES * iaa; 2340 DWORD scopeId = 0; 2341 2342 head = NULL; 2343 next = &head; 2344 iaaList = NULL; 2345 2346 require( gGetAdaptersAddressesFunctionPtr, exit ); 2347 2348 // Get the list of interfaces. The first call gets the size and the second call gets the actual data. 2349 // This loops to handle the case where the interface changes in the window after getting the size, but before the 2350 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong. 2351 2352 flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; 2353 i = 0; 2354 for( ;; ) 2355 { 2356 iaaListSize = 0; 2357 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize ); 2358 check( err == ERROR_BUFFER_OVERFLOW ); 2359 check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) ); 2360 2361 iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize ); 2362 require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY ); 2363 2364 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize ); 2365 if( err == ERROR_SUCCESS ) break; 2366 2367 free( iaaList ); 2368 iaaList = NULL; 2369 ++i; 2370 require( i < 100, exit ); 2371 dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err ); 2372 } 2373 2374 for( iaa = iaaList; iaa; iaa = iaa->Next ) 2375 { 2376 DWORD ipv6IfIndex; 2377 2378 if ( iaa->IfIndex > 0xFFFFFF ) 2379 { 2380 continue; 2381 } 2382 if ( iaa->Ipv6IfIndex > 0xFF ) 2383 { 2384 continue; 2385 } 2386 2387 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the 2388 // following code to crash when iterating through the prefix list. This seems 2389 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host. 2390 // This shouldn't happen according to Microsoft docs which states: 2391 // 2392 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface." 2393 // 2394 // So the data structure seems to be corrupted when we return from 2395 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length < 2396 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually 2397 // modify iaa to have the correct values. 2398 2399 if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) ) 2400 { 2401 ipv6IfIndex = iaa->Ipv6IfIndex; 2402 } 2403 else 2404 { 2405 ipv6IfIndex = 0; 2406 } 2407 2408 // Skip psuedo and tunnel interfaces. 2409 2410 if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) ) 2411 { 2412 continue; 2413 } 2414 2415 if ( iaa->IfIndex == ifIndex ) 2416 { 2417 scopeId = iaa->Ipv6IfIndex; 2418 break; 2419 } 2420 } 2421 2422 exit: 2423 2424 if( iaaList ) 2425 { 2426 free( iaaList ); 2427 } 2428 2429 return scopeId; 2430 } 2431