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