]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/mDNSWin32.c
mDNSResponder-258.21.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / mDNSWin32.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-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 To Do:
18
19 - Get unicode name of machine for nice name instead of just the host name.
20 - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
21 - Get DNS server address(es) from Windows and provide them to the uDNS layer.
22 - Implement TCP support for truncated packets (only stubs now).
23
24 */
25
26 #include <stdarg.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <crtdbg.h>
31 #include <string.h>
32
33 #include "CommonServices.h"
34 #include "DebugServices.h"
35 #include "Firewall.h"
36 #include "RegNames.h"
37 #include "Secret.h"
38 #include <dns_sd.h>
39
40 #include <Iphlpapi.h>
41 #include <mswsock.h>
42 #include <process.h>
43 #include <ntsecapi.h>
44 #include <lm.h>
45 #include <winioctl.h>
46 #include <ntddndis.h> // This defines the IOCTL constants.
47
48 #include "mDNSEmbeddedAPI.h"
49 #include "GenLinkedList.h"
50 #include "DNSCommon.h"
51 #include "mDNSWin32.h"
52
53 #if 0
54 #pragma mark == Constants ==
55 #endif
56
57 //===========================================================================================================================
58 // Constants
59 //===========================================================================================================================
60
61 #define DEBUG_NAME "[mDNSWin32] "
62
63 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
64 #define MDNS_WINDOWS_ENABLE_IPV4 1
65 #define MDNS_WINDOWS_ENABLE_IPV6 1
66 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
67 #define MDNS_SET_HINFO_STRINGS 0
68
69 #define kMDNSDefaultName "My Computer"
70
71 #define kWinSockMajorMin 2
72 #define kWinSockMinorMin 2
73
74 #define kRegistryMaxKeyLength 255
75 #define kRegistryMaxValueName 16383
76
77 static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
78
79 #define kIPv6IfIndexBase (10000000L)
80 #define SMBPortAsNumber 445
81 #define DEVICE_PREFIX "\\\\.\\"
82
83 #if 0
84 #pragma mark == Prototypes ==
85 #endif
86
87 //===========================================================================================================================
88 // Prototypes
89 //===========================================================================================================================
90
91 mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
92 mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
93 mDNSlocal mStatus SetupName( mDNS * const inMDNS );
94 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
95 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
96 mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD );
97 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
98 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
99 mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
100 mDNSlocal int getifaddrs( struct ifaddrs **outAddrs );
101 mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs );
102
103
104
105 // Platform Accessors
106
107 #ifdef __cplusplus
108 extern "C" {
109 #endif
110
111 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
112 struct mDNSPlatformInterfaceInfo
113 {
114 const char * name;
115 mDNSAddr ip;
116 };
117
118
119 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
120 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
121
122 // Utilities
123
124 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
125 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
126 #endif
127
128 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
129
130
131 mDNSlocal DWORD GetPrimaryInterface();
132 mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
133 mDNSlocal mDNSBool CanReceiveUnicast( void );
134 mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
135
136 mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
137 mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
138 mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
139 mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
140 mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
141 mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
142 mDNSlocal void TCPCanRead( TCPSocket * sock );
143 mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock );
144 mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
145 mDNSlocal void CALLBACK TCPFreeSocket( TCPSocket *sock );
146 mDNSlocal OSStatus UDPBeginRecv( UDPSocket * socket );
147 mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
148 mDNSlocal void CALLBACK UDPFreeSocket( UDPSocket * sock );
149 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
150 mDNSlocal void GetDDNSFQDN( domainname *const fqdn );
151 #ifdef UNICODE
152 mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
153 #else
154 mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
155 #endif
156 mDNSlocal void SetDomainSecrets( mDNS * const inMDNS );
157 mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain );
158 mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
159 mDNSlocal void CheckFileShares( mDNS * const inMDNS );
160 mDNSlocal void SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
161 mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName );
162 mDNSlocal void FreeSocketEventsForSocket( mDNS * const inMDNS, void * sock );
163 mDNSlocal void FreeSocketEvents( mDNS * const inMDNS );
164 mDNSlocal void TCPSocketEventHandler( mDNS * const inMDNS, void * v );
165 mDNSlocal void UDPSocketEventHandler( mDNS * const inMDNS, void * v );
166
167 #ifdef __cplusplus
168 }
169 #endif
170
171 #if 0
172 #pragma mark == Globals ==
173 #endif
174
175 //===========================================================================================================================
176 // Globals
177 //===========================================================================================================================
178
179 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
180 mDNSs32 mDNSPlatformOneSecond = 0;
181 mDNSlocal UDPSocket * gUDPSocketList = NULL;
182 mDNSlocal int gUDPSockets = 0;
183 mDNSlocal BOOL gSocketEventsEnabled = FALSE;
184 mDNSlocal GenLinkedList gSocketEvents;
185
186 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
187
188 typedef DWORD
189 ( WINAPI * GetAdaptersAddressesFunctionPtr )(
190 ULONG inFamily,
191 DWORD inFlags,
192 PVOID inReserved,
193 PIP_ADAPTER_ADDRESSES inAdapter,
194 PULONG outBufferSize );
195
196 mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
197 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
198
199 #endif
200
201
202 #ifndef HCRYPTPROV
203 typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249
204 #endif
205
206
207 #ifndef CRYPT_MACHINE_KEYSET
208 # define CRYPT_MACHINE_KEYSET 0x00000020
209 #endif
210
211 #ifndef CRYPT_NEWKEYSET
212 # define CRYPT_NEWKEYSET 0x00000008
213 #endif
214
215 #ifndef PROV_RSA_FULL
216 # define PROV_RSA_FULL 1
217 #endif
218
219 typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
220 typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
221 typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
222
223 static fnCryptAcquireContext g_lpCryptAcquireContext = NULL;
224 static fnCryptReleaseContext g_lpCryptReleaseContext = NULL;
225 static fnCryptGenRandom g_lpCryptGenRandom = NULL;
226 static HINSTANCE g_hAAPI32 = NULL;
227 static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL;
228
229
230 typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
231 (
232 DNSServiceRef *sdRef,
233 DNSServiceFlags flags,
234 uint32_t interfaceIndex,
235 const char *name, /* may be NULL */
236 const char *regtype,
237 const char *domain, /* may be NULL */
238 const char *host, /* may be NULL */
239 uint16_t port,
240 uint16_t txtLen,
241 const void *txtRecord, /* may be NULL */
242 DNSServiceRegisterReply callBack, /* may be NULL */
243 void *context /* may be NULL */
244 );
245
246
247 typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
248
249 mDNSlocal HMODULE gDNSSDLibrary = NULL;
250 mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister = NULL;
251 mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
252 mDNSlocal HANDLE gSMBThread = NULL;
253 mDNSlocal HANDLE gSMBThreadRegisterEvent = NULL;
254 mDNSlocal HANDLE gSMBThreadDeregisterEvent = NULL;
255 mDNSlocal HANDLE gSMBThreadStopEvent = NULL;
256 mDNSlocal HANDLE gSMBThreadQuitEvent = NULL;
257
258 #define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
259 #define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
260 #define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
261
262
263 #if 0
264 #pragma mark -
265 #pragma mark == Platform Support ==
266 #endif
267
268 //===========================================================================================================================
269 // mDNSPlatformInit
270 //===========================================================================================================================
271
272 mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
273 {
274 mStatus err;
275 WSADATA wsaData;
276 int supported;
277 struct sockaddr_in sa4;
278 struct sockaddr_in6 sa6;
279 int sa4len;
280 int sa6len;
281 DWORD size;
282 DWORD val;
283
284 dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
285
286 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
287 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
288
289 mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
290 if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
291 inMDNS->p->mainThread = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
292 require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
293 inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
294 require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
295 inMDNS->p->checkFileSharesTimeout = 10; // Retry time for CheckFileShares() in seconds
296 mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
297 InitLinkedList( &gSocketEvents, offsetof( SocketEvent, next));
298
299 // Startup WinSock 2.2 or later.
300
301 err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
302 require_noerr( err, exit );
303
304 supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
305 require_action( supported, exit, err = mStatus_UnsupportedErr );
306
307 inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
308
309 // Setup the HINFO HW strings.
310 //<rdar://problem/7245119> device-info should have model=Windows
311
312 strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
313 inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
314 dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
315
316 // Setup the HINFO SW strings.
317 #if ( MDNS_SET_HINFO_STRINGS )
318 mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
319 "mDNSResponder (%s %s)", __DATE__, __TIME__ );
320 inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
321 dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
322 #endif
323
324 // Set the thread global overlapped flag
325
326 val = 0;
327 err = setsockopt( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, ( char* ) &val, sizeof( val ) );
328 err = translate_errno( err != SOCKET_ERROR, WSAGetLastError(), kUnknownErr );
329 require_noerr( err, exit );
330
331 // Set up the IPv4 unicast socket
332
333 inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
334 inMDNS->p->unicastSock4.recvMsgPtr = NULL;
335 inMDNS->p->unicastSock4.ifd = NULL;
336 inMDNS->p->unicastSock4.next = NULL;
337 inMDNS->p->unicastSock4.m = inMDNS;
338
339 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
340
341 sa4.sin_family = AF_INET;
342 sa4.sin_addr.s_addr = INADDR_ANY;
343 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
344 check_noerr( err );
345 sa4len = sizeof( sa4 );
346 err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
347 require_noerr( err, exit );
348 inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
349 inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
350 err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
351
352 if ( err )
353 {
354 inMDNS->p->unicastSock4.recvMsgPtr = NULL;
355 }
356
357 err = UDPBeginRecv( &inMDNS->p->unicastSock4 );
358 require_noerr( err, exit );
359
360 #endif
361
362 // Set up the IPv6 unicast socket
363
364 inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
365 inMDNS->p->unicastSock6.recvMsgPtr = NULL;
366 inMDNS->p->unicastSock6.ifd = NULL;
367 inMDNS->p->unicastSock6.next = NULL;
368 inMDNS->p->unicastSock6.m = inMDNS;
369
370 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
371
372 sa6.sin6_family = AF_INET6;
373 sa6.sin6_addr = in6addr_any;
374 sa6.sin6_scope_id = 0;
375
376 // This call will fail if the machine hasn't installed IPv6. In that case,
377 // the error will be WSAEAFNOSUPPORT.
378
379 err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
380 require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
381 err = kNoErr;
382
383 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
384
385 if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
386 {
387 sa6len = sizeof( sa6 );
388 err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
389 require_noerr( err, exit );
390 inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
391 inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
392
393 err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
394
395 if ( err != 0 )
396 {
397 inMDNS->p->unicastSock6.recvMsgPtr = NULL;
398 }
399
400 err = UDPBeginRecv( &inMDNS->p->unicastSock6 );
401 require_noerr( err, exit );
402 }
403
404 #endif
405
406 // Notify core of domain secret keys
407
408 SetDomainSecrets( inMDNS );
409
410 // Success!
411
412 mDNSCoreInitComplete( inMDNS, err );
413
414
415 exit:
416
417 if ( err )
418 {
419 mDNSPlatformClose( inMDNS );
420 }
421
422 dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
423 return( err );
424 }
425
426 //===========================================================================================================================
427 // mDNSPlatformClose
428 //===========================================================================================================================
429
430 mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
431 {
432 mStatus err;
433
434 dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
435 check( inMDNS );
436
437 if ( gSMBThread != NULL )
438 {
439 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
440 SetEvent( gSMBThreadStopEvent );
441
442 if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
443 {
444 if ( gSMBThreadQuitEvent )
445 {
446 CloseHandle( gSMBThreadQuitEvent );
447 gSMBThreadQuitEvent = NULL;
448 }
449
450 if ( gSMBThreadStopEvent )
451 {
452 CloseHandle( gSMBThreadStopEvent );
453 gSMBThreadStopEvent = NULL;
454 }
455
456 if ( gSMBThreadDeregisterEvent )
457 {
458 CloseHandle( gSMBThreadDeregisterEvent );
459 gSMBThreadDeregisterEvent = NULL;
460 }
461
462 if ( gSMBThreadRegisterEvent )
463 {
464 CloseHandle( gSMBThreadRegisterEvent );
465 gSMBThreadRegisterEvent = NULL;
466 }
467
468 if ( gDNSSDLibrary )
469 {
470 FreeLibrary( gDNSSDLibrary );
471 gDNSSDLibrary = NULL;
472 }
473 }
474 else
475 {
476 LogMsg( "Unable to stop SMBThread" );
477 }
478
479 inMDNS->p->smbFileSharing = mDNSfalse;
480 inMDNS->p->smbPrintSharing = mDNSfalse;
481 }
482
483 // Tear everything down in reverse order to how it was set up.
484
485 err = TearDownInterfaceList( inMDNS );
486 check_noerr( err );
487 check( !inMDNS->p->inactiveInterfaceList );
488
489 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
490
491 if ( inMDNS->p->unicastSock4.fd != INVALID_SOCKET )
492 {
493 closesocket( inMDNS->p->unicastSock4.fd );
494 inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
495 }
496
497 #endif
498
499 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
500
501 if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
502 {
503 closesocket( inMDNS->p->unicastSock6.fd );
504 inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
505 }
506
507 #endif
508
509 // Free the DLL needed for IPv6 support.
510
511 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
512 if( gIPHelperLibraryInstance )
513 {
514 gGetAdaptersAddressesFunctionPtr = NULL;
515
516 FreeLibrary( gIPHelperLibraryInstance );
517 gIPHelperLibraryInstance = NULL;
518 }
519 #endif
520
521 if ( g_hAAPI32 )
522 {
523 // Release any resources
524
525 if ( g_hProvider && g_lpCryptReleaseContext )
526 {
527 ( g_lpCryptReleaseContext )( g_hProvider, 0 );
528 }
529
530 // Free the AdvApi32.dll
531
532 FreeLibrary( g_hAAPI32 );
533
534 // And reset all the data
535
536 g_lpCryptAcquireContext = NULL;
537 g_lpCryptReleaseContext = NULL;
538 g_lpCryptGenRandom = NULL;
539 g_hProvider = ( ULONG_PTR ) NULL;
540 g_hAAPI32 = NULL;
541 }
542
543 // Clear out the APC queue
544
545 SetSocketEventsEnabled( inMDNS, TRUE );
546 while ( SleepEx( 0, TRUE ) == WAIT_IO_COMPLETION );
547 SetSocketEventsEnabled( inMDNS, FALSE );
548
549 WSACleanup();
550
551 dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
552 }
553
554
555 //===========================================================================================================================
556 // mDNSPlatformLock
557 //===========================================================================================================================
558
559 mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
560 {
561 ( void ) inMDNS;
562 }
563
564 //===========================================================================================================================
565 // mDNSPlatformUnlock
566 //===========================================================================================================================
567
568 mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
569 {
570 ( void ) inMDNS;
571 }
572
573 //===========================================================================================================================
574 // mDNSPlatformStrCopy
575 //===========================================================================================================================
576
577 mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
578 {
579 check( inSrc );
580 check( inDst );
581
582 strcpy( (char *) inDst, (const char*) inSrc );
583 }
584
585 //===========================================================================================================================
586 // mDNSPlatformStrLen
587 //===========================================================================================================================
588
589 mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
590 {
591 check( inSrc );
592
593 return( (mDNSu32) strlen( (const char *) inSrc ) );
594 }
595
596 //===========================================================================================================================
597 // mDNSPlatformMemCopy
598 //===========================================================================================================================
599
600 mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
601 {
602 check( inSrc );
603 check( inDst );
604
605 memcpy( inDst, inSrc, inSize );
606 }
607
608 //===========================================================================================================================
609 // mDNSPlatformMemSame
610 //===========================================================================================================================
611
612 mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
613 {
614 check( inSrc );
615 check( inDst );
616
617 return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
618 }
619
620 //===========================================================================================================================
621 // mDNSPlatformMemZero
622 //===========================================================================================================================
623
624 mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
625 {
626 check( inDst );
627
628 memset( inDst, 0, inSize );
629 }
630
631 //===========================================================================================================================
632 // mDNSPlatformMemAllocate
633 //===========================================================================================================================
634
635 mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
636 {
637 void * mem;
638
639 check( inSize > 0 );
640
641 mem = malloc( inSize );
642 check( mem );
643
644 return( mem );
645 }
646
647 //===========================================================================================================================
648 // mDNSPlatformMemFree
649 //===========================================================================================================================
650
651 mDNSexport void mDNSPlatformMemFree( void *inMem )
652 {
653 check( inMem );
654
655 free( inMem );
656 }
657
658 //===========================================================================================================================
659 // mDNSPlatformRandomNumber
660 //===========================================================================================================================
661
662 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
663 {
664 mDNSu32 randomNumber = 0;
665 BOOL bResult;
666 OSStatus err = 0;
667
668 if ( !g_hAAPI32 )
669 {
670 g_hAAPI32 = LoadLibrary( TEXT("AdvAPI32.dll") );
671 err = translate_errno( g_hAAPI32 != NULL, GetLastError(), mStatus_UnknownErr );
672 require_noerr( err, exit );
673 }
674
675 // Function Pointer: CryptAcquireContext
676
677 if ( !g_lpCryptAcquireContext )
678 {
679 g_lpCryptAcquireContext = ( fnCryptAcquireContext )
680 #ifdef UNICODE
681 ( GetProcAddress( g_hAAPI32, "CryptAcquireContextW" ) );
682 #else
683 ( GetProcAddress( g_hAAPI32, "CryptAcquireContextA" ) );
684 #endif
685 err = translate_errno( g_lpCryptAcquireContext != NULL, GetLastError(), mStatus_UnknownErr );
686 require_noerr( err, exit );
687 }
688
689 // Function Pointer: CryptReleaseContext
690
691 if ( !g_lpCryptReleaseContext )
692 {
693 g_lpCryptReleaseContext = ( fnCryptReleaseContext )
694 ( GetProcAddress( g_hAAPI32, "CryptReleaseContext" ) );
695 err = translate_errno( g_lpCryptReleaseContext != NULL, GetLastError(), mStatus_UnknownErr );
696 require_noerr( err, exit );
697 }
698
699 // Function Pointer: CryptGenRandom
700
701 if ( !g_lpCryptGenRandom )
702 {
703 g_lpCryptGenRandom = ( fnCryptGenRandom )
704 ( GetProcAddress( g_hAAPI32, "CryptGenRandom" ) );
705 err = translate_errno( g_lpCryptGenRandom != NULL, GetLastError(), mStatus_UnknownErr );
706 require_noerr( err, exit );
707 }
708
709 // Setup
710
711 if ( !g_hProvider )
712 {
713 bResult = (*g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET );
714
715 if ( !bResult )
716 {
717 bResult = ( *g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET );
718 err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
719 require_noerr( err, exit );
720 }
721 }
722
723 bResult = (*g_lpCryptGenRandom)( g_hProvider, sizeof( randomNumber ), ( BYTE* ) &randomNumber );
724 err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr );
725 require_noerr( err, exit );
726
727 exit:
728
729 if ( err )
730 {
731 randomNumber = rand();
732 }
733
734 return randomNumber;
735 }
736
737 //===========================================================================================================================
738 // mDNSPlatformTimeInit
739 //===========================================================================================================================
740
741 mDNSexport mStatus mDNSPlatformTimeInit( void )
742 {
743 // No special setup is required on Windows -- we just use GetTickCount().
744 return( mStatus_NoError );
745 }
746
747 //===========================================================================================================================
748 // mDNSPlatformRawTime
749 //===========================================================================================================================
750
751 mDNSexport mDNSs32 mDNSPlatformRawTime( void )
752 {
753 return( (mDNSs32) GetTickCount() );
754 }
755
756 //===========================================================================================================================
757 // mDNSPlatformUTC
758 //===========================================================================================================================
759
760 mDNSexport mDNSs32 mDNSPlatformUTC( void )
761 {
762 return ( mDNSs32 ) time( NULL );
763 }
764
765 //===========================================================================================================================
766 // mDNSPlatformInterfaceNameToID
767 //===========================================================================================================================
768
769 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
770 {
771 mStatus err;
772 mDNSInterfaceData * ifd;
773
774 check( inMDNS );
775 check( inMDNS->p );
776 check( inName );
777
778 // Search for an interface with the specified name,
779
780 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
781 {
782 if( strcmp( ifd->name, inName ) == 0 )
783 {
784 break;
785 }
786 }
787 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
788
789 // Success!
790
791 if( outID )
792 {
793 *outID = (mDNSInterfaceID) ifd;
794 }
795 err = mStatus_NoError;
796
797 exit:
798 return( err );
799 }
800
801 //===========================================================================================================================
802 // mDNSPlatformInterfaceIDToInfo
803 //===========================================================================================================================
804
805 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
806 {
807 mStatus err;
808 mDNSInterfaceData * ifd;
809
810 check( inMDNS );
811 check( inID );
812 check( outInfo );
813
814 // Search for an interface with the specified ID,
815
816 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
817 {
818 if( ifd == (mDNSInterfaceData *) inID )
819 {
820 break;
821 }
822 }
823 require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
824
825 // Success!
826
827 outInfo->name = ifd->name;
828 outInfo->ip = ifd->interfaceInfo.ip;
829 err = mStatus_NoError;
830
831 exit:
832 return( err );
833 }
834
835 //===========================================================================================================================
836 // mDNSPlatformInterfaceIDfromInterfaceIndex
837 //===========================================================================================================================
838
839 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
840 {
841 mDNSInterfaceID id;
842
843 id = mDNSNULL;
844 if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
845 {
846 id = mDNSInterface_LocalOnly;
847 }
848 /* uncomment if Windows ever supports P2P
849 else if( inIndex == kDNSServiceInterfaceIndexP2P )
850 {
851 id = mDNSInterface_P2P;
852 }
853 */
854 else if( inIndex != 0 )
855 {
856 mDNSInterfaceData * ifd;
857
858 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
859 {
860 if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
861 {
862 id = ifd->interfaceInfo.InterfaceID;
863 break;
864 }
865 }
866 check( ifd );
867 }
868 return( id );
869 }
870
871 //===========================================================================================================================
872 // mDNSPlatformInterfaceIndexfromInterfaceID
873 //===========================================================================================================================
874
875 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID )
876 {
877 mDNSu32 index;
878
879 index = 0;
880 if( inID == mDNSInterface_LocalOnly )
881 {
882 index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
883 }
884 /* uncomment if Windows ever supports P2P
885 else if( inID == mDNSInterface_P2P )
886 {
887 index = (mDNSu32) kDNSServiceInterfaceIndexP2P;
888 }
889 */
890 else if( inID )
891 {
892 mDNSInterfaceData * ifd;
893
894 // Search active interfaces.
895 for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
896 {
897 if( (mDNSInterfaceID) ifd == inID )
898 {
899 index = ifd->scopeID;
900 break;
901 }
902 }
903
904 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
905
906 if( !ifd )
907 {
908 for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
909 {
910 if( (mDNSInterfaceID) ifd == inID )
911 {
912 index = ifd->scopeID;
913 break;
914 }
915 }
916 }
917 check( ifd );
918 }
919 return( index );
920 }
921
922
923 //===========================================================================================================================
924 // mDNSPlatformTCPSocket
925 //===========================================================================================================================
926
927 TCPSocket *
928 mDNSPlatformTCPSocket
929 (
930 mDNS * const m,
931 TCPSocketFlags flags,
932 mDNSIPPort * port
933 )
934 {
935 TCPSocket * sock = NULL;
936 u_long on = 1; // "on" for setsockopt
937 struct sockaddr_in saddr;
938 int len;
939 mStatus err = mStatus_NoError;
940
941 DEBUG_UNUSED( m );
942
943 require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
944
945 // Setup connection data object
946
947 sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
948 require_action( sock, exit, err = mStatus_NoMemoryErr );
949 mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
950 sock->fd = INVALID_SOCKET;
951 sock->flags = flags;
952 sock->m = m;
953
954 mDNSPlatformMemZero(&saddr, sizeof(saddr));
955 saddr.sin_family = AF_INET;
956 saddr.sin_addr.s_addr = htonl( INADDR_ANY );
957 saddr.sin_port = port->NotAnInteger;
958
959 // Create the socket
960
961 sock->fd = socket(AF_INET, SOCK_STREAM, 0);
962 err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
963 require_noerr( err, exit );
964
965 // bind
966
967 err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
968 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
969 require_noerr( err, exit );
970
971 // Set it to be non-blocking
972
973 err = ioctlsocket( sock->fd, FIONBIO, &on );
974 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
975 require_noerr( err, exit );
976
977 // Get port number
978
979 mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
980 len = sizeof( saddr );
981
982 err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
983 err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
984 require_noerr( err, exit );
985
986 port->NotAnInteger = saddr.sin_port;
987
988 exit:
989
990 if ( err && sock )
991 {
992 TCPFreeSocket( sock );
993 sock = mDNSNULL;
994 }
995
996 return sock;
997 }
998
999 //===========================================================================================================================
1000 // mDNSPlatformTCPConnect
1001 //===========================================================================================================================
1002
1003 mStatus
1004 mDNSPlatformTCPConnect
1005 (
1006 TCPSocket * sock,
1007 const mDNSAddr * inDstIP,
1008 mDNSOpaque16 inDstPort,
1009 domainname * hostname,
1010 mDNSInterfaceID inInterfaceID,
1011 TCPConnectionCallback inCallback,
1012 void * inContext
1013 )
1014 {
1015 struct sockaddr_in saddr;
1016 ( void ) hostname;
1017 mStatus err = mStatus_NoError;
1018
1019 DEBUG_UNUSED( inInterfaceID );
1020
1021 if ( inDstIP->type != mDNSAddrType_IPv4 )
1022 {
1023 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1024 return mStatus_UnknownErr;
1025 }
1026
1027 // Setup connection data object
1028
1029 sock->readEventHandler = TCPCanRead;
1030 sock->userCallback = inCallback;
1031 sock->userContext = inContext;
1032
1033 mDNSPlatformMemZero(&saddr, sizeof(saddr));
1034 saddr.sin_family = AF_INET;
1035 saddr.sin_port = inDstPort.NotAnInteger;
1036 memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
1037
1038 // Try and do connect
1039
1040 err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
1041 require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
1042 sock->connected = !err ? TRUE : FALSE;
1043
1044 if ( sock->connected )
1045 {
1046 err = TCPAddSocket( sock->m, sock );
1047 require_noerr( err, exit );
1048 }
1049 else
1050 {
1051 require_action( sock->m->p->registerWaitableEventFunc != NULL, exit, err = mStatus_ConnFailed );
1052
1053 sock->connectEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
1054 err = translate_errno( sock->connectEvent, GetLastError(), mStatus_UnknownErr );
1055 require_noerr( err, exit );
1056
1057 err = WSAEventSelect( sock->fd, sock->connectEvent, FD_CONNECT );
1058 require_noerr( err, exit );
1059
1060 err = sock->m->p->registerWaitableEventFunc( sock->m, sock->connectEvent, sock, TCPDidConnect );
1061 require_noerr( err, exit );
1062 }
1063
1064 exit:
1065
1066 if ( !err )
1067 {
1068 err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
1069 }
1070
1071 return err;
1072 }
1073
1074 //===========================================================================================================================
1075 // mDNSPlatformTCPAccept
1076 //===========================================================================================================================
1077
1078 mDNSexport
1079 mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
1080 {
1081 TCPSocket * sock = NULL;
1082 mStatus err = mStatus_NoError;
1083
1084 require_action( !flags, exit, err = mStatus_UnsupportedErr );
1085
1086 sock = malloc( sizeof( TCPSocket ) );
1087 require_action( sock, exit, err = mStatus_NoMemoryErr );
1088
1089 mDNSPlatformMemZero( sock, sizeof( *sock ) );
1090
1091 sock->fd = fd;
1092 sock->flags = flags;
1093
1094 exit:
1095
1096 if ( err && sock )
1097 {
1098 free( sock );
1099 sock = NULL;
1100 }
1101
1102 return sock;
1103 }
1104
1105
1106 //===========================================================================================================================
1107 // mDNSPlatformTCPCloseConnection
1108 //===========================================================================================================================
1109
1110 mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
1111 {
1112 check( sock );
1113
1114 if ( sock->connectEvent && sock->m->p->unregisterWaitableEventFunc )
1115 {
1116 sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
1117 }
1118
1119 if ( sock->fd != INVALID_SOCKET )
1120 {
1121 closesocket( sock->fd );
1122 sock->fd = INVALID_SOCKET;
1123
1124 QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
1125 }
1126
1127 FreeSocketEventsForSocket( sock->m, sock );
1128 }
1129
1130 //===========================================================================================================================
1131 // mDNSPlatformReadTCP
1132 //===========================================================================================================================
1133
1134 mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
1135 {
1136 unsigned long bytesLeft;
1137 int wsaError;
1138 long ret;
1139
1140 *closed = sock->closed;
1141 wsaError = sock->lastError;
1142 ret = -1;
1143
1144 if ( *closed )
1145 {
1146 ret = 0;
1147 }
1148 else if ( sock->lastError == 0 )
1149 {
1150 // First check to see if we have any data left in our buffer
1151
1152 bytesLeft = ( DWORD ) ( sock->eptr - sock->bptr );
1153
1154 if ( bytesLeft )
1155 {
1156 unsigned long bytesToCopy = ( bytesLeft < inBufferSize ) ? bytesLeft : inBufferSize;
1157
1158 memcpy( inBuffer, sock->bptr, bytesToCopy );
1159 sock->bptr += bytesToCopy;
1160
1161 ret = bytesToCopy;
1162
1163 if ( bytesLeft == bytesToCopy )
1164 {
1165 sock->lastError = TCPBeginRecv( sock );
1166
1167 // If we can't immediately queue up another read, abort the connection
1168 // now, even if we successfully wrote bytes to the buffer.
1169 // We don't expect this to happen unless something is seriously borked.
1170 // If we run into this in the real world, we should consider queuing up
1171 // a user APC function to defer an explicit callback to the read event handler
1172 // to inform the consumer of the problem.
1173
1174 if ( sock->lastError )
1175 {
1176 dlog( kDebugLevelError, DEBUG_NAME "TCPBeginRecv failed with error %d\n", sock->lastError );
1177 wsaError = sock->lastError;
1178 ret = -1;
1179 }
1180 }
1181 }
1182 else
1183 {
1184 wsaError = WSAEWOULDBLOCK;
1185 }
1186 }
1187
1188 // Always set the last winsock error, so that we don't inadvertently use a previous one
1189
1190 WSASetLastError( wsaError );
1191
1192 return ret;
1193 }
1194
1195
1196 //===========================================================================================================================
1197 // mDNSPlatformWriteTCP
1198 //===========================================================================================================================
1199
1200 mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
1201 {
1202 int nsent;
1203 OSStatus err;
1204
1205 nsent = send( sock->fd, inMsg, inMsgSize, 0 );
1206
1207 err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
1208 require_noerr( err, exit );
1209
1210 if ( nsent < 0)
1211 {
1212 nsent = 0;
1213 }
1214
1215 exit:
1216
1217 return nsent;
1218 }
1219
1220 //===========================================================================================================================
1221 // mDNSPlatformTCPGetFD
1222 //===========================================================================================================================
1223
1224 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
1225 {
1226 return ( int ) sock->fd;
1227 }
1228
1229
1230 //===========================================================================================================================
1231 // TCPAddConnection
1232 //===========================================================================================================================
1233
1234 mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
1235 {
1236 mStatus err;
1237
1238 ( void ) inMDNS;
1239
1240 dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
1241 err = TCPBeginRecv( sock );
1242 require_noerr( err, exit );
1243
1244 exit:
1245
1246 return err;
1247 }
1248
1249
1250 //===========================================================================================================================
1251 // TCPDidConnect
1252 //===========================================================================================================================
1253
1254 mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context )
1255 {
1256 TCPSocket * sock = ( TCPSocket* ) context;
1257 TCPConnectionCallback callback = NULL;
1258 WSANETWORKEVENTS sockEvent;
1259 int err = kNoErr;
1260
1261 if ( inMDNS->p->unregisterWaitableEventFunc )
1262 {
1263 inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );
1264 }
1265
1266 if ( sock )
1267 {
1268 callback = ( TCPConnectionCallback ) sock->userCallback;
1269 err = WSAEnumNetworkEvents( sock->fd, sock->connectEvent, &sockEvent );
1270 require_noerr( err, exit );
1271 require_action( sockEvent.lNetworkEvents & FD_CONNECT, exit, err = mStatus_UnknownErr );
1272 require_action( sockEvent.iErrorCode[ FD_CONNECT_BIT ] == 0, exit, err = sockEvent.iErrorCode[ FD_CONNECT_BIT ] );
1273
1274 sock->connected = mDNStrue;
1275
1276 if ( sock->fd != INVALID_SOCKET )
1277 {
1278 err = TCPAddSocket( sock->m, sock );
1279 require_noerr( err, exit );
1280 }
1281
1282 if ( callback )
1283 {
1284 callback( sock, sock->userContext, TRUE, 0 );
1285 }
1286 }
1287
1288 exit:
1289
1290 if ( err && callback )
1291 {
1292 callback( sock, sock->userContext, TRUE, err );
1293 }
1294 }
1295
1296
1297
1298 //===========================================================================================================================
1299 // TCPCanRead
1300 //===========================================================================================================================
1301
1302 mDNSlocal void TCPCanRead( TCPSocket * sock )
1303 {
1304 TCPConnectionCallback callback = ( TCPConnectionCallback ) sock->userCallback;
1305
1306 if ( callback )
1307 {
1308 callback( sock, sock->userContext, mDNSfalse, sock->lastError );
1309 }
1310 }
1311
1312
1313 //===========================================================================================================================
1314 // TCPBeginRecv
1315 //===========================================================================================================================
1316
1317 mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock )
1318 {
1319 DWORD bytesReceived = 0;
1320 DWORD flags = 0;
1321 mStatus err;
1322
1323 ZeroMemory( &sock->overlapped, sizeof( sock->overlapped ) );
1324 sock->overlapped.hEvent = sock;
1325
1326 sock->wbuf.buf = ( char* ) sock->buf;
1327 sock->wbuf.len = sizeof( sock->buf );
1328
1329 err = WSARecv( sock->fd, &sock->wbuf, 1, &bytesReceived, &flags, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) TCPEndRecv );
1330 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), WSAGetLastError(), kUnknownErr );
1331 require_noerr( err, exit );
1332
1333 exit:
1334
1335 return err;
1336 }
1337
1338
1339 //===========================================================================================================================
1340 // TCPEndRecv
1341 //===========================================================================================================================
1342
1343 mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
1344 {
1345 TCPSocket * sock;
1346
1347 ( void ) flags;
1348
1349 sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
1350
1351 if ( sock && ( sock->fd != INVALID_SOCKET ) )
1352 {
1353 // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
1354 //
1355 // There seems to be a bug in WinSock with respect to Alertable I/O. According
1356 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
1357 // callbacks will only be invoked during the following calls (when the caller sets
1358 // the appropriate flag):
1359 //
1360 // - SleepEx
1361 // - WaitForSingleObjectEx
1362 // - WaitForMultipleObjectsEx
1363 // - SignalObjectAndWait
1364 // - MsgWaitForMultipleObjectsEx
1365 //
1366 // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
1367 // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
1368 // to directly call the readEventHandler. Otherwise we queue the packet up and
1369 // dispatch it later.
1370
1371 if ( gSocketEventsEnabled && !gSocketEvents.Head )
1372 {
1373 sock->lastError = error;
1374
1375 if ( !error )
1376 {
1377 if ( bytesTransferred )
1378 {
1379 sock->bptr = sock->buf;
1380 sock->eptr = sock->buf + bytesTransferred;
1381 }
1382 else
1383 {
1384 sock->closed = TRUE;
1385 }
1386 }
1387
1388 if ( sock->readEventHandler != NULL )
1389 {
1390 // Turn off socket events before calling the readEventHandler.
1391 // This will prevent reentrancy problems.
1392 //
1393 // Don't forget to reenable socket events afterwards.
1394
1395 SetSocketEventsEnabled( sock->m, FALSE );
1396 sock->readEventHandler( sock );
1397 SetSocketEventsEnabled( sock->m, TRUE );
1398 }
1399 }
1400 else
1401 {
1402 TCPSocketEvent * event;
1403
1404 event = malloc( sizeof( TCPSocketEvent ) );
1405 require_action( event, exit, error = ( DWORD ) kNoMemoryErr );
1406 event->super.sock = sock;
1407 event->super.handler = &TCPSocketEventHandler;
1408 event->super.next = NULL;
1409 event->error = error;
1410 event->bytesTransferred = bytesTransferred;
1411
1412 if ( bytesTransferred )
1413 {
1414 memcpy( event->buf, sock->buf, bytesTransferred );
1415 }
1416
1417 AddToTail( &gSocketEvents, event );
1418 }
1419 }
1420
1421 exit:
1422
1423 return;
1424 }
1425
1426
1427 //===========================================================================================================================
1428 // mDNSPlatformUDPSocket
1429 //===========================================================================================================================
1430
1431 mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
1432 {
1433 UDPSocket* sock = NULL;
1434 mDNSIPPort port = requestedport;
1435 mStatus err = mStatus_NoError;
1436 unsigned i;
1437
1438 // Setup connection data object
1439
1440 sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
1441 require_action( sock, exit, err = mStatus_NoMemoryErr );
1442 memset( sock, 0, sizeof( UDPSocket ) );
1443
1444 // Create the socket
1445
1446 sock->fd = INVALID_SOCKET;
1447 sock->recvMsgPtr = m->p->unicastSock4.recvMsgPtr;
1448 sock->addr = m->p->unicastSock4.addr;
1449 sock->ifd = NULL;
1450 sock->m = m;
1451
1452 // Try at most 10000 times to get a unique random port
1453
1454 for (i=0; i<10000; i++)
1455 {
1456 struct sockaddr_in saddr;
1457
1458 saddr.sin_family = AF_INET;
1459 saddr.sin_addr.s_addr = 0;
1460
1461 // The kernel doesn't do cryptographically strong random port
1462 // allocation, so we do it ourselves here
1463
1464 if (mDNSIPPortIsZero(requestedport))
1465 {
1466 port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
1467 }
1468
1469 saddr.sin_port = port.NotAnInteger;
1470
1471 err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
1472 if (!err) break;
1473 }
1474
1475 require_noerr( err, exit );
1476
1477 // Set the port
1478
1479 sock->port = port;
1480
1481 // Arm the completion routine
1482
1483 err = UDPBeginRecv( sock );
1484 require_noerr( err, exit );
1485
1486 // Bookkeeping
1487
1488 sock->next = gUDPSocketList;
1489 gUDPSocketList = sock;
1490 gUDPSockets++;
1491
1492 exit:
1493
1494 if ( err && sock )
1495 {
1496 UDPFreeSocket( sock );
1497 sock = NULL;
1498 }
1499
1500 return sock;
1501 }
1502
1503 //===========================================================================================================================
1504 // mDNSPlatformUDPClose
1505 //===========================================================================================================================
1506
1507 mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
1508 {
1509 UDPSocket * current = gUDPSocketList;
1510 UDPSocket * last = NULL;
1511
1512 while ( current )
1513 {
1514 if ( current == sock )
1515 {
1516 if ( last == NULL )
1517 {
1518 gUDPSocketList = sock->next;
1519 }
1520 else
1521 {
1522 last->next = sock->next;
1523 }
1524
1525 // Alertable I/O is great, except not so much when it comes to closing
1526 // the socket. Anything that has been previously queued for this socket
1527 // will stay in the queue after you close the socket. This is problematic
1528 // for obvious reasons. So we'll attempt to workaround this by closing
1529 // the socket which will prevent any further queued packets and then not calling
1530 // UDPFreeSocket directly, but by queueing it using QueueUserAPC. The queues
1531 // are FIFO, so that will execute *after* any other previous items in the queue
1532 //
1533 // UDPEndRecv will check if the socket is valid, and if not, it will ignore
1534 // the packet
1535
1536 closesocket( sock->fd );
1537 sock->fd = INVALID_SOCKET;
1538
1539 QueueUserAPC( ( PAPCFUNC ) UDPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
1540 FreeSocketEventsForSocket( sock->m, sock );
1541
1542 gUDPSockets--;
1543
1544 break;
1545 }
1546
1547 last = current;
1548 current = current->next;
1549 }
1550 }
1551
1552
1553 //===========================================================================================================================
1554 // mDNSPlatformSendUDP
1555 //===========================================================================================================================
1556
1557 mDNSexport mStatus
1558 mDNSPlatformSendUDP(
1559 const mDNS * const inMDNS,
1560 const void * const inMsg,
1561 const mDNSu8 * const inMsgEnd,
1562 mDNSInterfaceID inInterfaceID,
1563 UDPSocket * inSrcSocket,
1564 const mDNSAddr * inDstIP,
1565 mDNSIPPort inDstPort )
1566 {
1567 SOCKET sendingsocket = INVALID_SOCKET;
1568 mStatus err = mStatus_NoError;
1569 mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
1570 struct sockaddr_storage addr;
1571 int n;
1572
1573 DEBUG_USE_ONLY( inMDNS );
1574
1575 n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
1576 check( inMDNS );
1577 check( inMsg );
1578 check( inMsgEnd );
1579 check( inDstIP );
1580
1581 dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
1582
1583 if( inDstIP->type == mDNSAddrType_IPv4 )
1584 {
1585 struct sockaddr_in * sa4;
1586
1587 sa4 = (struct sockaddr_in *) &addr;
1588 sa4->sin_family = AF_INET;
1589 sa4->sin_port = inDstPort.NotAnInteger;
1590 sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
1591 sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
1592
1593 if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
1594 }
1595 else if( inDstIP->type == mDNSAddrType_IPv6 )
1596 {
1597 struct sockaddr_in6 * sa6;
1598
1599 sa6 = (struct sockaddr_in6 *) &addr;
1600 sa6->sin6_family = AF_INET6;
1601 sa6->sin6_port = inDstPort.NotAnInteger;
1602 sa6->sin6_flowinfo = 0;
1603 sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
1604 sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
1605 sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
1606 }
1607 else
1608 {
1609 dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
1610 err = mStatus_BadParamErr;
1611 goto exit;
1612 }
1613
1614 if (IsValidSocket(sendingsocket))
1615 {
1616 n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
1617 err = translate_errno( n > 0, errno_compat(), kWriteErr );
1618
1619 if ( err )
1620 {
1621 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1622
1623 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
1624 {
1625 err = mStatus_TransientErr;
1626 }
1627 else
1628 {
1629 require_noerr( err, exit );
1630 }
1631 }
1632 }
1633
1634 exit:
1635 return( err );
1636 }
1637
1638
1639 mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
1640 {
1641 DEBUG_UNUSED( m );
1642 DEBUG_UNUSED( InterfaceID );
1643 }
1644
1645 //===========================================================================================================================
1646 // mDNSPlatformSendRawPacket
1647 //===========================================================================================================================
1648
1649 mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
1650 {
1651 DEBUG_UNUSED( msg );
1652 DEBUG_UNUSED( end );
1653 DEBUG_UNUSED( InterfaceID );
1654 }
1655
1656 mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
1657 {
1658 DEBUG_UNUSED( msg );
1659 DEBUG_UNUSED( end );
1660 DEBUG_UNUSED( InterfaceID );
1661 }
1662
1663 mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
1664 {
1665 DEBUG_UNUSED( tpa );
1666 DEBUG_UNUSED( tha );
1667 DEBUG_UNUSED( InterfaceID );
1668 }
1669
1670 mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
1671 {
1672 dlog( kDebugLevelInfo, "%s\n", msg );
1673 }
1674
1675 mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
1676 {
1677 extern mDNS mDNSStorage;
1678 int type;
1679
1680 DEBUG_UNUSED( ident );
1681
1682 type = EVENTLOG_ERROR_TYPE;
1683
1684 switch (loglevel)
1685 {
1686 case MDNS_LOG_MSG: type = EVENTLOG_ERROR_TYPE; break;
1687 case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE; break;
1688 case MDNS_LOG_SPS: type = EVENTLOG_INFORMATION_TYPE; break;
1689 case MDNS_LOG_INFO: type = EVENTLOG_INFORMATION_TYPE; break;
1690 case MDNS_LOG_DEBUG: type = EVENTLOG_INFORMATION_TYPE; break;
1691 default:
1692 fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
1693 fflush(stderr);
1694 }
1695
1696 mDNSStorage.p->reportStatusFunc( type, msg );
1697 dlog( kDebugLevelInfo, "%s\n", msg );
1698 }
1699
1700 mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
1701 {
1702 DEBUG_UNUSED( src );
1703 DEBUG_UNUSED( dst );
1704 }
1705
1706 //===========================================================================================================================
1707 // mDNSPlatformTLSSetupCerts
1708 //===========================================================================================================================
1709
1710 mDNSexport mStatus
1711 mDNSPlatformTLSSetupCerts(void)
1712 {
1713 return mStatus_UnsupportedErr;
1714 }
1715
1716 //===========================================================================================================================
1717 // mDNSPlatformTLSTearDownCerts
1718 //===========================================================================================================================
1719
1720 mDNSexport void
1721 mDNSPlatformTLSTearDownCerts(void)
1722 {
1723 }
1724
1725 //===========================================================================================================================
1726 // mDNSPlatformSetDNSConfig
1727 //===========================================================================================================================
1728
1729 mDNSlocal void SetDNSServers( mDNS *const m );
1730 mDNSlocal void SetSearchDomainList( void );
1731
1732 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains)
1733 {
1734 if (setservers) SetDNSServers(m);
1735 if (setsearch) SetSearchDomainList();
1736
1737 if ( fqdn )
1738 {
1739 GetDDNSFQDN( fqdn );
1740 }
1741
1742 if ( browseDomains )
1743 {
1744 GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
1745 }
1746
1747 if ( regDomains )
1748 {
1749 GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
1750 }
1751 }
1752
1753
1754 //===========================================================================================================================
1755 // mDNSPlatformDynDNSHostNameStatusChanged
1756 //===========================================================================================================================
1757
1758 mDNSexport void
1759 mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
1760 {
1761 char uname[MAX_ESCAPED_DOMAIN_NAME];
1762 BYTE bStatus;
1763 LPCTSTR name;
1764 HKEY key = NULL;
1765 mStatus err;
1766 char * p;
1767
1768 ConvertDomainNameToCString(dname, uname);
1769
1770 p = uname;
1771
1772 while (*p)
1773 {
1774 *p = (char) tolower(*p);
1775 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
1776 p++;
1777 }
1778
1779 check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
1780 name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
1781 err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
1782 require_noerr( err, exit );
1783
1784 bStatus = ( status ) ? 0 : 1;
1785 err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
1786 require_noerr( err, exit );
1787
1788 exit:
1789
1790 if ( key )
1791 {
1792 RegCloseKey( key );
1793 }
1794
1795 return;
1796 }
1797
1798
1799 //===========================================================================================================================
1800 // SetDomainSecrets
1801 //===========================================================================================================================
1802
1803 // This routine needs to be called whenever the system secrets database changes.
1804 // We call it from DynDNSConfigDidChange and mDNSPlatformInit
1805
1806 void
1807 SetDomainSecrets( mDNS * const m )
1808 {
1809 DomainAuthInfo *ptr;
1810 domainname fqdn;
1811 DNameListElem * regDomains = NULL;
1812
1813 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
1814 // In the case where the user simultaneously removes their DDNS host name and the key
1815 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
1816 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
1817 // address records behind that we no longer have permission to delete.
1818
1819 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
1820 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
1821
1822 GetDDNSFQDN( &fqdn );
1823
1824 if ( fqdn.c[ 0 ] )
1825 {
1826 SetDomainSecret( m, &fqdn );
1827 }
1828
1829 GetDDNSDomains( &regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
1830
1831 while ( regDomains )
1832 {
1833 DNameListElem * current = regDomains;
1834 SetDomainSecret( m, &current->name );
1835 regDomains = regDomains->next;
1836 free( current );
1837 }
1838 }
1839
1840
1841 //===========================================================================================================================
1842 // SetSearchDomainList
1843 //===========================================================================================================================
1844
1845 mDNSlocal void SetDomainFromDHCP( void );
1846 mDNSlocal void SetReverseMapSearchDomainList( void );
1847
1848 mDNSlocal void
1849 SetSearchDomainList( void )
1850 {
1851 char * searchList = NULL;
1852 DWORD searchListLen;
1853 //DNameListElem * head = NULL;
1854 //DNameListElem * current = NULL;
1855 char * tok;
1856 HKEY key;
1857 mStatus err;
1858
1859 err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
1860 require_noerr( err, exit );
1861
1862 err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
1863 require_noerr( err, exit );
1864
1865 // Windows separates the search domains with ','
1866
1867 tok = strtok( searchList, "," );
1868 while ( tok )
1869 {
1870 if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
1871 mDNS_AddSearchDomain_CString(tok);
1872 tok = strtok( NULL, "," );
1873 }
1874
1875 exit:
1876
1877 if ( searchList )
1878 {
1879 free( searchList );
1880 }
1881
1882 if ( key )
1883 {
1884 RegCloseKey( key );
1885 }
1886
1887 SetDomainFromDHCP();
1888 SetReverseMapSearchDomainList();
1889 }
1890
1891
1892 //===========================================================================================================================
1893 // SetReverseMapSearchDomainList
1894 //===========================================================================================================================
1895
1896 mDNSlocal void
1897 SetReverseMapSearchDomainList( void )
1898 {
1899 struct ifaddrs * ifa;
1900
1901 ifa = myGetIfAddrs( 1 );
1902 while (ifa)
1903 {
1904 mDNSAddr addr;
1905
1906 if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
1907 {
1908 mDNSAddr netmask;
1909 char buffer[256];
1910
1911 if (!SetupAddr(&netmask, ifa->ifa_netmask))
1912 {
1913 sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
1914 addr.ip.v4.b[2] & netmask.ip.v4.b[2],
1915 addr.ip.v4.b[1] & netmask.ip.v4.b[1],
1916 addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
1917 mDNS_AddSearchDomain_CString(buffer);
1918 }
1919 }
1920
1921 ifa = ifa->ifa_next;
1922 }
1923
1924 return;
1925 }
1926
1927
1928 //===========================================================================================================================
1929 // SetDNSServers
1930 //===========================================================================================================================
1931
1932 mDNSlocal void
1933 SetDNSServers( mDNS *const m )
1934 {
1935 PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
1936 FIXED_INFO * fixedInfo = NULL;
1937 ULONG bufLen = 0;
1938 IP_ADDR_STRING * dnsServerList;
1939 IP_ADDR_STRING * ipAddr;
1940 DWORD index;
1941 int i = 0;
1942 mStatus err = kUnknownErr;
1943
1944 // Get the primary interface.
1945
1946 index = GetPrimaryInterface();
1947
1948 // This should have the interface index of the primary index. Fall back in cases where
1949 // it can't be determined.
1950
1951 if ( index )
1952 {
1953 bufLen = 0;
1954
1955 for ( i = 0; i < 100; i++ )
1956 {
1957 err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
1958
1959 if ( err != ERROR_BUFFER_OVERFLOW )
1960 {
1961 break;
1962 }
1963
1964 pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
1965 require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
1966 }
1967
1968 require_noerr( err, exit );
1969
1970 dnsServerList = &pAdapterInfo->DnsServerList;
1971 }
1972 else
1973 {
1974 bufLen = sizeof( FIXED_INFO );
1975
1976 for ( i = 0; i < 100; i++ )
1977 {
1978 if ( fixedInfo )
1979 {
1980 GlobalFree( fixedInfo );
1981 fixedInfo = NULL;
1982 }
1983
1984 fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
1985 require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
1986
1987 err = GetNetworkParams( fixedInfo, &bufLen );
1988
1989 if ( err != ERROR_BUFFER_OVERFLOW )
1990 {
1991 break;
1992 }
1993 }
1994
1995 require_noerr( err, exit );
1996
1997 dnsServerList = &fixedInfo->DnsServerList;
1998 }
1999
2000 for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
2001 {
2002 mDNSAddr addr;
2003 err = StringToAddress( &addr, ipAddr->IpAddress.String );
2004 if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
2005 }
2006
2007 exit:
2008
2009 if ( pAdapterInfo )
2010 {
2011 free( pAdapterInfo );
2012 }
2013
2014 if ( fixedInfo )
2015 {
2016 GlobalFree( fixedInfo );
2017 }
2018 }
2019
2020
2021 //===========================================================================================================================
2022 // SetDomainFromDHCP
2023 //===========================================================================================================================
2024
2025 mDNSlocal void
2026 SetDomainFromDHCP( void )
2027 {
2028 int i = 0;
2029 IP_ADAPTER_INFO * pAdapterInfo;
2030 IP_ADAPTER_INFO * pAdapter;
2031 DWORD bufLen;
2032 DWORD index;
2033 HKEY key = NULL;
2034 LPSTR domain = NULL;
2035 DWORD dwSize;
2036 mStatus err = mStatus_NoError;
2037
2038 pAdapterInfo = NULL;
2039
2040 for ( i = 0; i < 100; i++ )
2041 {
2042 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2043
2044 if ( err != ERROR_BUFFER_OVERFLOW )
2045 {
2046 break;
2047 }
2048
2049 pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
2050 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2051 }
2052
2053 require_noerr( err, exit );
2054
2055 index = GetPrimaryInterface();
2056
2057 for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
2058 {
2059 if ( pAdapter->IpAddressList.IpAddress.String &&
2060 pAdapter->IpAddressList.IpAddress.String[0] &&
2061 pAdapter->GatewayList.IpAddress.String &&
2062 pAdapter->GatewayList.IpAddress.String[0] &&
2063 ( !index || ( pAdapter->Index == index ) ) )
2064 {
2065 // Found one that will work
2066
2067 char keyName[1024];
2068
2069 _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
2070
2071 err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
2072 require_noerr( err, exit );
2073
2074 err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
2075 check_noerr( err );
2076
2077 if ( !domain || !domain[0] )
2078 {
2079 if ( domain )
2080 {
2081 free( domain );
2082 domain = NULL;
2083 }
2084
2085 err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
2086 check_noerr( err );
2087 }
2088
2089 if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain);
2090
2091 break;
2092 }
2093 }
2094
2095 exit:
2096
2097 if ( pAdapterInfo )
2098 {
2099 free( pAdapterInfo );
2100 }
2101
2102 if ( domain )
2103 {
2104 free( domain );
2105 }
2106
2107 if ( key )
2108 {
2109 RegCloseKey( key );
2110 }
2111 }
2112
2113
2114 //===========================================================================================================================
2115 // mDNSPlatformGetPrimaryInterface
2116 //===========================================================================================================================
2117
2118 mDNSexport mStatus
2119 mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
2120 {
2121 IP_ADAPTER_INFO * pAdapterInfo;
2122 IP_ADAPTER_INFO * pAdapter;
2123 DWORD bufLen;
2124 int i;
2125 BOOL found;
2126 DWORD index;
2127 mStatus err = mStatus_NoError;
2128
2129 DEBUG_UNUSED( m );
2130
2131 *v6 = zeroAddr;
2132
2133 pAdapterInfo = NULL;
2134 bufLen = 0;
2135 found = FALSE;
2136
2137 for ( i = 0; i < 100; i++ )
2138 {
2139 err = GetAdaptersInfo( pAdapterInfo, &bufLen);
2140
2141 if ( err != ERROR_BUFFER_OVERFLOW )
2142 {
2143 break;
2144 }
2145
2146 pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
2147 require_action( pAdapterInfo, exit, err = kNoMemoryErr );
2148 }
2149
2150 require_noerr( err, exit );
2151
2152 index = GetPrimaryInterface();
2153
2154 for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
2155 {
2156 if ( pAdapter->IpAddressList.IpAddress.String &&
2157 pAdapter->IpAddressList.IpAddress.String[0] &&
2158 pAdapter->GatewayList.IpAddress.String &&
2159 pAdapter->GatewayList.IpAddress.String[0] &&
2160 ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
2161 ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
2162 ( !index || ( pAdapter->Index == index ) ) )
2163 {
2164 // Found one that will work
2165
2166 if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
2167 {
2168 memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
2169 }
2170
2171 found = TRUE;
2172 break;
2173 }
2174 }
2175
2176 exit:
2177
2178 if ( pAdapterInfo )
2179 {
2180 free( pAdapterInfo );
2181 }
2182
2183 return err;
2184 }
2185
2186 mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
2187 {
2188 (void) m;
2189 (void) InterfaceID;
2190 (void) EthAddr;
2191 (void) IPAddr;
2192 (void) iteration;
2193 }
2194
2195 #if 0
2196 #pragma mark -
2197 #endif
2198
2199 //===========================================================================================================================
2200 // debugf_
2201 //===========================================================================================================================
2202 #if( MDNS_DEBUGMSGS )
2203 mDNSexport void debugf_( const char *inFormat, ... )
2204 {
2205 char buffer[ 512 ];
2206 va_list args;
2207 mDNSu32 length;
2208
2209 va_start( args, inFormat );
2210 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2211 va_end( args );
2212
2213 dlog( kDebugLevelInfo, "%s\n", buffer );
2214 }
2215 #endif
2216
2217 //===========================================================================================================================
2218 // verbosedebugf_
2219 //===========================================================================================================================
2220
2221 #if( MDNS_DEBUGMSGS > 1 )
2222 mDNSexport void verbosedebugf_( const char *inFormat, ... )
2223 {
2224 char buffer[ 512 ];
2225 va_list args;
2226 mDNSu32 length;
2227
2228 va_start( args, inFormat );
2229 length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
2230 va_end( args );
2231
2232 dlog( kDebugLevelVerbose, "%s\n", buffer );
2233 }
2234 #endif
2235
2236
2237 #if 0
2238 #pragma mark -
2239 #pragma mark == Platform Internals ==
2240 #endif
2241
2242
2243 //===========================================================================================================================
2244 // SetupNiceName
2245 //===========================================================================================================================
2246
2247 mStatus SetupNiceName( mDNS * const inMDNS )
2248 {
2249 HKEY descKey = NULL;
2250 char utf8[ 256 ];
2251 LPCTSTR s;
2252 LPWSTR joinName;
2253 NETSETUP_JOIN_STATUS joinStatus;
2254 mStatus err = 0;
2255 DWORD namelen;
2256 BOOL ok;
2257
2258 check( inMDNS );
2259
2260 // Set up the nice name.
2261 utf8[0] = '\0';
2262
2263 // First try and open the registry key that contains the computer description value
2264 s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2265 err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
2266 check_translated_errno( err == 0, errno_compat(), kNameErr );
2267
2268 if ( !err )
2269 {
2270 TCHAR desc[256];
2271 DWORD descSize = sizeof( desc );
2272
2273 // look for the computer description
2274 err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
2275
2276 if ( !err )
2277 {
2278 err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
2279 }
2280
2281 if ( err )
2282 {
2283 utf8[ 0 ] = '\0';
2284 }
2285 }
2286
2287 // if we can't find it in the registry, then use the hostname of the machine
2288 if ( err || ( utf8[ 0 ] == '\0' ) )
2289 {
2290 TCHAR hostname[256];
2291
2292 namelen = sizeof( hostname ) / sizeof( TCHAR );
2293
2294 ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
2295 err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
2296 check_noerr( err );
2297
2298 if( !err )
2299 {
2300 err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
2301 }
2302
2303 if ( err )
2304 {
2305 utf8[ 0 ] = '\0';
2306 }
2307 }
2308
2309 // if we can't get the hostname
2310 if ( err || ( utf8[ 0 ] == '\0' ) )
2311 {
2312 // Invalidate name so fall back to a default name.
2313
2314 strcpy( utf8, kMDNSDefaultName );
2315 }
2316
2317 utf8[ sizeof( utf8 ) - 1 ] = '\0';
2318 inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
2319 memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
2320
2321 dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
2322
2323 if ( descKey )
2324 {
2325 RegCloseKey( descKey );
2326 }
2327
2328 ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
2329 ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
2330
2331 namelen = sizeof( inMDNS->p->nbname );
2332 ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
2333 check( ok );
2334 if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
2335
2336 err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
2337 check ( err == NERR_Success );
2338 if ( err == NERR_Success )
2339 {
2340 if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
2341 {
2342 err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
2343 check( !err );
2344 if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
2345 }
2346
2347 NetApiBufferFree( joinName );
2348 joinName = NULL;
2349 }
2350
2351 err = 0;
2352
2353 return( err );
2354 }
2355
2356 //===========================================================================================================================
2357 // SetupHostName
2358 //===========================================================================================================================
2359
2360 mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
2361 {
2362 mStatus err = 0;
2363 char tempString[ 256 ];
2364 DWORD tempStringLen;
2365 domainlabel tempLabel;
2366 BOOL ok;
2367
2368 check( inMDNS );
2369
2370 // Set up the nice name.
2371 tempString[ 0 ] = '\0';
2372
2373 // use the hostname of the machine
2374 tempStringLen = sizeof( tempString );
2375 ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
2376 err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
2377 check_noerr( err );
2378
2379 // if we can't get the hostname
2380 if( err || ( tempString[ 0 ] == '\0' ) )
2381 {
2382 // Invalidate name so fall back to a default name.
2383
2384 strcpy( tempString, kMDNSDefaultName );
2385 }
2386
2387 tempString[ sizeof( tempString ) - 1 ] = '\0';
2388 tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
2389 memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
2390
2391 // Set up the host name.
2392
2393 ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
2394 if( inMDNS->hostlabel.c[ 0 ] == 0 )
2395 {
2396 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2397
2398 MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
2399 }
2400
2401 check( inMDNS->hostlabel.c[ 0 ] != 0 );
2402
2403 mDNS_SetFQDN( inMDNS );
2404
2405 dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
2406
2407 return( err );
2408 }
2409
2410 //===========================================================================================================================
2411 // SetupName
2412 //===========================================================================================================================
2413
2414 mDNSlocal mStatus SetupName( mDNS * const inMDNS )
2415 {
2416 mStatus err = 0;
2417
2418 check( inMDNS );
2419
2420 err = SetupNiceName( inMDNS );
2421 check_noerr( err );
2422
2423 err = SetupHostName( inMDNS );
2424 check_noerr( err );
2425
2426 return err;
2427 }
2428
2429
2430 //===========================================================================================================================
2431 // SetupInterfaceList
2432 //===========================================================================================================================
2433
2434 mStatus SetupInterfaceList( mDNS * const inMDNS )
2435 {
2436 mStatus err;
2437 mDNSInterfaceData ** next;
2438 mDNSInterfaceData * ifd;
2439 struct ifaddrs * addrs;
2440 struct ifaddrs * p;
2441 struct ifaddrs * loopbackv4;
2442 struct ifaddrs * loopbackv6;
2443 u_int flagMask;
2444 u_int flagTest;
2445 mDNSBool foundv4;
2446 mDNSBool foundv6;
2447 mDNSBool foundUnicastSock4DestAddr;
2448 mDNSBool foundUnicastSock6DestAddr;
2449
2450 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
2451 check( inMDNS );
2452 check( inMDNS->p );
2453
2454 inMDNS->p->registeredLoopback4 = mDNSfalse;
2455 inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
2456 addrs = NULL;
2457 foundv4 = mDNSfalse;
2458 foundv6 = mDNSfalse;
2459 foundUnicastSock4DestAddr = mDNSfalse;
2460 foundUnicastSock6DestAddr = mDNSfalse;
2461
2462 // Tear down any existing interfaces that may be set up.
2463
2464 TearDownInterfaceList( inMDNS );
2465
2466 // Set up the name of this machine.
2467
2468 err = SetupName( inMDNS );
2469 check_noerr( err );
2470
2471 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2472 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2473
2474 err = getifaddrs( &addrs );
2475 require_noerr( err, exit );
2476
2477 loopbackv4 = NULL;
2478 loopbackv6 = NULL;
2479 next = &inMDNS->p->interfaceList;
2480
2481 flagMask = IFF_UP | IFF_MULTICAST;
2482 flagTest = IFF_UP | IFF_MULTICAST;
2483
2484 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2485 for( p = addrs; p; p = p->ifa_next )
2486 {
2487 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2488 {
2489 continue;
2490 }
2491 if( p->ifa_flags & IFF_LOOPBACK )
2492 {
2493 if( !loopbackv4 )
2494 {
2495 loopbackv4 = p;
2496 }
2497 continue;
2498 }
2499 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2500 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2501
2502 err = SetupInterface( inMDNS, p, &ifd );
2503 require_noerr( err, exit );
2504
2505 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2506 // register him, but we also want to note that we haven't found a v4 interface
2507 // so that we register loopback so same host operations work
2508
2509 if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
2510 {
2511 foundv4 = mDNStrue;
2512 }
2513
2514 if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
2515 {
2516 inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
2517 }
2518
2519 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2520 // of determing the destination address of a packet that is sent to us.
2521 // For multicast packets, that's easy to determine. But for the unicast
2522 // sockets, we'll fake it by taking the address of the first interface
2523 // that is successfully setup.
2524
2525 if ( !foundUnicastSock4DestAddr )
2526 {
2527 inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
2528 foundUnicastSock4DestAddr = TRUE;
2529 }
2530
2531 *next = ifd;
2532 next = &ifd->next;
2533 ++inMDNS->p->interfaceCount;
2534 }
2535 #endif
2536
2537 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2538
2539 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2540 for( p = addrs; p; p = p->ifa_next )
2541 {
2542 if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2543 {
2544 continue;
2545 }
2546 if( p->ifa_flags & IFF_LOOPBACK )
2547 {
2548 if( !loopbackv6 )
2549 {
2550 loopbackv6 = p;
2551 }
2552 continue;
2553 }
2554 dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2555 p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
2556
2557 err = SetupInterface( inMDNS, p, &ifd );
2558 require_noerr( err, exit );
2559
2560 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2561 // register him, but we also want to note that we haven't found a v4 interface
2562 // so that we register loopback so same host operations work
2563
2564 if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
2565 {
2566 foundv6 = mDNStrue;
2567 }
2568
2569 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2570 // of determing the destination address of a packet that is sent to us.
2571 // For multicast packets, that's easy to determine. But for the unicast
2572 // sockets, we'll fake it by taking the address of the first interface
2573 // that is successfully setup.
2574
2575 if ( !foundUnicastSock6DestAddr )
2576 {
2577 inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
2578 foundUnicastSock6DestAddr = TRUE;
2579 }
2580
2581 *next = ifd;
2582 next = &ifd->next;
2583 ++inMDNS->p->interfaceCount;
2584 }
2585 #endif
2586
2587 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2588
2589 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2590
2591 flagMask |= IFF_LOOPBACK;
2592 flagTest |= IFF_LOOPBACK;
2593
2594 for( p = addrs; p; p = p->ifa_next )
2595 {
2596 if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
2597 {
2598 continue;
2599 }
2600 if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
2601 {
2602 continue;
2603 }
2604
2605 v4loopback = p;
2606 break;
2607 }
2608
2609 #endif
2610
2611 if ( !foundv4 && loopbackv4 )
2612 {
2613 dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2614 loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
2615
2616 err = SetupInterface( inMDNS, loopbackv4, &ifd );
2617 require_noerr( err, exit );
2618
2619 inMDNS->p->registeredLoopback4 = mDNStrue;
2620
2621 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2622
2623 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2624 // of determing the destination address of a packet that is sent to us.
2625 // For multicast packets, that's easy to determine. But for the unicast
2626 // sockets, we'll fake it by taking the address of the first interface
2627 // that is successfully setup.
2628
2629 if ( !foundUnicastSock4DestAddr )
2630 {
2631 inMDNS->p->unicastSock4.addr = ifd->sock.addr;
2632 foundUnicastSock4DestAddr = TRUE;
2633 }
2634 #endif
2635
2636 *next = ifd;
2637 next = &ifd->next;
2638 ++inMDNS->p->interfaceCount;
2639 }
2640
2641 if ( !foundv6 && loopbackv6 )
2642 {
2643 dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
2644 loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
2645
2646 err = SetupInterface( inMDNS, loopbackv6, &ifd );
2647 require_noerr( err, exit );
2648
2649 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2650
2651 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2652 // of determing the destination address of a packet that is sent to us.
2653 // For multicast packets, that's easy to determine. But for the unicast
2654 // sockets, we'll fake it by taking the address of the first interface
2655 // that is successfully setup.
2656
2657 if ( !foundUnicastSock6DestAddr )
2658 {
2659 inMDNS->p->unicastSock6.addr = ifd->sock.addr;
2660 foundUnicastSock6DestAddr = TRUE;
2661 }
2662 #endif
2663
2664 *next = ifd;
2665 next = &ifd->next;
2666 ++inMDNS->p->interfaceCount;
2667 }
2668
2669 CheckFileShares( inMDNS );
2670
2671 exit:
2672 if( err )
2673 {
2674 TearDownInterfaceList( inMDNS );
2675 }
2676 if( addrs )
2677 {
2678 freeifaddrs( addrs );
2679 }
2680 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
2681 return( err );
2682 }
2683
2684 //===========================================================================================================================
2685 // TearDownInterfaceList
2686 //===========================================================================================================================
2687
2688 mStatus TearDownInterfaceList( mDNS * const inMDNS )
2689 {
2690 mDNSInterfaceData ** p;
2691 mDNSInterfaceData * ifd;
2692
2693 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
2694 check( inMDNS );
2695 check( inMDNS->p );
2696
2697 // Free any pending events received.
2698
2699 FreeSocketEvents( inMDNS );
2700
2701 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2702 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2703 // so that remove events that occur after an interface goes away can still report the correct interface.
2704
2705 p = &inMDNS->p->inactiveInterfaceList;
2706 while( *p )
2707 {
2708 ifd = *p;
2709 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
2710 {
2711 p = &ifd->next;
2712 continue;
2713 }
2714
2715 dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
2716 *p = ifd->next;
2717
2718 QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
2719 }
2720
2721 // Tear down all the interfaces.
2722
2723 while( inMDNS->p->interfaceList )
2724 {
2725 ifd = inMDNS->p->interfaceList;
2726 inMDNS->p->interfaceList = ifd->next;
2727
2728 TearDownInterface( inMDNS, ifd );
2729 }
2730 inMDNS->p->interfaceCount = 0;
2731
2732 dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
2733 return( mStatus_NoError );
2734 }
2735
2736 //===========================================================================================================================
2737 // SetupInterface
2738 //===========================================================================================================================
2739
2740 mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
2741 {
2742 mDNSInterfaceData * ifd;
2743 mDNSInterfaceData * p;
2744 mStatus err;
2745
2746 ifd = NULL;
2747 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
2748 check( inMDNS );
2749 check( inMDNS->p );
2750 check( inIFA );
2751 check( inIFA->ifa_addr );
2752 check( outIFD );
2753
2754 // Allocate memory for the interface and initialize it.
2755
2756 ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
2757 require_action( ifd, exit, err = mStatus_NoMemoryErr );
2758 ifd->sock.fd = kInvalidSocketRef;
2759 ifd->sock.ifd = ifd;
2760 ifd->sock.next = NULL;
2761 ifd->sock.m = inMDNS;
2762 ifd->index = inIFA->ifa_extra.index;
2763 ifd->scopeID = inIFA->ifa_extra.index;
2764 check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
2765 strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
2766 ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
2767
2768 strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
2769 ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
2770
2771 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2772 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2773 // on a large configured network, which means there's a good chance that most or all the other devices on that
2774 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2775 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2776 // devices on a large configured network, so we are willing to make that sacrifice.
2777
2778 ifd->interfaceInfo.McastTxRx = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
2779 ifd->interfaceInfo.InterfaceID = NULL;
2780
2781 for( p = inMDNS->p->interfaceList; p; p = p->next )
2782 {
2783 if ( strcmp( p->name, ifd->name ) == 0 )
2784 {
2785 if (!ifd->interfaceInfo.InterfaceID)
2786 {
2787 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
2788 }
2789
2790 if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
2791 ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
2792 ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
2793 {
2794 ifd->interfaceInfo.McastTxRx = mDNSfalse;
2795 }
2796
2797 break;
2798 }
2799 }
2800
2801 if ( !ifd->interfaceInfo.InterfaceID )
2802 {
2803 ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
2804 }
2805
2806 // Set up a socket for this interface (if needed).
2807
2808 if( ifd->interfaceInfo.McastTxRx )
2809 {
2810 DWORD size;
2811
2812 err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
2813 require_noerr( err, exit );
2814 ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
2815 ifd->sock.port = MulticastDNSPort;
2816
2817 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2818
2819 err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
2820
2821 if ( err )
2822 {
2823 ifd->sock.recvMsgPtr = NULL;
2824 }
2825 }
2826
2827 if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
2828 {
2829 inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
2830 }
2831
2832 ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
2833
2834 // Register this interface with mDNS.
2835
2836 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
2837 require_noerr( err, exit );
2838
2839 err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
2840 require_noerr( err, exit );
2841
2842 memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
2843
2844 ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
2845
2846 if ( ifd->sock.fd != kInvalidSocketRef )
2847 {
2848 err = UDPBeginRecv( &ifd->sock );
2849 require_noerr( err, exit );
2850 }
2851
2852 err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
2853 require_noerr( err, exit );
2854 ifd->hostRegistered = mDNStrue;
2855
2856 dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
2857
2858 // Success!
2859
2860 *outIFD = ifd;
2861 ifd = NULL;
2862
2863 exit:
2864
2865 if( ifd )
2866 {
2867 TearDownInterface( inMDNS, ifd );
2868 }
2869 dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
2870 return( err );
2871 }
2872
2873 //===========================================================================================================================
2874 // TearDownInterface
2875 //===========================================================================================================================
2876
2877 mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
2878 {
2879 check( inMDNS );
2880 check( inIFD );
2881
2882 // Deregister this interface with mDNS.
2883
2884 dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
2885
2886 if( inIFD->hostRegistered )
2887 {
2888 inIFD->hostRegistered = mDNSfalse;
2889 mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
2890 }
2891
2892 // Tear down the multicast socket.
2893
2894 if ( inIFD->sock.fd != INVALID_SOCKET )
2895 {
2896 closesocket( inIFD->sock.fd );
2897 inIFD->sock.fd = INVALID_SOCKET;
2898 }
2899
2900 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2901 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2902
2903 if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
2904 {
2905 inIFD->next = inMDNS->p->inactiveInterfaceList;
2906 inMDNS->p->inactiveInterfaceList = inIFD;
2907 dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
2908 }
2909 else
2910 {
2911 dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
2912 QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
2913 }
2914
2915 return( mStatus_NoError );
2916 }
2917
2918 mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
2919 {
2920 free( inIFD );
2921 }
2922
2923 //===========================================================================================================================
2924 // SetupSocket
2925 //===========================================================================================================================
2926
2927 mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
2928 {
2929 mStatus err;
2930 SocketRef sock;
2931 int option;
2932 DWORD bytesReturned = 0;
2933 BOOL behavior = FALSE;
2934
2935 DEBUG_UNUSED( inMDNS );
2936
2937 dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
2938 check( inMDNS );
2939 check( outSocketRef );
2940
2941 // Set up an IPv4 or IPv6 UDP socket.
2942
2943 sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
2944 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
2945 require_noerr( err, exit );
2946
2947 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2948 // if we're creating a multicast socket
2949
2950 if ( port.NotAnInteger )
2951 {
2952 option = 1;
2953 err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
2954 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2955 }
2956
2957 // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
2958 //
2959 // Not sure why, but the default behavior for sockets is to behave incorrectly
2960 // when using them in Overlapped I/O mode on XP. According to MSDN:
2961 //
2962 // SIO_UDP_CONNRESET (opcode setting: I, T==3)
2963 // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
2964 // Set to FALSE to disable reporting.
2965 //
2966 // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
2967 // messages were being sent to us after we sent out packets to a multicast address. This is clearly
2968 // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
2969 // will no longer receive any packets from that socket, which is not harmless. This behavior is only
2970 // seen on XP.
2971 //
2972 // So we turn off port unreachable reporting to make sure our sockets that are reading
2973 // multicast packets function correctly under all circumstances.
2974
2975 err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
2976 check_translated_errno( err == 0, errno_compat(), kOptionErr );
2977
2978 if( inAddr->sa_family == AF_INET )
2979 {
2980 mDNSv4Addr ipv4;
2981 struct sockaddr_in sa4;
2982 struct ip_mreq mreqv4;
2983
2984 // Bind the socket to the desired port
2985
2986 ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
2987 mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
2988 sa4.sin_family = AF_INET;
2989 sa4.sin_port = port.NotAnInteger;
2990 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
2991
2992 err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
2993 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
2994
2995 // Turn on option to receive destination addresses and receiving interface.
2996
2997 option = 1;
2998 err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
2999 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3000
3001 if (port.NotAnInteger)
3002 {
3003 // Join the all-DNS multicast group so we receive Multicast DNS packets
3004
3005 mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
3006 mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
3007 err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
3008 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3009
3010 // Specify the interface to send multicast packets on this socket.
3011
3012 sa4.sin_addr.s_addr = ipv4.NotAnInteger;
3013 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
3014 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3015
3016 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3017
3018 option = 1;
3019 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
3020 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3021 }
3022
3023 // Send unicast packets with TTL 255 (helps against spoofing).
3024
3025 option = 255;
3026 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
3027 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3028
3029 // Send multicast packets with TTL 255 (helps against spoofing).
3030
3031 option = 255;
3032 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
3033 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3034
3035 }
3036 else if( inAddr->sa_family == AF_INET6 )
3037 {
3038 struct sockaddr_in6 * sa6p;
3039 struct sockaddr_in6 sa6;
3040 struct ipv6_mreq mreqv6;
3041
3042 sa6p = (struct sockaddr_in6 *) inAddr;
3043
3044 // Bind the socket to the desired port
3045
3046 mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
3047 sa6.sin6_family = AF_INET6;
3048 sa6.sin6_port = port.NotAnInteger;
3049 sa6.sin6_flowinfo = 0;
3050 sa6.sin6_addr = sa6p->sin6_addr;
3051 sa6.sin6_scope_id = sa6p->sin6_scope_id;
3052
3053 err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
3054 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
3055
3056 // Turn on option to receive destination addresses and receiving interface.
3057
3058 option = 1;
3059 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
3060 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3061
3062 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3063 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3064 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3065
3066 #if( defined( IPV6_V6ONLY ) )
3067 option = 1;
3068 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
3069 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3070 #endif
3071
3072 if ( port.NotAnInteger )
3073 {
3074 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3075
3076 mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
3077 mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
3078 err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
3079 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3080
3081 // Specify the interface to send multicast packets on this socket.
3082
3083 option = (int) sa6p->sin6_scope_id;
3084 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
3085 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3086
3087 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3088
3089 option = 1;
3090 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
3091 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3092 }
3093
3094 // Send unicast packets with TTL 255 (helps against spoofing).
3095
3096 option = 255;
3097 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
3098 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3099
3100 // Send multicast packets with TTL 255 (helps against spoofing).
3101
3102 option = 255;
3103 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
3104 check_translated_errno( err == 0, errno_compat(), kOptionErr );
3105 }
3106 else
3107 {
3108 dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
3109 err = kUnsupportedErr;
3110 goto exit;
3111 }
3112
3113 // Success!
3114
3115 *outSocketRef = sock;
3116 sock = kInvalidSocketRef;
3117 err = mStatus_NoError;
3118
3119 exit:
3120 if( IsValidSocket( sock ) )
3121 {
3122 close_compat( sock );
3123 }
3124 return( err );
3125 }
3126
3127 //===========================================================================================================================
3128 // SetupSocket
3129 //===========================================================================================================================
3130
3131 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
3132 {
3133 mStatus err;
3134
3135 check( inSA );
3136 check( outIP );
3137
3138 if( inSA->sa_family == AF_INET )
3139 {
3140 struct sockaddr_in * sa4;
3141
3142 sa4 = (struct sockaddr_in *) inSA;
3143 outIP->type = mDNSAddrType_IPv4;
3144 outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
3145 if( outPort )
3146 {
3147 outPort->NotAnInteger = sa4->sin_port;
3148 }
3149 err = mStatus_NoError;
3150 }
3151 else if( inSA->sa_family == AF_INET6 )
3152 {
3153 struct sockaddr_in6 * sa6;
3154
3155 sa6 = (struct sockaddr_in6 *) inSA;
3156 outIP->type = mDNSAddrType_IPv6;
3157 outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
3158 if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
3159 {
3160 outIP->ip.v6.w[ 1 ] = 0;
3161 }
3162 if( outPort )
3163 {
3164 outPort->NotAnInteger = sa6->sin6_port;
3165 }
3166 err = mStatus_NoError;
3167 }
3168 else
3169 {
3170 dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
3171 err = mStatus_BadParamErr;
3172 }
3173 return( err );
3174 }
3175
3176
3177 #if 0
3178 #pragma mark -
3179 #endif
3180
3181 //===========================================================================================================================
3182 // UDPBeginRecv
3183 //===========================================================================================================================
3184
3185 mDNSlocal OSStatus UDPBeginRecv( UDPSocket * sock )
3186 {
3187 DWORD size;
3188 DWORD numTries;
3189 OSStatus err;
3190
3191 require_action( socket != NULL, exit, err = kUnknownErr );
3192
3193 // Initialize the buffer structure
3194
3195 sock->wbuf.buf = (char *) &sock->packet;
3196 sock->wbuf.len = (u_long) sizeof( sock->packet );
3197 sock->srcAddrLen = sizeof( sock->srcAddr );
3198
3199 // Initialize the overlapped structure
3200
3201 ZeroMemory( &sock->overlapped, sizeof( OVERLAPPED ) );
3202 sock->overlapped.hEvent = sock;
3203
3204 numTries = 0;
3205
3206 do
3207 {
3208 if ( sock->recvMsgPtr )
3209 {
3210 sock->wmsg.name = ( LPSOCKADDR ) &sock->srcAddr;
3211 sock->wmsg.namelen = sock->srcAddrLen;
3212 sock->wmsg.lpBuffers = &sock->wbuf;
3213 sock->wmsg.dwBufferCount = 1;
3214 sock->wmsg.Control.buf = ( CHAR* ) sock->controlBuffer;
3215 sock->wmsg.Control.len = sizeof( sock->controlBuffer );
3216 sock->wmsg.dwFlags = 0;
3217
3218 err = sock->recvMsgPtr( sock->fd, &sock->wmsg, &size, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
3219 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), (OSStatus) WSAGetLastError(), kUnknownErr );
3220
3221 // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
3222 //
3223 // There seems to be a bug in some network device drivers that involves calling WSARecvMsg() in
3224 // overlapped i/o mode. Although all the parameters to WSARecvMsg() are correct, it returns a
3225 // WSAEFAULT error code when there is no actual error. We have found experientially that falling
3226 // back to using WSARecvFrom() when this happens will work correctly.
3227
3228 if ( err == WSAEFAULT ) sock->recvMsgPtr = NULL;
3229 }
3230 else
3231 {
3232 DWORD flags = 0;
3233
3234 err = WSARecvFrom( sock->fd, &sock->wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sock->srcAddr, &sock->srcAddrLen, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
3235 err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
3236 }
3237
3238 // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
3239 //
3240 // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
3241 // send operation resulted in an ICMP "Port Unreachable" message."
3242 //
3243 // Because this is the case, we want to ignore this error and try again. Just in case
3244 // this is some kind of pathological condition, we'll break out of the retry loop
3245 // after 100 iterations
3246
3247 require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
3248 }
3249 while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
3250
3251 exit:
3252
3253 if ( err )
3254 {
3255 LogMsg( "WSARecvMsg failed (%d)\n", err );
3256 }
3257
3258 return err;
3259 }
3260
3261
3262 //===========================================================================================================================
3263 // UDPEndRecv
3264 //===========================================================================================================================
3265
3266 mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
3267 {
3268 UDPSocket * sock = NULL;
3269
3270 ( void ) flags;
3271
3272 require_action_quiet( err != WSA_OPERATION_ABORTED, exit, err = ( DWORD ) kUnknownErr );
3273 require_noerr( err, exit );
3274 sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
3275 require_action( sock != NULL, exit, err = ( DWORD ) kUnknownErr );
3276
3277 // If we've closed the socket, then we want to ignore
3278 // this read. The packet might have been queued before
3279 // the socket was closed.
3280
3281 if ( sock->fd != INVALID_SOCKET )
3282 {
3283 const mDNSInterfaceID iid = sock->ifd ? sock->ifd->interfaceInfo.InterfaceID : NULL;
3284 mDNSAddr srcAddr;
3285 mDNSIPPort srcPort;
3286 mDNSAddr dstAddr;
3287 mDNSIPPort dstPort;
3288 mDNSu8 * end;
3289
3290 // Translate the source of this packet into mDNS data types
3291
3292 SockAddrToMDNSAddr( (struct sockaddr *) &sock->srcAddr, &srcAddr, &srcPort );
3293
3294 // Initialize the destination of this packet. Just in case
3295 // we can't determine this info because we couldn't call
3296 // WSARecvMsg (recvMsgPtr)
3297
3298 dstAddr = sock->addr;
3299 dstPort = sock->port;
3300
3301 if ( sock->recvMsgPtr )
3302 {
3303 LPWSACMSGHDR header;
3304 LPWSACMSGHDR last = NULL;
3305 int count = 0;
3306
3307 // Parse the control information. Reject packets received on the wrong interface.
3308
3309 // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
3310 //
3311 // There seems to be an interaction between Bullguard and this next bit of code.
3312 // When a user's machine is running Bullguard, the control information that is
3313 // returned is corrupted, and the code would go into an infinite loop. We'll add
3314 // two bits of defensive coding here. The first will check that each pointer to
3315 // the LPWSACMSGHDR that is returned in the for loop is different than the last.
3316 // This fixes the problem with Bullguard. The second will break out of this loop
3317 // after 100 iterations, just in case the corruption isn't caught by the first
3318 // check.
3319
3320 for( header = WSA_CMSG_FIRSTHDR( &sock->wmsg ); header; header = WSA_CMSG_NXTHDR( &sock->wmsg, header ) )
3321 {
3322 if ( ( header != last ) && ( ++count < 100 ) )
3323 {
3324 last = header;
3325
3326 if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
3327 {
3328 IN_PKTINFO * ipv4PacketInfo;
3329
3330 ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
3331
3332 if ( sock->ifd != NULL )
3333 {
3334 require_action( ipv4PacketInfo->ipi_ifindex == sock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
3335 }
3336
3337 dstAddr.type = mDNSAddrType_IPv4;
3338 dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
3339 }
3340 else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
3341 {
3342 IN6_PKTINFO * ipv6PacketInfo;
3343
3344 ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
3345
3346 if ( sock->ifd != NULL )
3347 {
3348 require_action( ipv6PacketInfo->ipi6_ifindex == ( sock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
3349 }
3350
3351 dstAddr.type = mDNSAddrType_IPv6;
3352 dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
3353 }
3354 }
3355 else
3356 {
3357 static BOOL loggedMessage = FALSE;
3358
3359 if ( !loggedMessage )
3360 {
3361 LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
3362 loggedMessage = TRUE;
3363 }
3364
3365 break;
3366 }
3367 }
3368 }
3369
3370 // Dispatch the packet to mDNS.
3371
3372 dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
3373 dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", bytesTransferred );
3374 dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
3375 dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
3376
3377 if ( sock->ifd != NULL )
3378 {
3379 dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &sock->ifd->interfaceInfo.ip, sock->ifd->index );
3380 }
3381
3382 dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
3383
3384 end = ( (mDNSu8 *) &sock->packet ) + bytesTransferred;
3385
3386 // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
3387 //
3388 // There seems to be a bug in WinSock with respect to Alertable I/O. According
3389 // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
3390 // callbacks will only be invoked during the following calls (when the caller sets
3391 // the appropriate flag):
3392 //
3393 // - SleepEx
3394 // - WaitForSingleObjectEx
3395 // - WaitForMultipleObjectsEx
3396 // - SignalObjectAndWait
3397 // - MsgWaitForMultipleObjectsEx
3398 //
3399 // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
3400 // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
3401 // to directly call mDNSCoreReceive. Otherwise we queue the packet up and dispatch it later.
3402
3403 if ( gSocketEventsEnabled && !gSocketEvents.Head )
3404 {
3405 // Turn off socket events before calling mDNSCoreReceive().
3406 // This will prevent reentrancy problems.
3407 //
3408 // Don't forget to reenable socket events afterwards.
3409
3410 SetSocketEventsEnabled( sock->m, FALSE );
3411 mDNSCoreReceive( sock->m, &sock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
3412 SetSocketEventsEnabled( sock->m, TRUE );
3413 }
3414 else
3415 {
3416 UDPSocketEvent * event;
3417
3418 event = malloc( sizeof( UDPSocketEvent ) );
3419 require_action( event, exit, err = ( DWORD ) kNoMemoryErr );
3420 event->super.sock = sock;
3421 event->super.handler = &UDPSocketEventHandler;
3422 event->super.next = NULL;
3423 event->iid = iid;
3424 memcpy( &event->packet, &sock->packet, sizeof( event->packet ) );
3425 event->end = ( (mDNSu8 *) &event->packet ) + bytesTransferred;
3426 event->srcAddr = srcAddr;
3427 event->dstAddr = dstAddr;
3428 event->srcPort = srcPort;
3429 event->dstPort = dstPort;
3430
3431 AddToTail( &gSocketEvents, event );
3432 }
3433 }
3434
3435 exit:
3436
3437 // If the socket is still good, then start up another asynchronous read
3438
3439 if ( sock && ( sock->fd != INVALID_SOCKET ) )
3440 {
3441 err = UDPBeginRecv( sock );
3442 check_noerr( err );
3443 }
3444 }
3445
3446
3447 //===========================================================================================================================
3448 // InterfaceListDidChange
3449 //===========================================================================================================================
3450 void InterfaceListDidChange( mDNS * const inMDNS )
3451 {
3452 mStatus err;
3453
3454 dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
3455 check( inMDNS );
3456
3457 // Tear down the existing interfaces and set up new ones using the new IP info.
3458
3459 err = TearDownInterfaceList( inMDNS );
3460 check_noerr( err );
3461
3462 err = SetupInterfaceList( inMDNS );
3463 check_noerr( err );
3464
3465 err = uDNS_SetupDNSConfig( inMDNS );
3466 check_noerr( err );
3467
3468 // Inform clients of the change.
3469
3470 mDNS_ConfigChanged(inMDNS);
3471
3472 // Force mDNS to update.
3473
3474 mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
3475 }
3476
3477
3478 //===========================================================================================================================
3479 // ComputerDescriptionDidChange
3480 //===========================================================================================================================
3481 void ComputerDescriptionDidChange( mDNS * const inMDNS )
3482 {
3483 dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
3484 check( inMDNS );
3485
3486 // redo the names
3487 SetupNiceName( inMDNS );
3488 }
3489
3490
3491 //===========================================================================================================================
3492 // TCPIPConfigDidChange
3493 //===========================================================================================================================
3494 void TCPIPConfigDidChange( mDNS * const inMDNS )
3495 {
3496 mStatus err;
3497
3498 dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
3499 check( inMDNS );
3500
3501 err = uDNS_SetupDNSConfig( inMDNS );
3502 check_noerr( err );
3503 }
3504
3505
3506 //===========================================================================================================================
3507 // DynDNSConfigDidChange
3508 //===========================================================================================================================
3509 void DynDNSConfigDidChange( mDNS * const inMDNS )
3510 {
3511 mStatus err;
3512
3513 dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
3514 check( inMDNS );
3515
3516 SetDomainSecrets( inMDNS );
3517
3518 err = uDNS_SetupDNSConfig( inMDNS );
3519 check_noerr( err );
3520 }
3521
3522
3523 //===========================================================================================================================
3524 // FileSharingDidChange
3525 //===========================================================================================================================
3526 void FileSharingDidChange( mDNS * const inMDNS )
3527 {
3528 dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
3529 check( inMDNS );
3530
3531 CheckFileShares( inMDNS );
3532 }
3533
3534
3535 //===========================================================================================================================
3536 // FilewallDidChange
3537 //===========================================================================================================================
3538 void FirewallDidChange( mDNS * const inMDNS )
3539 {
3540 dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
3541 check( inMDNS );
3542
3543 CheckFileShares( inMDNS );
3544 }
3545
3546
3547 #if 0
3548 #pragma mark -
3549 #pragma mark == Utilities ==
3550 #endif
3551
3552 //===========================================================================================================================
3553 // getifaddrs
3554 //===========================================================================================================================
3555
3556 mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
3557 {
3558 int err;
3559
3560 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3561
3562 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3563 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3564
3565 if( !gIPHelperLibraryInstance )
3566 {
3567 gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
3568 if( gIPHelperLibraryInstance )
3569 {
3570 gGetAdaptersAddressesFunctionPtr =
3571 (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
3572 if( !gGetAdaptersAddressesFunctionPtr )
3573 {
3574 BOOL ok;
3575
3576 ok = FreeLibrary( gIPHelperLibraryInstance );
3577 check_translated_errno( ok, GetLastError(), kUnknownErr );
3578 gIPHelperLibraryInstance = NULL;
3579 }
3580 }
3581 }
3582
3583 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3584 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3585 // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
3586
3587 if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
3588 {
3589 err = getifaddrs_ipv4( outAddrs );
3590 require_noerr( err, exit );
3591 }
3592
3593 #else
3594
3595 err = getifaddrs_ipv4( outAddrs );
3596 require_noerr( err, exit );
3597
3598 #endif
3599
3600 exit:
3601 return( err );
3602 }
3603
3604 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3605 //===========================================================================================================================
3606 // getifaddrs_ipv6
3607 //===========================================================================================================================
3608
3609 mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
3610 {
3611 DWORD err;
3612 int i;
3613 DWORD flags;
3614 struct ifaddrs * head;
3615 struct ifaddrs ** next;
3616 IP_ADAPTER_ADDRESSES * iaaList;
3617 ULONG iaaListSize;
3618 IP_ADAPTER_ADDRESSES * iaa;
3619 size_t size;
3620 struct ifaddrs * ifa;
3621
3622 check( gGetAdaptersAddressesFunctionPtr );
3623
3624 head = NULL;
3625 next = &head;
3626 iaaList = NULL;
3627
3628 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3629 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3630 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3631
3632 flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
3633 i = 0;
3634 for( ;; )
3635 {
3636 iaaListSize = 0;
3637 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
3638 check( err == ERROR_BUFFER_OVERFLOW );
3639 check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
3640
3641 iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
3642 require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
3643
3644 err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
3645 if( err == ERROR_SUCCESS ) break;
3646
3647 free( iaaList );
3648 iaaList = NULL;
3649 ++i;
3650 require( i < 100, exit );
3651 dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
3652 }
3653
3654 for( iaa = iaaList; iaa; iaa = iaa->Next )
3655 {
3656 int addrIndex;
3657 IP_ADAPTER_UNICAST_ADDRESS * addr;
3658 DWORD ipv6IfIndex;
3659 IP_ADAPTER_PREFIX * firstPrefix;
3660
3661 if( iaa->IfIndex > 0xFFFFFF )
3662 {
3663 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
3664 }
3665 if( iaa->Ipv6IfIndex > 0xFF )
3666 {
3667 dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
3668 }
3669
3670 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3671 // following code to crash when iterating through the prefix list. This seems
3672 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3673 // This shouldn't happen according to Microsoft docs which states:
3674 //
3675 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3676 //
3677 // So the data structure seems to be corrupted when we return from
3678 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3679 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3680 // modify iaa to have the correct values.
3681
3682 if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
3683 {
3684 ipv6IfIndex = iaa->Ipv6IfIndex;
3685 firstPrefix = iaa->FirstPrefix;
3686 }
3687 else
3688 {
3689 ipv6IfIndex = 0;
3690 firstPrefix = NULL;
3691 }
3692
3693 // Skip pseudo and tunnel interfaces.
3694
3695 if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
3696 {
3697 continue;
3698 }
3699
3700 // Add each address as a separate interface to emulate the way getifaddrs works.
3701
3702 for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
3703 {
3704 int family;
3705 int prefixIndex;
3706 IP_ADAPTER_PREFIX * prefix;
3707 ULONG prefixLength;
3708 uint32_t ipv4Index;
3709 struct sockaddr_in ipv4Netmask;
3710
3711 family = addr->Address.lpSockaddr->sa_family;
3712 if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
3713
3714 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3715 // Seems as if the problem here is a buggy implementation of some network interface
3716 // driver. It is reporting that is has a link-local address when it is actually
3717 // disconnected. This was causing a problem in AddressToIndexAndMask.
3718 // The solution is to call AddressToIndexAndMask first, and if unable to lookup
3719 // the address, to ignore that address.
3720
3721 ipv4Index = 0;
3722 memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
3723
3724 if ( family == AF_INET )
3725 {
3726 err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
3727
3728 if ( err )
3729 {
3730 err = 0;
3731 continue;
3732 }
3733 }
3734
3735 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
3736 require_action( ifa, exit, err = WSAENOBUFS );
3737
3738 *next = ifa;
3739 next = &ifa->ifa_next;
3740
3741 // Get the name.
3742
3743 size = strlen( iaa->AdapterName ) + 1;
3744 ifa->ifa_name = (char *) malloc( size );
3745 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
3746 memcpy( ifa->ifa_name, iaa->AdapterName, size );
3747
3748 // Get interface flags.
3749
3750 ifa->ifa_flags = 0;
3751 if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
3752 if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
3753 else if ( IsPointToPoint( addr ) ) ifa->ifa_flags |= IFF_POINTTOPOINT;
3754 if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
3755
3756
3757 // <rdar://problem/4045657> Interface index being returned is 512
3758 //
3759 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
3760 // This code used to shift the IPv4 index up to ensure uniqueness between
3761 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
3762 // then see interface indexes passed back that don't correspond to anything
3763 // that is seen in Win32 APIs or command line tools like "route". As a relatively
3764 // small percentage of developers are actively using IPv6, it seems to
3765 // make sense to make our use of IPv4 as confusion free as possible.
3766 // So now, IPv6 interface indexes will be shifted up by a
3767 // constant value which will serve to uniquely identify them, and we will
3768 // leave IPv4 interface indexes unmodified.
3769
3770 switch( family )
3771 {
3772 case AF_INET: ifa->ifa_extra.index = iaa->IfIndex; break;
3773 case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase; break;
3774 default: break;
3775 }
3776
3777 // Get lease lifetime
3778
3779 if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
3780 {
3781 ifa->ifa_dhcpEnabled = TRUE;
3782 ifa->ifa_dhcpLeaseExpires = time( NULL ) + addr->ValidLifetime;
3783 }
3784 else
3785 {
3786 ifa->ifa_dhcpEnabled = FALSE;
3787 ifa->ifa_dhcpLeaseExpires = 0;
3788 }
3789
3790 if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
3791 {
3792 memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
3793 }
3794
3795 // Because we don't get notified of womp changes, we're going to just assume
3796 // that all wired interfaces have it enabled. Before we go to sleep, we'll check
3797 // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
3798 // accordingly
3799
3800 ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
3801
3802 // Get address.
3803
3804 switch( family )
3805 {
3806 case AF_INET:
3807 case AF_INET6:
3808 ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
3809 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
3810 memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
3811 break;
3812
3813 default:
3814 break;
3815 }
3816 check( ifa->ifa_addr );
3817
3818 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3819
3820 prefixLength = 0;
3821 for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
3822 {
3823 if( ( prefix->Address.lpSockaddr->sa_family == family ) && ( prefixIndex == addrIndex ) )
3824 {
3825 check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
3826 prefixLength = prefix->PrefixLength;
3827 break;
3828 }
3829 }
3830 switch( family )
3831 {
3832 case AF_INET:
3833 {
3834 struct sockaddr_in * sa4;
3835
3836 sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
3837 require_action( sa4, exit, err = WSAENOBUFS );
3838 sa4->sin_family = AF_INET;
3839 sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
3840
3841 dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
3842 ifa->ifa_netmask = (struct sockaddr *) sa4;
3843 break;
3844 }
3845
3846 case AF_INET6:
3847 {
3848 struct sockaddr_in6 * sa6;
3849 int len;
3850 int maskIndex;
3851 uint8_t maskByte;
3852
3853 require_action( prefixLength <= 128, exit, err = ERROR_INVALID_DATA );
3854
3855 sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
3856 require_action( sa6, exit, err = WSAENOBUFS );
3857 sa6->sin6_family = AF_INET6;
3858
3859 if( prefixLength == 0 )
3860 {
3861 dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__ );
3862 prefixLength = 128;
3863 }
3864 maskIndex = 0;
3865 for( len = (int) prefixLength; len > 0; len -= 8 )
3866 {
3867 if( len >= 8 ) maskByte = 0xFF;
3868 else maskByte = (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
3869 sa6->sin6_addr.s6_addr[ maskIndex++ ] = maskByte;
3870 }
3871 ifa->ifa_netmask = (struct sockaddr *) sa6;
3872 break;
3873 }
3874
3875 default:
3876 break;
3877 }
3878 }
3879 }
3880
3881 // Success!
3882
3883 if( outAddrs )
3884 {
3885 *outAddrs = head;
3886 head = NULL;
3887 }
3888 err = ERROR_SUCCESS;
3889
3890 exit:
3891 if( head )
3892 {
3893 freeifaddrs( head );
3894 }
3895 if( iaaList )
3896 {
3897 free( iaaList );
3898 }
3899 return( (int) err );
3900 }
3901
3902 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3903
3904 //===========================================================================================================================
3905 // getifaddrs_ipv4
3906 //===========================================================================================================================
3907
3908 mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
3909 {
3910 int err;
3911 SOCKET sock;
3912 DWORD size;
3913 DWORD actualSize;
3914 INTERFACE_INFO * buffer;
3915 INTERFACE_INFO * tempBuffer;
3916 INTERFACE_INFO * ifInfo;
3917 int n;
3918 int i;
3919 struct ifaddrs * head;
3920 struct ifaddrs ** next;
3921 struct ifaddrs * ifa;
3922
3923 sock = INVALID_SOCKET;
3924 buffer = NULL;
3925 head = NULL;
3926 next = &head;
3927
3928 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
3929 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
3930 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
3931
3932 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
3933 err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
3934 require_noerr( err, exit );
3935
3936 n = 0;
3937 size = 16 * sizeof( INTERFACE_INFO );
3938 for( ;; )
3939 {
3940 tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
3941 require_action( tempBuffer, exit, err = WSAENOBUFS );
3942 buffer = tempBuffer;
3943
3944 err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
3945 if( err == 0 )
3946 {
3947 break;
3948 }
3949
3950 ++n;
3951 require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
3952
3953 size += ( 16 * sizeof( INTERFACE_INFO ) );
3954 }
3955 check( actualSize <= size );
3956 check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
3957 n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
3958
3959 // Process the raw interface list and build a linked list of IPv4 interfaces.
3960
3961 for( i = 0; i < n; ++i )
3962 {
3963 uint32_t ifIndex;
3964 struct sockaddr_in netmask;
3965
3966 ifInfo = &buffer[ i ];
3967 if( ifInfo->iiAddress.Address.sa_family != AF_INET )
3968 {
3969 continue;
3970 }
3971
3972 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3973 // See comment in getifaddrs_ipv6
3974
3975 ifIndex = 0;
3976 memset( &netmask, 0, sizeof( netmask ) );
3977 err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
3978
3979 if ( err )
3980 {
3981 continue;
3982 }
3983
3984 ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
3985 require_action( ifa, exit, err = WSAENOBUFS );
3986
3987 *next = ifa;
3988 next = &ifa->ifa_next;
3989
3990 // Get the name.
3991
3992 ifa->ifa_name = (char *) malloc( 16 );
3993 require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
3994 sprintf( ifa->ifa_name, "%d", i + 1 );
3995
3996 // Get interface flags.
3997
3998 ifa->ifa_flags = (u_int) ifInfo->iiFlags;
3999
4000 // Get addresses.
4001
4002 if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
4003 {
4004 struct sockaddr_in * sa4;
4005
4006 sa4 = &ifInfo->iiAddress.AddressIn;
4007 ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
4008 require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
4009 memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
4010
4011 ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
4012 require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
4013
4014 // <rdar://problem/4076478> Service won't start on Win2K. The address
4015 // family field was not being initialized.
4016
4017 ifa->ifa_netmask->sa_family = AF_INET;
4018 ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
4019 ifa->ifa_extra.index = ifIndex;
4020 }
4021 else
4022 {
4023 // Emulate an interface index.
4024
4025 ifa->ifa_extra.index = (uint32_t)( i + 1 );
4026 }
4027 }
4028
4029 // Success!
4030
4031 if( outAddrs )
4032 {
4033 *outAddrs = head;
4034 head = NULL;
4035 }
4036 err = 0;
4037
4038 exit:
4039
4040 if( head )
4041 {
4042 freeifaddrs( head );
4043 }
4044 if( buffer )
4045 {
4046 free( buffer );
4047 }
4048 if( sock != INVALID_SOCKET )
4049 {
4050 closesocket( sock );
4051 }
4052 return( err );
4053 }
4054
4055 //===========================================================================================================================
4056 // freeifaddrs
4057 //===========================================================================================================================
4058
4059 mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
4060 {
4061 struct ifaddrs * p;
4062 struct ifaddrs * q;
4063
4064 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4065
4066 for( p = inIFAs; p; p = q )
4067 {
4068 q = p->ifa_next;
4069
4070 if( p->ifa_name )
4071 {
4072 free( p->ifa_name );
4073 p->ifa_name = NULL;
4074 }
4075 if( p->ifa_addr )
4076 {
4077 free( p->ifa_addr );
4078 p->ifa_addr = NULL;
4079 }
4080 if( p->ifa_netmask )
4081 {
4082 free( p->ifa_netmask );
4083 p->ifa_netmask = NULL;
4084 }
4085 if( p->ifa_broadaddr )
4086 {
4087 free( p->ifa_broadaddr );
4088 p->ifa_broadaddr = NULL;
4089 }
4090 if( p->ifa_dstaddr )
4091 {
4092 free( p->ifa_dstaddr );
4093 p->ifa_dstaddr = NULL;
4094 }
4095 if( p->ifa_data )
4096 {
4097 free( p->ifa_data );
4098 p->ifa_data = NULL;
4099 }
4100 free( p );
4101 }
4102 }
4103
4104
4105 //===========================================================================================================================
4106 // GetPrimaryInterface
4107 //===========================================================================================================================
4108
4109 mDNSlocal DWORD
4110 GetPrimaryInterface()
4111 {
4112 PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
4113 DWORD dwSize = 0;
4114 BOOL bOrder = FALSE;
4115 OSStatus err;
4116 DWORD index = 0;
4117 DWORD metric = 0;
4118 unsigned long int i;
4119
4120 // Find out how big our buffer needs to be.
4121
4122 err = GetIpForwardTable(NULL, &dwSize, bOrder);
4123 require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
4124
4125 // Allocate the memory for the table
4126
4127 pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
4128 require_action( pIpForwardTable, exit, err = kNoMemoryErr );
4129
4130 // Now get the table.
4131
4132 err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
4133 require_noerr( err, exit );
4134
4135
4136 // Search for the row in the table we want.
4137
4138 for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
4139 {
4140 // Look for a default route
4141
4142 if ( pIpForwardTable->table[i].dwForwardDest == 0 )
4143 {
4144 if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
4145 {
4146 continue;
4147 }
4148
4149 index = pIpForwardTable->table[i].dwForwardIfIndex;
4150 metric = pIpForwardTable->table[i].dwForwardMetric1;
4151 }
4152 }
4153
4154 exit:
4155
4156 if ( pIpForwardTable != NULL )
4157 {
4158 free( pIpForwardTable );
4159 }
4160
4161 return index;
4162 }
4163
4164
4165 //===========================================================================================================================
4166 // AddressToIndexAndMask
4167 //===========================================================================================================================
4168
4169 mDNSlocal mStatus
4170 AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask )
4171 {
4172 // Before calling AddIPAddress we use GetIpAddrTable to get
4173 // an adapter to which we can add the IP.
4174
4175 PMIB_IPADDRTABLE pIPAddrTable = NULL;
4176 DWORD dwSize = 0;
4177 mStatus err = mStatus_UnknownErr;
4178 DWORD i;
4179
4180 // For now, this is only for IPv4 addresses. That is why we can safely cast
4181 // addr's to sockaddr_in.
4182
4183 require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
4184
4185 // Make an initial call to GetIpAddrTable to get the
4186 // necessary size into the dwSize variable
4187
4188 for ( i = 0; i < 100; i++ )
4189 {
4190 err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
4191
4192 if ( err != ERROR_INSUFFICIENT_BUFFER )
4193 {
4194 break;
4195 }
4196
4197 pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
4198 require_action( pIPAddrTable, exit, err = WSAENOBUFS );
4199 }
4200
4201 require_noerr( err, exit );
4202 err = mStatus_UnknownErr;
4203
4204 for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
4205 {
4206 if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
4207 {
4208 *ifIndex = pIPAddrTable->table[i].dwIndex;
4209 ( ( struct sockaddr_in*) mask )->sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
4210 err = mStatus_NoError;
4211 break;
4212 }
4213 }
4214
4215 exit:
4216
4217 if ( pIPAddrTable )
4218 {
4219 free( pIPAddrTable );
4220 }
4221
4222 return err;
4223 }
4224
4225
4226 //===========================================================================================================================
4227 // CanReceiveUnicast
4228 //===========================================================================================================================
4229
4230 mDNSlocal mDNSBool CanReceiveUnicast( void )
4231 {
4232 mDNSBool ok;
4233 SocketRef sock;
4234 struct sockaddr_in addr;
4235
4236 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4237
4238 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
4239 check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
4240 ok = IsValidSocket( sock );
4241 if( ok )
4242 {
4243 mDNSPlatformMemZero( &addr, sizeof( addr ) );
4244 addr.sin_family = AF_INET;
4245 addr.sin_port = MulticastDNSPort.NotAnInteger;
4246 addr.sin_addr.s_addr = htonl( INADDR_ANY );
4247
4248 ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
4249 close_compat( sock );
4250 }
4251
4252 dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
4253 return( ok );
4254 }
4255
4256
4257 //===========================================================================================================================
4258 // IsPointToPoint
4259 //===========================================================================================================================
4260
4261 mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
4262 {
4263 struct ifaddrs * addrs = NULL;
4264 struct ifaddrs * p = NULL;
4265 OSStatus err;
4266 mDNSBool ret = mDNSfalse;
4267
4268 // For now, only works for IPv4 interfaces
4269
4270 if ( addr->Address.lpSockaddr->sa_family == AF_INET )
4271 {
4272 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4273
4274 err = getifaddrs_ipv4( &addrs );
4275 require_noerr( err, exit );
4276
4277 for ( p = addrs; p; p = p->ifa_next )
4278 {
4279 if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
4280 ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
4281 {
4282 ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
4283 break;
4284 }
4285 }
4286 }
4287
4288 exit:
4289
4290 if ( addrs )
4291 {
4292 freeifaddrs( addrs );
4293 }
4294
4295 return ret;
4296 }
4297
4298
4299 //===========================================================================================================================
4300 // GetWindowsVersionString
4301 //===========================================================================================================================
4302
4303 mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
4304 {
4305 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4306 #define VER_PLATFORM_WIN32_CE 3
4307 #endif
4308
4309 OSStatus err;
4310 OSVERSIONINFO osInfo;
4311 BOOL ok;
4312 const char * versionString;
4313 DWORD platformID;
4314 DWORD majorVersion;
4315 DWORD minorVersion;
4316 DWORD buildNumber;
4317
4318 versionString = "unknown Windows version";
4319
4320 osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
4321 ok = GetVersionEx( &osInfo );
4322 err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
4323 require_noerr( err, exit );
4324
4325 platformID = osInfo.dwPlatformId;
4326 majorVersion = osInfo.dwMajorVersion;
4327 minorVersion = osInfo.dwMinorVersion;
4328 buildNumber = osInfo.dwBuildNumber & 0xFFFF;
4329
4330 if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
4331 {
4332 if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
4333 {
4334 versionString = "Windows 95";
4335 }
4336 else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
4337 {
4338 versionString = "Windows 95 SP1";
4339 }
4340 else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
4341 {
4342 versionString = "Windows 95 OSR2";
4343 }
4344 else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
4345 {
4346 versionString = "Windows 98";
4347 }
4348 else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
4349 {
4350 versionString = "Windows 98 SP1";
4351 }
4352 else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
4353 {
4354 versionString = "Windows 98 SE";
4355 }
4356 else if( minorVersion == 90 )
4357 {
4358 versionString = "Windows ME";
4359 }
4360 }
4361 else if( platformID == VER_PLATFORM_WIN32_NT )
4362 {
4363 if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
4364 {
4365 versionString = "Windows NT 3.51";
4366 }
4367 else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
4368 {
4369 versionString = "Windows NT 4";
4370 }
4371 else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
4372 {
4373 versionString = "Windows 2000";
4374 }
4375 else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
4376 {
4377 versionString = "Windows XP";
4378 }
4379 else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
4380 {
4381 versionString = "Windows Server 2003";
4382 }
4383 }
4384 else if( platformID == VER_PLATFORM_WIN32_CE )
4385 {
4386 versionString = "Windows CE";
4387 }
4388
4389 exit:
4390 if( inBuffer && ( inBufferSize > 0 ) )
4391 {
4392 inBufferSize -= 1;
4393 strncpy( inBuffer, versionString, inBufferSize );
4394 inBuffer[ inBufferSize ] = '\0';
4395 }
4396 return( err );
4397 }
4398
4399
4400 //===========================================================================================================================
4401 // RegQueryString
4402 //===========================================================================================================================
4403
4404 mDNSlocal mStatus
4405 RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
4406 {
4407 DWORD type;
4408 int i;
4409 mStatus err;
4410
4411 *stringLen = MAX_ESCAPED_DOMAIN_NAME;
4412 *string = NULL;
4413 i = 0;
4414
4415 do
4416 {
4417 if ( *string )
4418 {
4419 free( *string );
4420 }
4421
4422 *string = (char*) malloc( *stringLen );
4423 require_action( *string, exit, err = mStatus_NoMemoryErr );
4424
4425 err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
4426
4427 i++;
4428 }
4429 while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
4430
4431 require_noerr_quiet( err, exit );
4432
4433 if ( enabled )
4434 {
4435 DWORD dwSize = sizeof( DWORD );
4436
4437 err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
4438 check_noerr( err );
4439
4440 err = kNoErr;
4441 }
4442
4443 exit:
4444
4445 return err;
4446 }
4447
4448
4449 //===========================================================================================================================
4450 // StringToAddress
4451 //===========================================================================================================================
4452
4453 mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
4454 {
4455 struct sockaddr_in6 sa6;
4456 struct sockaddr_in sa4;
4457 INT dwSize;
4458 mStatus err;
4459
4460 sa6.sin6_family = AF_INET6;
4461 dwSize = sizeof( sa6 );
4462
4463 err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
4464
4465 if ( err == mStatus_NoError )
4466 {
4467 err = SetupAddr( ip, (struct sockaddr*) &sa6 );
4468 require_noerr( err, exit );
4469 }
4470 else
4471 {
4472 sa4.sin_family = AF_INET;
4473 dwSize = sizeof( sa4 );
4474
4475 err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
4476 err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
4477 require_noerr( err, exit );
4478
4479 err = SetupAddr( ip, (struct sockaddr*) &sa4 );
4480 require_noerr( err, exit );
4481 }
4482
4483 exit:
4484
4485 return err;
4486 }
4487
4488
4489 //===========================================================================================================================
4490 // myGetIfAddrs
4491 //===========================================================================================================================
4492
4493 mDNSlocal struct ifaddrs*
4494 myGetIfAddrs(int refresh)
4495 {
4496 static struct ifaddrs *ifa = NULL;
4497
4498 if (refresh && ifa)
4499 {
4500 freeifaddrs(ifa);
4501 ifa = NULL;
4502 }
4503
4504 if (ifa == NULL)
4505 {
4506 getifaddrs(&ifa);
4507 }
4508
4509 return ifa;
4510 }
4511
4512
4513 //===========================================================================================================================
4514 // TCHARtoUTF8
4515 //===========================================================================================================================
4516
4517 mDNSlocal OSStatus
4518 TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
4519 {
4520 #if( defined( UNICODE ) || defined( _UNICODE ) )
4521 OSStatus err;
4522 int len;
4523
4524 len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4525 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4526 require_noerr( err, exit );
4527
4528 exit:
4529 return( err );
4530 #else
4531 return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
4532 #endif
4533 }
4534
4535
4536 //===========================================================================================================================
4537 // WindowsLatin1toUTF8
4538 //===========================================================================================================================
4539
4540 mDNSlocal OSStatus
4541 WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
4542 {
4543 OSStatus err;
4544 WCHAR * utf16;
4545 int len;
4546
4547 utf16 = NULL;
4548
4549 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4550
4551 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
4552 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4553 require_noerr( err, exit );
4554
4555 utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
4556 require_action( utf16, exit, err = kNoMemoryErr );
4557
4558 len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
4559 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4560 require_noerr( err, exit );
4561
4562 // Now convert the temporary UTF-16 to UTF-8.
4563
4564 len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
4565 err = translate_errno( len > 0, errno_compat(), kUnknownErr );
4566 require_noerr( err, exit );
4567
4568 exit:
4569 if( utf16 ) free( utf16 );
4570 return( err );
4571 }
4572
4573
4574 //===========================================================================================================================
4575 // TCPFreeSocket
4576 //===========================================================================================================================
4577
4578 mDNSlocal void CALLBACK
4579 TCPFreeSocket( TCPSocket *sock )
4580 {
4581 check( sock );
4582
4583 dlog( kDebugLevelChatty, DEBUG_NAME "freeing TCPSocket 0x%x:%d\n", sock, sock->fd );
4584
4585 if ( sock->connectEvent )
4586 {
4587 CloseHandle( sock->connectEvent );
4588 sock->connectEvent = NULL;
4589 }
4590
4591 if ( sock->fd != INVALID_SOCKET )
4592 {
4593 closesocket( sock->fd );
4594 sock->fd = INVALID_SOCKET;
4595 }
4596
4597 free( sock );
4598 }
4599
4600
4601 //===========================================================================================================================
4602 // UDPFreeSocket
4603 //===========================================================================================================================
4604
4605 mDNSlocal void CALLBACK
4606 UDPFreeSocket( UDPSocket * sock )
4607 {
4608 check( sock );
4609
4610 dlog( kDebugLevelChatty, DEBUG_NAME "freeing UDPSocket %d (%##a)\n", sock->fd, &sock->addr );
4611
4612 if ( sock->fd != INVALID_SOCKET )
4613 {
4614 closesocket( sock->fd );
4615 sock->fd = INVALID_SOCKET;
4616 }
4617
4618 free( sock );
4619 }
4620
4621 //===========================================================================================================================
4622 // SetupAddr
4623 //===========================================================================================================================
4624
4625 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
4626 {
4627 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
4628
4629 if (sa->sa_family == AF_INET)
4630 {
4631 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
4632 ip->type = mDNSAddrType_IPv4;
4633 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
4634 return(mStatus_NoError);
4635 }
4636
4637 if (sa->sa_family == AF_INET6)
4638 {
4639 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
4640 ip->type = mDNSAddrType_IPv6;
4641 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
4642 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
4643 return(mStatus_NoError);
4644 }
4645
4646 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
4647 return(mStatus_Invalid);
4648 }
4649
4650
4651 mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
4652 {
4653 LPSTR name = NULL;
4654 DWORD dwSize;
4655 DWORD enabled;
4656 HKEY key = NULL;
4657 OSStatus err;
4658
4659 check( fqdn );
4660
4661 // Initialize
4662
4663 fqdn->c[0] = '\0';
4664
4665 // Get info from Bonjour registry key
4666
4667 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
4668 require_noerr( err, exit );
4669
4670 err = RegQueryString( key, "", &name, &dwSize, &enabled );
4671 if ( !err && ( name[0] != '\0' ) && enabled )
4672 {
4673 if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
4674 {
4675 dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
4676 }
4677 }
4678
4679 exit:
4680
4681 if ( key )
4682 {
4683 RegCloseKey( key );
4684 key = NULL;
4685 }
4686
4687 if ( name )
4688 {
4689 free( name );
4690 name = NULL;
4691 }
4692 }
4693
4694
4695 #ifdef UNICODE
4696 mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
4697 #else
4698 mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
4699 #endif
4700 {
4701 char subKeyName[kRegistryMaxKeyLength + 1];
4702 DWORD cSubKeys = 0;
4703 DWORD cbMaxSubKey;
4704 DWORD cchMaxClass;
4705 DWORD dwSize;
4706 HKEY key = NULL;
4707 HKEY subKey = NULL;
4708 domainname dname;
4709 DWORD i;
4710 OSStatus err;
4711
4712 check( domains );
4713
4714 // Initialize
4715
4716 *domains = NULL;
4717
4718 err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
4719 require_noerr( err, exit );
4720
4721 // Get information about this node
4722
4723 err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
4724 require_noerr( err, exit );
4725
4726 for ( i = 0; i < cSubKeys; i++)
4727 {
4728 DWORD enabled;
4729
4730 dwSize = kRegistryMaxKeyLength;
4731
4732 err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
4733
4734 if ( !err )
4735 {
4736 err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
4737 require_noerr( err, exit );
4738
4739 dwSize = sizeof( DWORD );
4740 err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
4741
4742 if ( !err && ( subKeyName[0] != '\0' ) && enabled )
4743 {
4744 if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
4745 {
4746 dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
4747 }
4748 else
4749 {
4750 DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
4751 require_action( domain, exit, err = mStatus_NoMemoryErr );
4752
4753 AssignDomainName(&domain->name, &dname);
4754 domain->next = *domains;
4755
4756 *domains = domain;
4757 }
4758 }
4759
4760 RegCloseKey( subKey );
4761 subKey = NULL;
4762 }
4763 }
4764
4765 exit:
4766
4767 if ( subKey )
4768 {
4769 RegCloseKey( subKey );
4770 }
4771
4772 if ( key )
4773 {
4774 RegCloseKey( key );
4775 }
4776 }
4777
4778
4779 mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
4780 {
4781 char domainUTF8[ 256 ];
4782 DomainAuthInfo *foundInList;
4783 DomainAuthInfo *ptr;
4784 char outDomain[ 256 ];
4785 char outKey[ 256 ];
4786 char outSecret[ 256 ];
4787 OSStatus err;
4788
4789 ConvertDomainNameToCString( inDomain, domainUTF8 );
4790
4791 // If we're able to find a secret for this domain
4792
4793 if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
4794 {
4795 domainname domain;
4796 domainname key;
4797
4798 // Tell the core about this secret
4799
4800 MakeDomainNameFromDNSNameString( &domain, outDomain );
4801 MakeDomainNameFromDNSNameString( &key, outKey );
4802
4803 for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
4804 if (SameDomainName(&foundInList->domain, &domain ) ) break;
4805
4806 ptr = foundInList;
4807
4808 if (!ptr)
4809 {
4810 ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
4811 require_action( ptr, exit, err = mStatus_NoMemoryErr );
4812 }
4813
4814 err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, mDNSfalse );
4815 require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
4816
4817 debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
4818 }
4819
4820 exit:
4821
4822 return;
4823 }
4824
4825
4826 mDNSlocal VOID CALLBACK
4827 CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
4828 {
4829 mDNS * const m = ( mDNS * const ) arg;
4830
4831 ( void ) dwTimerLowValue;
4832 ( void ) dwTimerHighValue;
4833
4834 CheckFileShares( m );
4835 }
4836
4837
4838 mDNSlocal unsigned __stdcall
4839 SMBRegistrationThread( void * arg )
4840 {
4841 mDNS * const m = ( mDNS * const ) arg;
4842 DNSServiceRef sref = NULL;
4843 HANDLE handles[ 3 ];
4844 mDNSu8 txtBuf[ 256 ];
4845 mDNSu8 * txtPtr;
4846 size_t keyLen;
4847 size_t valLen;
4848 mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
4849 DNSServiceErrorType err;
4850
4851 DEBUG_UNUSED( arg );
4852
4853 handles[ 0 ] = gSMBThreadStopEvent;
4854 handles[ 1 ] = gSMBThreadRegisterEvent;
4855 handles[ 2 ] = gSMBThreadDeregisterEvent;
4856
4857 memset( txtBuf, 0, sizeof( txtBuf ) );
4858 txtPtr = txtBuf;
4859 keyLen = strlen( "netbios=" );
4860 valLen = strlen( m->p->nbname );
4861 require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
4862 *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
4863 memcpy( txtPtr, "netbios=", keyLen );
4864 txtPtr += keyLen;
4865 if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
4866 keyLen = strlen( "domain=" );
4867 valLen = strlen( m->p->nbdomain );
4868 require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
4869 *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
4870 memcpy( txtPtr, "domain=", keyLen );
4871 txtPtr += keyLen;
4872 if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
4873
4874 for ( ;; )
4875 {
4876 DWORD ret;
4877
4878 ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
4879
4880 if ( ret != WAIT_FAILED )
4881 {
4882 if ( ret == kSMBStopEvent )
4883 {
4884 break;
4885 }
4886 else if ( ret == kSMBRegisterEvent )
4887 {
4888 err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
4889
4890 if ( err )
4891 {
4892 LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
4893 sref = NULL;
4894 break;
4895 }
4896 }
4897 else if ( ret == kSMBDeregisterEvent )
4898 {
4899 if ( sref )
4900 {
4901 gDNSServiceRefDeallocate( sref );
4902 sref = NULL;
4903 }
4904 }
4905 }
4906 else
4907 {
4908 LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
4909 break;
4910 }
4911 }
4912
4913 exit:
4914
4915 if ( sref != NULL )
4916 {
4917 gDNSServiceRefDeallocate( sref );
4918 sref = NULL;
4919 }
4920
4921 SetEvent( gSMBThreadQuitEvent );
4922 _endthreadex( 0 );
4923 return 0;
4924 }
4925
4926
4927 mDNSlocal void
4928 CheckFileShares( mDNS * const m )
4929 {
4930 PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL;
4931 DWORD entriesRead = 0;
4932 DWORD totalEntries = 0;
4933 DWORD resume = 0;
4934 mDNSBool advertise = mDNSfalse;
4935 mDNSBool fileSharing = mDNSfalse;
4936 mDNSBool printSharing = mDNSfalse;
4937 HKEY key = NULL;
4938 BOOL retry = FALSE;
4939 NET_API_STATUS res;
4940 mStatus err;
4941
4942 check( m );
4943
4944 // Only do this if we're not shutting down
4945
4946 require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
4947
4948 err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
4949
4950 if ( !err )
4951 {
4952 DWORD dwSize = sizeof( DWORD );
4953 RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
4954 }
4955
4956 if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
4957 {
4958 dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
4959
4960 res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
4961
4962 if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
4963 {
4964 PSHARE_INFO_1 p = bufPtr;
4965 DWORD i;
4966
4967 for( i = 0; i < entriesRead; i++ )
4968 {
4969 // We are only interested if the user is sharing anything other
4970 // than the built-in "print$" source
4971
4972 if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
4973 {
4974 fileSharing = mDNStrue;
4975 }
4976 else if ( p->shi1_type == STYPE_PRINTQ )
4977 {
4978 printSharing = mDNStrue;
4979 }
4980
4981 p++;
4982 }
4983
4984 NetApiBufferFree( bufPtr );
4985 bufPtr = NULL;
4986 retry = FALSE;
4987 }
4988 else if ( res == NERR_ServerNotStarted )
4989 {
4990 retry = TRUE;
4991 }
4992 }
4993
4994 if ( retry )
4995 {
4996 __int64 qwTimeout;
4997 LARGE_INTEGER liTimeout;
4998
4999 qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
5000 liTimeout.LowPart = ( DWORD )( qwTimeout & 0xFFFFFFFF );
5001 liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
5002
5003 SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
5004 }
5005
5006 if ( !m->p->smbFileSharing && fileSharing )
5007 {
5008 if ( !gSMBThread )
5009 {
5010 if ( !gDNSSDLibrary )
5011 {
5012 gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
5013 require_action( gDNSSDLibrary, exit, err = GetLastError() );
5014 }
5015
5016 if ( !gDNSServiceRegister )
5017 {
5018 gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
5019 require_action( gDNSServiceRegister, exit, err = GetLastError() );
5020 }
5021
5022 if ( !gDNSServiceRefDeallocate )
5023 {
5024 gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
5025 require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
5026 }
5027
5028 if ( !gSMBThreadRegisterEvent )
5029 {
5030 gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5031 require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
5032 }
5033
5034 if ( !gSMBThreadDeregisterEvent )
5035 {
5036 gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5037 require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
5038 }
5039
5040 if ( !gSMBThreadStopEvent )
5041 {
5042 gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5043 require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
5044 }
5045
5046 if ( !gSMBThreadQuitEvent )
5047 {
5048 gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
5049 require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
5050 }
5051
5052 gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
5053 require_action( gSMBThread != NULL, exit, err = GetLastError() );
5054 }
5055
5056 SetEvent( gSMBThreadRegisterEvent );
5057
5058 m->p->smbFileSharing = mDNStrue;
5059 }
5060 else if ( m->p->smbFileSharing && !fileSharing )
5061 {
5062 dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
5063
5064 if ( gSMBThreadDeregisterEvent != NULL )
5065 {
5066 SetEvent( gSMBThreadDeregisterEvent );
5067 }
5068
5069 m->p->smbFileSharing = mDNSfalse;
5070 }
5071
5072 exit:
5073
5074 if ( key )
5075 {
5076 RegCloseKey( key );
5077 }
5078 }
5079
5080
5081 BOOL
5082 IsWOMPEnabled( mDNS * const m )
5083 {
5084 BOOL enabled;
5085
5086 mDNSInterfaceData * ifd;
5087
5088 enabled = FALSE;
5089
5090 for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
5091 {
5092 if ( IsWOMPEnabledForAdapter( ifd->name ) )
5093 {
5094 enabled = TRUE;
5095 break;
5096 }
5097 }
5098
5099 return enabled;
5100 }
5101
5102
5103 mDNSlocal mDNSu8
5104 IsWOMPEnabledForAdapter( const char * adapterName )
5105 {
5106 char fileName[80];
5107 NDIS_OID oid;
5108 DWORD count;
5109 HANDLE handle = INVALID_HANDLE_VALUE;
5110 NDIS_PNP_CAPABILITIES * pNPC = NULL;
5111 int err;
5112 mDNSu8 ok = TRUE;
5113
5114 require_action( adapterName != NULL, exit, ok = FALSE );
5115
5116 dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
5117
5118 // Construct a device name to pass to CreateFile
5119
5120 strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
5121 strcat_s( fileName, sizeof( fileName ), adapterName );
5122 handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
5123 require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
5124
5125 // We successfully opened the driver, format the IOCTL to pass the driver.
5126
5127 oid = OID_PNP_CAPABILITIES;
5128 pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
5129 require_action( pNPC != NULL, exit, ok = FALSE );
5130 ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
5131 err = translate_errno( ok, GetLastError(), kUnknownErr );
5132 require_action( !err, exit, ok = FALSE );
5133 ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
5134
5135 exit:
5136
5137 if ( pNPC != NULL )
5138 {
5139 free( pNPC );
5140 }
5141
5142 if ( handle != INVALID_HANDLE_VALUE )
5143 {
5144 CloseHandle( handle );
5145 }
5146
5147 dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
5148
5149 return ( mDNSu8 ) ok;
5150 }
5151
5152
5153 void
5154 SetSocketEventsEnabled( mDNS * const inMDNS, BOOL enabled )
5155 {
5156 DEBUG_UNUSED( inMDNS );
5157
5158 if ( enabled )
5159 {
5160 int numEvents = 0;
5161
5162 check( !gSocketEventsEnabled );
5163
5164 // If we're enabled, then drain the queue right now.
5165
5166 while ( gSocketEvents.Head && ( numEvents < 100 ) )
5167 {
5168 SocketEvent * event = ( SocketEvent* ) gSocketEvents.Head;
5169 RemoveFromList( &gSocketEvents, event );
5170 check( event->handler );
5171
5172 // At this point we're going to call our event handler, and
5173 // gSocketEventsEnabled should be FALSE. So if the callback
5174 // does anything that causes alertable I/O callbacks to be
5175 // invoked, we'll queue the packets instead of invoking core
5176 // callbacks reentrantly.
5177 //
5178 // One potential problem here is a pathological case of
5179 // continuing to queue packets during invocation of
5180 // the callback, and thus never exiting out of this loop.
5181 // This is entirely theoretical as we've never seen it happen,
5182 // but just to be overly cautious, we'll only process a maximum of
5183 // 100 events here just in case.
5184
5185 event->handler( inMDNS, event );
5186 free( event );
5187
5188 numEvents++;
5189 }
5190 }
5191
5192 gSocketEventsEnabled = enabled;
5193 }
5194
5195
5196 mDNSlocal void
5197 FreeSocketEventsForSocket( mDNS * const inMDNS, void * sock )
5198 {
5199 SocketEvent * event;
5200
5201 DEBUG_UNUSED( inMDNS );
5202
5203 for ( event = ( SocketEvent* ) gSocketEvents.Head; event; event = event->next )
5204 {
5205 if ( event->sock == sock )
5206 {
5207 RemoveFromList( &gSocketEvents, event );
5208 free( event );
5209 break;
5210 }
5211 }
5212 }
5213
5214
5215 mDNSlocal void
5216 FreeSocketEvents( mDNS * const inMDNS )
5217 {
5218 DEBUG_UNUSED( inMDNS );
5219
5220 while ( gSocketEvents.Head )
5221 {
5222 SocketEvent * event = ( SocketEvent* ) gSocketEvents.Head;
5223 RemoveFromList( &gSocketEvents, event );
5224 free( event );
5225 }
5226 }
5227
5228
5229 mDNSlocal void
5230 TCPSocketEventHandler( mDNS * const inMDNS, void * v )
5231 {
5232 TCPSocketEvent * event = ( TCPSocketEvent* ) v;
5233 TCPSocket * sock = ( TCPSocket* ) event->super.sock;
5234
5235 DEBUG_UNUSED( inMDNS );
5236 check( sock );
5237
5238 sock->lastError = event->error;
5239
5240 if ( !event->error )
5241 {
5242 if ( event->bytesTransferred )
5243 {
5244 memcpy( sock->buf, event->buf, event->bytesTransferred );
5245 sock->bptr = sock->buf;
5246 sock->eptr = sock->buf + event->bytesTransferred;
5247 }
5248 else
5249 {
5250 sock->closed = TRUE;
5251 }
5252 }
5253
5254 if ( sock->readEventHandler != NULL )
5255 {
5256 sock->readEventHandler( sock );
5257 }
5258 }
5259
5260
5261 mDNSlocal void
5262 UDPSocketEventHandler( mDNS * const inMDNS, void * v )
5263 {
5264 UDPSocketEvent * event = ( UDPSocketEvent* ) v;
5265
5266 mDNSCoreReceive( inMDNS, &event->packet, event->end, &event->srcAddr, event->srcPort, &event->dstAddr, event->dstPort, event->iid );
5267 }