1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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).
36 #include "CommonServices.h"
37 #include "DebugServices.h"
49 #include <ntddndis.h> // This defines the IOCTL constants.
51 #include "mDNSEmbeddedAPI.h"
52 #include "GenLinkedList.h"
53 #include "DNSCommon.h"
54 #include "mDNSWin32.h"
59 #pragma mark == Constants ==
62 //===========================================================================================================================
64 //===========================================================================================================================
66 #define DEBUG_NAME "[mDNSWin32] "
68 #define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
69 #define MDNS_WINDOWS_ENABLE_IPV4 1
70 #define MDNS_WINDOWS_ENABLE_IPV6 1
71 #define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
72 #define MDNS_SET_HINFO_STRINGS 0
74 #define kMDNSDefaultName "My Computer"
76 #define kWinSockMajorMin 2
77 #define kWinSockMinorMin 2
79 #define kRegistryMaxKeyLength 255
80 #define kRegistryMaxValueName 16383
82 static GUID kWSARecvMsgGUID
= WSAID_WSARECVMSG
;
84 #define kIPv6IfIndexBase (10000000L)
85 #define SMBPortAsNumber 445
86 #define DEVICE_PREFIX "\\\\.\\"
89 #pragma mark == Prototypes ==
92 //===========================================================================================================================
94 //===========================================================================================================================
96 mDNSlocal mStatus
SetupNiceName( mDNS
* const inMDNS
);
97 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
);
98 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
);
99 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
);
100 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
);
101 mDNSlocal
void CALLBACK
FreeInterface( mDNSInterfaceData
*inIFD
);
102 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
);
103 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
);
104 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
);
105 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
);
106 mDNSlocal
void freeifaddrs( struct ifaddrs
*inAddrs
);
110 // Platform Accessors
116 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
117 struct mDNSPlatformInterfaceInfo
124 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
125 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
130 #define kUnicastWakeupNumTries ( 1 )
131 #define kUnicastWakeupSleepBetweenTries ( 0 )
132 #define kMulticastWakeupNumTries ( 18 )
133 #define kMulticastWakeupSleepBetweenTries ( 100 )
135 typedef struct MulticastWakeupStruct
138 struct sockaddr_in addr
;
140 unsigned char data
[ 102 ];
144 } MulticastWakeupStruct
;
149 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
150 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
);
153 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
);
156 mDNSlocal DWORD
GetPrimaryInterface();
157 mDNSlocal mStatus
AddressToIndexAndMask( struct sockaddr
* address
, uint32_t * index
, struct sockaddr
* mask
);
158 mDNSlocal mDNSBool
CanReceiveUnicast( void );
159 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
);
161 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
);
162 mDNSlocal mStatus
RegQueryString( HKEY key
, LPCSTR param
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
);
163 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
);
164 mDNSlocal OSStatus
TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
);
165 mDNSlocal OSStatus
WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
);
166 mDNSlocal
void CALLBACK
TCPSocketNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
);
167 mDNSlocal
void TCPCloseSocket( TCPSocket
* socket
);
168 mDNSlocal
void CALLBACK
UDPSocketNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
);
169 mDNSlocal
void UDPCloseSocket( UDPSocket
* sock
);
170 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
);
171 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
);
173 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
);
175 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCSTR lpSubKey
);
177 mDNSlocal
void SetDomainSecrets( mDNS
* const inMDNS
);
178 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
);
179 mDNSlocal VOID CALLBACK
CheckFileSharesProc( LPVOID arg
, DWORD dwTimerLowValue
, DWORD dwTimerHighValue
);
180 mDNSlocal
void CheckFileShares( mDNS
* const inMDNS
);
181 mDNSlocal
void SMBCallback(mDNS
*const m
, ServiceRecordSet
*const srs
, mStatus result
);
182 mDNSlocal mDNSu8
IsWOMPEnabledForAdapter( const char * adapterName
);
183 mDNSlocal
void SendWakeupPacket( mDNS
* const inMDNS
, LPSOCKADDR addr
, INT addrlen
, const char * buf
, INT buflen
, INT numTries
, INT msecSleep
);
184 mDNSlocal
void _cdecl
SendMulticastWakeupPacket( void *arg
);
191 #pragma mark == Globals ==
194 //===========================================================================================================================
196 //===========================================================================================================================
198 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
199 mDNSs32 mDNSPlatformOneSecond
= 0;
200 mDNSlocal UDPSocket
* gUDPSockets
= NULL
;
201 mDNSlocal
int gUDPNumSockets
= 0;
202 mDNSlocal BOOL gEnableIPv6
= TRUE
;
204 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
207 ( WINAPI
* GetAdaptersAddressesFunctionPtr
)(
211 PIP_ADAPTER_ADDRESSES inAdapter
,
212 PULONG outBufferSize
);
214 mDNSlocal HMODULE gIPHelperLibraryInstance
= NULL
;
215 mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr
= NULL
;
221 typedef ULONG_PTR HCRYPTPROV
; // WinCrypt.h, line 249
225 #ifndef CRYPT_MACHINE_KEYSET
226 # define CRYPT_MACHINE_KEYSET 0x00000020
229 #ifndef CRYPT_NEWKEYSET
230 # define CRYPT_NEWKEYSET 0x00000008
233 #ifndef PROV_RSA_FULL
234 # define PROV_RSA_FULL 1
237 typedef BOOL (__stdcall
*fnCryptGenRandom
)( HCRYPTPROV
, DWORD
, BYTE
* );
238 typedef BOOL (__stdcall
*fnCryptAcquireContext
)( HCRYPTPROV
*, LPCTSTR
, LPCTSTR
, DWORD
, DWORD
);
239 typedef BOOL (__stdcall
*fnCryptReleaseContext
)(HCRYPTPROV
, DWORD
);
241 static fnCryptAcquireContext g_lpCryptAcquireContext
= NULL
;
242 static fnCryptReleaseContext g_lpCryptReleaseContext
= NULL
;
243 static fnCryptGenRandom g_lpCryptGenRandom
= NULL
;
244 static HINSTANCE g_hAAPI32
= NULL
;
245 static HCRYPTPROV g_hProvider
= ( ULONG_PTR
) NULL
;
248 typedef DNSServiceErrorType ( DNSSD_API
*DNSServiceRegisterFunc
)
250 DNSServiceRef
*sdRef
,
251 DNSServiceFlags flags
,
252 uint32_t interfaceIndex
,
253 const char *name
, /* may be NULL */
255 const char *domain
, /* may be NULL */
256 const char *host
, /* may be NULL */
259 const void *txtRecord
, /* may be NULL */
260 DNSServiceRegisterReply callBack
, /* may be NULL */
261 void *context
/* may be NULL */
265 typedef void ( DNSSD_API
*DNSServiceRefDeallocateFunc
)( DNSServiceRef sdRef
);
267 mDNSlocal HMODULE gDNSSDLibrary
= NULL
;
268 mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister
= NULL
;
269 mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate
= NULL
;
270 mDNSlocal HANDLE gSMBThread
= NULL
;
271 mDNSlocal HANDLE gSMBThreadRegisterEvent
= NULL
;
272 mDNSlocal HANDLE gSMBThreadDeregisterEvent
= NULL
;
273 mDNSlocal HANDLE gSMBThreadStopEvent
= NULL
;
274 mDNSlocal HANDLE gSMBThreadQuitEvent
= NULL
;
276 #define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
277 #define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
278 #define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
283 #pragma mark == Platform Support ==
286 //===========================================================================================================================
288 //===========================================================================================================================
290 mDNSexport mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
293 OSVERSIONINFO osInfo
;
297 struct sockaddr_in sa4
;
298 struct sockaddr_in6 sa6
;
303 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init\n" );
305 // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
306 // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
308 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
309 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
310 inMDNS
->p
->mainThread
= OpenThread( THREAD_ALL_ACCESS
, FALSE
, GetCurrentThreadId() );
311 require_action( inMDNS
->p
->mainThread
, exit
, err
= mStatus_UnknownErr
);
312 inMDNS
->p
->checkFileSharesTimer
= CreateWaitableTimer( NULL
, FALSE
, NULL
);
313 require_action( inMDNS
->p
->checkFileSharesTimer
, exit
, err
= mStatus_UnknownErr
);
314 inMDNS
->p
->checkFileSharesTimeout
= 10; // Retry time for CheckFileShares() in seconds
315 mDNSPlatformOneSecond
= 1000; // Use milliseconds as the quantum of time
317 // Get OS version info
319 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
320 ok
= GetVersionEx( &osInfo
);
321 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
322 require_noerr( err
, exit
);
323 inMDNS
->p
->osMajorVersion
= osInfo
.dwMajorVersion
;
324 inMDNS
->p
->osMinorVersion
= osInfo
.dwMinorVersion
;
326 // Don't enable IPv6 on anything less recent than Windows Vista
328 if ( inMDNS
->p
->osMajorVersion
< 6 )
333 // Startup WinSock 2.2 or later.
335 err
= WSAStartup( MAKEWORD( kWinSockMajorMin
, kWinSockMinorMin
), &wsaData
);
336 require_noerr( err
, exit
);
338 supported
= ( ( LOBYTE( wsaData
.wVersion
) == kWinSockMajorMin
) && ( HIBYTE( wsaData
.wVersion
) == kWinSockMinorMin
) );
339 require_action( supported
, exit
, err
= mStatus_UnsupportedErr
);
341 inMDNS
->CanReceiveUnicastOn5353
= CanReceiveUnicast();
343 // Setup the HINFO HW strings.
344 //<rdar://problem/7245119> device-info should have model=Windows
346 strcpy_s( ( char* ) &inMDNS
->HIHardware
.c
[ 1 ], sizeof( inMDNS
->HIHardware
.c
) - 2, "Windows" );
347 inMDNS
->HIHardware
.c
[ 0 ] = ( mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HIHardware
.c
[ 1 ] );
348 dlog( kDebugLevelInfo
, DEBUG_NAME
"HIHardware: %#s\n", inMDNS
->HIHardware
.c
);
350 // Setup the HINFO SW strings.
351 #if ( MDNS_SET_HINFO_STRINGS )
352 mDNS_snprintf( (char *) &inMDNS
->HISoftware
.c
[ 1 ], sizeof( inMDNS
->HISoftware
.c
) - 2,
353 "mDNSResponder (%s %s)", __DATE__
, __TIME__
);
354 inMDNS
->HISoftware
.c
[ 0 ] = (mDNSu8
) mDNSPlatformStrLen( &inMDNS
->HISoftware
.c
[ 1 ] );
355 dlog( kDebugLevelInfo
, DEBUG_NAME
"HISoftware: %#s\n", inMDNS
->HISoftware
.c
);
358 // Set up the IPv4 unicast socket
360 inMDNS
->p
->unicastSock4
.fd
= INVALID_SOCKET
;
361 inMDNS
->p
->unicastSock4
.recvMsgPtr
= NULL
;
362 inMDNS
->p
->unicastSock4
.ifd
= NULL
;
363 inMDNS
->p
->unicastSock4
.next
= NULL
;
364 inMDNS
->p
->unicastSock4
.m
= inMDNS
;
366 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
368 sa4
.sin_family
= AF_INET
;
369 sa4
.sin_addr
.s_addr
= INADDR_ANY
;
370 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa4
, zeroIPPort
, &inMDNS
->p
->unicastSock4
.fd
);
372 sa4len
= sizeof( sa4
);
373 err
= getsockname( inMDNS
->p
->unicastSock4
.fd
, (struct sockaddr
*) &sa4
, &sa4len
);
374 require_noerr( err
, exit
);
375 inMDNS
->p
->unicastSock4
.port
.NotAnInteger
= sa4
.sin_port
;
376 inMDNS
->UnicastPort4
= inMDNS
->p
->unicastSock4
.port
;
377 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
);
381 inMDNS
->p
->unicastSock4
.recvMsgPtr
= NULL
;
384 err
= mDNSPollRegisterSocket( inMDNS
->p
->unicastSock4
.fd
, FD_READ
, UDPSocketNotification
, &inMDNS
->p
->unicastSock4
);
385 require_noerr( err
, exit
);
389 // Set up the IPv6 unicast socket
391 inMDNS
->p
->unicastSock6
.fd
= INVALID_SOCKET
;
392 inMDNS
->p
->unicastSock6
.recvMsgPtr
= NULL
;
393 inMDNS
->p
->unicastSock6
.ifd
= NULL
;
394 inMDNS
->p
->unicastSock6
.next
= NULL
;
395 inMDNS
->p
->unicastSock6
.m
= inMDNS
;
397 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
401 sa6
.sin6_family
= AF_INET6
;
402 sa6
.sin6_addr
= in6addr_any
;
403 sa6
.sin6_scope_id
= 0;
405 // This call will fail if the machine hasn't installed IPv6. In that case,
406 // the error will be WSAEAFNOSUPPORT.
408 err
= SetupSocket( inMDNS
, (const struct sockaddr
*) &sa6
, zeroIPPort
, &inMDNS
->p
->unicastSock6
.fd
);
409 require_action( !err
|| ( err
== WSAEAFNOSUPPORT
), exit
, err
= (mStatus
) WSAGetLastError() );
412 // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
414 if ( inMDNS
->p
->unicastSock6
.fd
!= INVALID_SOCKET
)
416 sa6len
= sizeof( sa6
);
417 err
= getsockname( inMDNS
->p
->unicastSock6
.fd
, (struct sockaddr
*) &sa6
, &sa6len
);
418 require_noerr( err
, exit
);
419 inMDNS
->p
->unicastSock6
.port
.NotAnInteger
= sa6
.sin6_port
;
420 inMDNS
->UnicastPort6
= inMDNS
->p
->unicastSock6
.port
;
422 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
);
426 inMDNS
->p
->unicastSock6
.recvMsgPtr
= NULL
;
429 err
= mDNSPollRegisterSocket( inMDNS
->p
->unicastSock6
.fd
, FD_READ
, UDPSocketNotification
, &inMDNS
->p
->unicastSock6
);
430 require_noerr( err
, exit
);
436 // Notify core of domain secret keys
438 SetDomainSecrets( inMDNS
);
442 mDNSCoreInitComplete( inMDNS
, err
);
449 mDNSPlatformClose( inMDNS
);
452 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform init done (err=%d %m)\n", err
, err
);
456 //===========================================================================================================================
458 //===========================================================================================================================
460 mDNSexport
void mDNSPlatformClose( mDNS
* const inMDNS
)
464 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close\n" );
467 if ( gSMBThread
!= NULL
)
469 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down smb registration thread\n" );
470 SetEvent( gSMBThreadStopEvent
);
472 if ( WaitForSingleObject( gSMBThreadQuitEvent
, 5 * 1000 ) == WAIT_OBJECT_0
)
474 if ( gSMBThreadQuitEvent
)
476 CloseHandle( gSMBThreadQuitEvent
);
477 gSMBThreadQuitEvent
= NULL
;
480 if ( gSMBThreadStopEvent
)
482 CloseHandle( gSMBThreadStopEvent
);
483 gSMBThreadStopEvent
= NULL
;
486 if ( gSMBThreadDeregisterEvent
)
488 CloseHandle( gSMBThreadDeregisterEvent
);
489 gSMBThreadDeregisterEvent
= NULL
;
492 if ( gSMBThreadRegisterEvent
)
494 CloseHandle( gSMBThreadRegisterEvent
);
495 gSMBThreadRegisterEvent
= NULL
;
500 FreeLibrary( gDNSSDLibrary
);
501 gDNSSDLibrary
= NULL
;
506 LogMsg( "Unable to stop SMBThread" );
509 inMDNS
->p
->smbFileSharing
= mDNSfalse
;
510 inMDNS
->p
->smbPrintSharing
= mDNSfalse
;
513 // Tear everything down in reverse order to how it was set up.
515 err
= TearDownInterfaceList( inMDNS
);
517 check( !inMDNS
->p
->inactiveInterfaceList
);
519 #if ( MDNS_WINDOWS_ENABLE_IPV4 )
521 UDPCloseSocket( &inMDNS
->p
->unicastSock4
);
525 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
529 UDPCloseSocket( &inMDNS
->p
->unicastSock6
);
534 // Free the DLL needed for IPv6 support.
536 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
537 if( gIPHelperLibraryInstance
)
539 gGetAdaptersAddressesFunctionPtr
= NULL
;
541 FreeLibrary( gIPHelperLibraryInstance
);
542 gIPHelperLibraryInstance
= NULL
;
548 // Release any resources
550 if ( g_hProvider
&& g_lpCryptReleaseContext
)
552 ( g_lpCryptReleaseContext
)( g_hProvider
, 0 );
555 // Free the AdvApi32.dll
557 FreeLibrary( g_hAAPI32
);
559 // And reset all the data
561 g_lpCryptAcquireContext
= NULL
;
562 g_lpCryptReleaseContext
= NULL
;
563 g_lpCryptGenRandom
= NULL
;
564 g_hProvider
= ( ULONG_PTR
) NULL
;
570 dlog( kDebugLevelTrace
, DEBUG_NAME
"platform close done\n" );
574 //===========================================================================================================================
576 //===========================================================================================================================
578 mDNSexport
void mDNSPlatformLock( const mDNS
* const inMDNS
)
583 //===========================================================================================================================
584 // mDNSPlatformUnlock
585 //===========================================================================================================================
587 mDNSexport
void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
592 //===========================================================================================================================
593 // mDNSPlatformStrCopy
594 //===========================================================================================================================
596 mDNSexport
void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
601 strcpy( (char *) inDst
, (const char*) inSrc
);
604 //===========================================================================================================================
605 // mDNSPlatformStrLen
606 //===========================================================================================================================
608 mDNSexport mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
612 return( (mDNSu32
) strlen( (const char *) inSrc
) );
615 //===========================================================================================================================
616 // mDNSPlatformMemCopy
617 //===========================================================================================================================
619 mDNSexport
void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
624 memcpy( inDst
, inSrc
, inSize
);
627 //===========================================================================================================================
628 // mDNSPlatformMemSame
629 //===========================================================================================================================
631 mDNSexport mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
636 return( (mDNSBool
)( memcmp( inSrc
, inDst
, inSize
) == 0 ) );
639 //===========================================================================================================================
640 // mDNSPlatformMemCmp
641 //===========================================================================================================================
643 mDNSexport
int mDNSPlatformMemCmp( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
648 return( memcmp( inSrc
, inDst
, inSize
) );
651 mDNSexport
void mDNSPlatformQsort(void *base
, int nel
, int width
, int (*compar
)(const void *, const void *))
659 // DNSSEC stub functions
660 mDNSexport
void VerifySignature(mDNS
*const m
, DNSSECVerifier
*dv
, DNSQuestion
*q
)
667 mDNSexport mDNSBool
AddNSECSForCacheRecord(mDNS
*const m
, CacheRecord
*crlist
, CacheRecord
*negcr
, mDNSu8 rcode
)
676 mDNSexport
void BumpDNSSECStats(mDNS
*const m
, DNSSECStatsAction action
, DNSSECStatsType type
, mDNSu32 value
)
684 // Proxy stub functions
685 mDNSexport mDNSu8
*DNSProxySetAttributes(DNSQuestion
*q
, DNSMessageHeader
*h
, DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
)
696 mDNSexport
void DNSProxyInit(mDNS
*const m
, mDNSu32 IpIfArr
[], mDNSu32 OpIf
)
703 mDNSexport
void DNSProxyTerminate(mDNS
*const m
)
708 //===========================================================================================================================
709 // mDNSPlatformMemZero
710 //===========================================================================================================================
712 mDNSexport
void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
716 memset( inDst
, 0, inSize
);
719 //===========================================================================================================================
720 // mDNSPlatformMemAllocate
721 //===========================================================================================================================
723 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
729 mem
= malloc( inSize
);
735 //===========================================================================================================================
736 // mDNSPlatformMemFree
737 //===========================================================================================================================
739 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
746 //===========================================================================================================================
747 // mDNSPlatformRandomNumber
748 //===========================================================================================================================
750 mDNSexport mDNSu32
mDNSPlatformRandomNumber(void)
752 unsigned int randomNumber
;
755 err
= rand_s( &randomNumber
);
756 require_noerr( err
, exit
);
762 randomNumber
= rand();
765 return ( mDNSu32
) randomNumber
;
768 //===========================================================================================================================
769 // mDNSPlatformTimeInit
770 //===========================================================================================================================
772 mDNSexport mStatus
mDNSPlatformTimeInit( void )
774 // No special setup is required on Windows -- we just use GetTickCount().
775 return( mStatus_NoError
);
778 //===========================================================================================================================
779 // mDNSPlatformRawTime
780 //===========================================================================================================================
782 mDNSexport mDNSs32
mDNSPlatformRawTime( void )
784 return( (mDNSs32
) GetTickCount() );
787 //===========================================================================================================================
789 //===========================================================================================================================
791 mDNSexport mDNSs32
mDNSPlatformUTC( void )
793 return ( mDNSs32
) time( NULL
);
796 //===========================================================================================================================
797 // mDNSPlatformInterfaceNameToID
798 //===========================================================================================================================
800 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
803 mDNSInterfaceData
* ifd
;
809 // Search for an interface with the specified name,
811 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
813 if( strcmp( ifd
->name
, inName
) == 0 )
818 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
824 *outID
= (mDNSInterfaceID
) ifd
;
826 err
= mStatus_NoError
;
832 //===========================================================================================================================
833 // mDNSPlatformInterfaceIDToInfo
834 //===========================================================================================================================
836 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
839 mDNSInterfaceData
* ifd
;
845 // Search for an interface with the specified ID,
847 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
849 if( ifd
== (mDNSInterfaceData
*) inID
)
854 require_action_quiet( ifd
, exit
, err
= mStatus_NoSuchNameErr
);
858 outInfo
->name
= ifd
->name
;
859 outInfo
->ip
= ifd
->interfaceInfo
.ip
;
860 err
= mStatus_NoError
;
866 //===========================================================================================================================
867 // mDNSPlatformInterfaceIDfromInterfaceIndex
868 //===========================================================================================================================
870 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
* const inMDNS
, mDNSu32 inIndex
)
875 if( inIndex
== kDNSServiceInterfaceIndexLocalOnly
)
877 id
= mDNSInterface_LocalOnly
;
879 else if( inIndex
!= 0 )
881 mDNSInterfaceData
* ifd
;
883 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
885 if( ( ifd
->scopeID
== inIndex
) && ifd
->interfaceInfo
.InterfaceActive
)
887 id
= ifd
->interfaceInfo
.InterfaceID
;
896 //===========================================================================================================================
897 // mDNSPlatformInterfaceIndexfromInterfaceID
898 //===========================================================================================================================
900 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSBool suppressNetworkChange
)
904 (void) suppressNetworkChange
;
907 if( inID
== mDNSInterface_LocalOnly
)
909 index
= (mDNSu32
) kDNSServiceInterfaceIndexLocalOnly
;
913 mDNSInterfaceData
* ifd
;
915 // Search active interfaces.
916 for( ifd
= inMDNS
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
918 if( (mDNSInterfaceID
) ifd
== inID
)
920 index
= ifd
->scopeID
;
925 // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
929 for( ifd
= inMDNS
->p
->inactiveInterfaceList
; ifd
; ifd
= ifd
->next
)
931 if( (mDNSInterfaceID
) ifd
== inID
)
933 index
= ifd
->scopeID
;
944 //===========================================================================================================================
945 // mDNSPlatformTCPSocket
946 //===========================================================================================================================
949 mDNSPlatformTCPSocket
952 TCPSocketFlags flags
,
954 mDNSBool useBackgroundTrafficClass
957 TCPSocket
* sock
= NULL
;
958 u_long on
= 1; // "on" for setsockopt
959 struct sockaddr_in saddr
;
961 mStatus err
= mStatus_NoError
;
964 DEBUG_UNUSED( useBackgroundTrafficClass
);
966 require_action( flags
== 0, exit
, err
= mStatus_UnsupportedErr
);
968 // Setup connection data object
970 sock
= (TCPSocket
*) malloc( sizeof( TCPSocket
) );
971 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
972 mDNSPlatformMemZero( sock
, sizeof( TCPSocket
) );
973 sock
->fd
= INVALID_SOCKET
;
977 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
978 saddr
.sin_family
= AF_INET
;
979 saddr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
980 saddr
.sin_port
= port
->NotAnInteger
;
984 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
985 err
= translate_errno( sock
->fd
!= INVALID_SOCKET
, WSAGetLastError(), mStatus_UnknownErr
);
986 require_noerr( err
, exit
);
990 err
= bind( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
991 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
992 require_noerr( err
, exit
);
994 // Set it to be non-blocking
996 err
= ioctlsocket( sock
->fd
, FIONBIO
, &on
);
997 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
998 require_noerr( err
, exit
);
1002 mDNSPlatformMemZero( &saddr
, sizeof( saddr
) );
1003 len
= sizeof( saddr
);
1005 err
= getsockname( sock
->fd
, ( struct sockaddr
* ) &saddr
, &len
);
1006 err
= translate_errno( err
== 0, WSAGetLastError(), mStatus_UnknownErr
);
1007 require_noerr( err
, exit
);
1009 port
->NotAnInteger
= saddr
.sin_port
;
1015 TCPCloseSocket( sock
);
1023 //===========================================================================================================================
1024 // mDNSPlatformTCPConnect
1025 //===========================================================================================================================
1028 mDNSPlatformTCPConnect
1031 const mDNSAddr
* inDstIP
,
1032 mDNSOpaque16 inDstPort
,
1033 domainname
* hostname
,
1034 mDNSInterfaceID inInterfaceID
,
1035 TCPConnectionCallback inCallback
,
1039 struct sockaddr_in saddr
;
1040 mStatus err
= mStatus_NoError
;
1042 DEBUG_UNUSED( hostname
);
1043 DEBUG_UNUSED( inInterfaceID
);
1045 if ( inDstIP
->type
!= mDNSAddrType_IPv4
)
1047 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
1048 return mStatus_UnknownErr
;
1051 // Setup connection data object
1053 sock
->userCallback
= inCallback
;
1054 sock
->userContext
= inContext
;
1056 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1057 saddr
.sin_family
= AF_INET
;
1058 saddr
.sin_port
= inDstPort
.NotAnInteger
;
1059 memcpy(&saddr
.sin_addr
, &inDstIP
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1061 // Try and do connect
1063 err
= connect( sock
->fd
, ( struct sockaddr
* ) &saddr
, sizeof( saddr
) );
1064 require_action( !err
|| ( WSAGetLastError() == WSAEWOULDBLOCK
), exit
, err
= mStatus_ConnFailed
);
1065 sock
->connected
= !err
? TRUE
: FALSE
;
1067 err
= mDNSPollRegisterSocket( sock
->fd
, FD_CONNECT
| FD_READ
| FD_CLOSE
, TCPSocketNotification
, sock
);
1068 require_noerr( err
, exit
);
1074 err
= sock
->connected
? mStatus_ConnEstablished
: mStatus_ConnPending
;
1081 //===========================================================================================================================
1082 // mDNSPlatformTCPAccept
1083 //===========================================================================================================================
1086 mDNSexport TCPSocket
*mDNSPlatformTCPAccept( TCPSocketFlags flags
, int fd
)
1088 TCPSocket
* sock
= NULL
;
1089 mStatus err
= mStatus_NoError
;
1091 require_action( !flags
, exit
, err
= mStatus_UnsupportedErr
);
1093 sock
= malloc( sizeof( TCPSocket
) );
1094 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1096 mDNSPlatformMemZero( sock
, sizeof( *sock
) );
1099 sock
->flags
= flags
;
1113 //===========================================================================================================================
1114 // mDNSPlatformTCPCloseConnection
1115 //===========================================================================================================================
1117 mDNSexport
void mDNSPlatformTCPCloseConnection( TCPSocket
*sock
)
1123 dlog( kDebugLevelChatty
, DEBUG_NAME
"mDNSPlatformTCPCloseConnection 0x%x:%d\n", sock
, sock
->fd
);
1125 if ( sock
->fd
!= INVALID_SOCKET
)
1127 mDNSPollUnregisterSocket( sock
->fd
);
1128 closesocket( sock
->fd
);
1129 sock
->fd
= INVALID_SOCKET
;
1137 //===========================================================================================================================
1138 // mDNSPlatformReadTCP
1139 //===========================================================================================================================
1141 mDNSexport
long mDNSPlatformReadTCP( TCPSocket
*sock
, void *inBuffer
, unsigned long inBufferSize
, mDNSBool
* closed
)
1146 *closed
= mDNSfalse
;
1147 nread
= recv( sock
->fd
, inBuffer
, inBufferSize
, 0 );
1148 err
= translate_errno( ( nread
>= 0 ), WSAGetLastError(), mStatus_UnknownErr
);
1152 dlog( kDebugLevelChatty
, DEBUG_NAME
"mDNSPlatformReadTCP: 0x%x:%d read %d bytes\n", sock
, sock
->fd
, nread
);
1158 else if ( err
== WSAECONNRESET
)
1163 else if ( err
== WSAEWOULDBLOCK
)
1169 LogMsg( "ERROR: mDNSPlatformReadTCP - recv: %d\n", err
);
1177 //===========================================================================================================================
1178 // mDNSPlatformWriteTCP
1179 //===========================================================================================================================
1181 mDNSexport
long mDNSPlatformWriteTCP( TCPSocket
*sock
, const char *inMsg
, unsigned long inMsgSize
)
1186 nsent
= send( sock
->fd
, inMsg
, inMsgSize
, 0 );
1188 err
= translate_errno( ( nsent
>= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK
), WSAGetLastError(), mStatus_UnknownErr
);
1189 require_noerr( err
, exit
);
1201 //===========================================================================================================================
1202 // mDNSPlatformTCPGetFD
1203 //===========================================================================================================================
1205 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1207 return ( int ) sock
->fd
;
1212 //===========================================================================================================================
1213 // TCPSocketNotification
1214 //===========================================================================================================================
1216 mDNSlocal
void CALLBACK
1217 TCPSocketNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
)
1219 TCPSocket
*tcpSock
= ( TCPSocket
* ) context
;
1220 TCPConnectionCallback callback
;
1223 DEBUG_UNUSED( sock
);
1225 require_action( tcpSock
, exit
, err
= mStatus_BadParamErr
);
1226 callback
= ( TCPConnectionCallback
) tcpSock
->userCallback
;
1227 require_action( callback
, exit
, err
= mStatus_BadParamErr
);
1229 if ( event
&& ( event
->lNetworkEvents
& FD_CONNECT
) )
1231 if ( event
->iErrorCode
[ FD_CONNECT_BIT
] == 0 )
1233 callback( tcpSock
, tcpSock
->userContext
, mDNStrue
, 0 );
1234 tcpSock
->connected
= mDNStrue
;
1238 callback( tcpSock
, tcpSock
->userContext
, mDNSfalse
, event
->iErrorCode
[ FD_CONNECT_BIT
] );
1243 callback( tcpSock
, tcpSock
->userContext
, mDNSfalse
, 0 );
1253 //===========================================================================================================================
1254 // mDNSPlatformUDPSocket
1255 //===========================================================================================================================
1257 mDNSexport UDPSocket
* mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
1259 UDPSocket
* sock
= NULL
;
1260 mDNSIPPort port
= requestedport
;
1261 mStatus err
= mStatus_NoError
;
1264 // Setup connection data object
1266 sock
= ( UDPSocket
* ) malloc(sizeof( UDPSocket
) );
1267 require_action( sock
, exit
, err
= mStatus_NoMemoryErr
);
1268 memset( sock
, 0, sizeof( UDPSocket
) );
1270 // Create the socket
1272 sock
->fd
= INVALID_SOCKET
;
1273 sock
->recvMsgPtr
= m
->p
->unicastSock4
.recvMsgPtr
;
1274 sock
->addr
= m
->p
->unicastSock4
.addr
;
1278 // Try at most 10000 times to get a unique random port
1280 for (i
=0; i
<10000; i
++)
1282 struct sockaddr_in saddr
;
1284 saddr
.sin_family
= AF_INET
;
1285 saddr
.sin_addr
.s_addr
= 0;
1287 // The kernel doesn't do cryptographically strong random port
1288 // allocation, so we do it ourselves here
1290 if (mDNSIPPortIsZero(requestedport
))
1292 port
= mDNSOpaque16fromIntVal( ( mDNSu16
) ( 0xC000 + mDNSRandom(0x3FFF) ) );
1295 saddr
.sin_port
= port
.NotAnInteger
;
1297 err
= SetupSocket(m
, ( struct sockaddr
* ) &saddr
, port
, &sock
->fd
);
1301 require_noerr( err
, exit
);
1307 // Arm the completion routine
1309 err
= mDNSPollRegisterSocket( sock
->fd
, FD_READ
, UDPSocketNotification
, sock
);
1310 require_noerr( err
, exit
);
1314 sock
->next
= gUDPSockets
;
1322 UDPCloseSocket( sock
);
1330 //===========================================================================================================================
1331 // mDNSPlatformUDPClose
1332 //===========================================================================================================================
1334 mDNSexport
void mDNSPlatformUDPClose( UDPSocket
*sock
)
1336 UDPSocket
* current
= gUDPSockets
;
1337 UDPSocket
* last
= NULL
;
1341 if ( current
== sock
)
1345 gUDPSockets
= sock
->next
;
1349 last
->next
= sock
->next
;
1352 UDPCloseSocket( sock
);
1361 current
= current
->next
;
1366 //===========================================================================================================================
1367 // mDNSPlatformSendUDP
1368 //===========================================================================================================================
1371 mDNSPlatformSendUDP(
1372 const mDNS
* const inMDNS
,
1373 const void * const inMsg
,
1374 const mDNSu8
* const inMsgEnd
,
1375 mDNSInterfaceID inInterfaceID
,
1376 UDPSocket
* inSrcSocket
,
1377 const mDNSAddr
* inDstIP
,
1378 mDNSIPPort inDstPort
,
1379 mDNSBool useBackgroundTrafficClass
)
1381 SOCKET sendingsocket
= INVALID_SOCKET
;
1382 mStatus err
= mStatus_NoError
;
1383 mDNSInterfaceData
* ifd
= (mDNSInterfaceData
*) inInterfaceID
;
1384 struct sockaddr_storage addr
;
1387 DEBUG_USE_ONLY( inMDNS
);
1388 DEBUG_USE_ONLY( useBackgroundTrafficClass
);
1390 n
= (int)( inMsgEnd
- ( (const mDNSu8
* const) inMsg
) );
1396 dlog( kDebugLevelChatty
, DEBUG_NAME
"platform send %d bytes to %#a:%u\n", n
, inDstIP
, ntohs( inDstPort
.NotAnInteger
) );
1398 if( inDstIP
->type
== mDNSAddrType_IPv4
)
1400 struct sockaddr_in
* sa4
;
1402 sa4
= (struct sockaddr_in
*) &addr
;
1403 sa4
->sin_family
= AF_INET
;
1404 sa4
->sin_port
= inDstPort
.NotAnInteger
;
1405 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
1406 sendingsocket
= ifd
? ifd
->sock
.fd
: inMDNS
->p
->unicastSock4
.fd
;
1408 if (inSrcSocket
) { sendingsocket
= inSrcSocket
->fd
; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket
->port
), inMDNS
->p
->unicastSock4
.fd
, sendingsocket
); }
1410 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
1412 struct sockaddr_in6
* sa6
;
1414 sa6
= (struct sockaddr_in6
*) &addr
;
1415 sa6
->sin6_family
= AF_INET6
;
1416 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
1417 sa6
->sin6_flowinfo
= 0;
1418 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
1419 sa6
->sin6_scope_id
= 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
1420 sendingsocket
= ifd
? ifd
->sock
.fd
: inMDNS
->p
->unicastSock6
.fd
;
1424 dlog( kDebugLevelError
, DEBUG_NAME
"%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__
, inDstIP
->type
);
1425 err
= mStatus_BadParamErr
;
1429 if (IsValidSocket(sendingsocket
))
1431 n
= sendto( sendingsocket
, (char *) inMsg
, n
, 0, (struct sockaddr
*) &addr
, sizeof( addr
) );
1432 err
= translate_errno( n
> 0, errno_compat(), kWriteErr
);
1436 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1438 if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP
) && ( WSAGetLastError() == WSAEHOSTDOWN
|| WSAGetLastError() == WSAENETDOWN
|| WSAGetLastError() == WSAEHOSTUNREACH
|| WSAGetLastError() == WSAENETUNREACH
) )
1440 err
= mStatus_TransientErr
;
1444 require_noerr( err
, exit
);
1454 mDNSexport mDNSBool
mDNSPlatformPeekUDP(mDNS
*const m
, UDPSocket
*src
)
1457 DEBUG_UNUSED( src
);
1461 mDNSexport
void mDNSPlatformUpdateProxyList(mDNS
*const m
, const mDNSInterfaceID InterfaceID
)
1464 DEBUG_UNUSED( InterfaceID
);
1468 mDNSexport
void mDNSPlatformSetAllowSleep(mDNS
*const m
, mDNSBool allowSleep
, const char *reason
)
1471 DEBUG_UNUSED( allowSleep
);
1472 DEBUG_UNUSED( reason
);
1475 //===========================================================================================================================
1476 // mDNSPlatformSendRawPacket
1477 //===========================================================================================================================
1479 mDNSexport
void mDNSPlatformSendWakeupPacket(mDNS
*const m
, mDNSInterfaceID InterfaceID
, char *ethaddr
, char *ipaddr
, int iteration
)
1481 unsigned char mac
[ 6 ];
1482 unsigned char buf
[ 102 ];
1483 char hex
[ 3 ] = { 0 };
1484 unsigned char *bufPtr
= buf
;
1485 struct sockaddr_storage saddr
;
1486 INT len
= sizeof( saddr
);
1487 mDNSBool unicast
= mDNSfalse
;
1488 MulticastWakeupStruct
*info
;
1494 require_action( ethaddr
, exit
, err
= mStatus_BadParamErr
);
1496 for ( i
= 0; i
< 6; i
++ )
1498 memcpy( hex
, ethaddr
+ ( i
* 3 ), 2 );
1499 mac
[ i
] = ( unsigned char ) strtoul( hex
, NULL
, 16 );
1502 memset( buf
, 0, sizeof( buf
) );
1504 for ( i
= 0; i
< 6; i
++ )
1509 for ( i
= 0; i
< 16; i
++ )
1511 memcpy( bufPtr
, mac
, sizeof( mac
) );
1512 bufPtr
+= sizeof( mac
);
1517 if ( WSAStringToAddressA( ipaddr
, AF_INET
, NULL
, ( LPSOCKADDR
) &saddr
, &len
) == 0 )
1519 struct sockaddr_in
* saddr4
= ( struct sockaddr_in
* ) &saddr
;
1520 saddr4
->sin_port
= htons( 9 );
1521 len
= sizeof( *saddr4
);
1523 if ( saddr4
->sin_addr
.s_addr
!= htonl( INADDR_ANY
) )
1528 else if ( WSAStringToAddressA( ipaddr
, AF_INET6
, NULL
, ( LPSOCKADDR
) &saddr
, &len
) == 0 )
1530 mDNSInterfaceData
*ifd
= ( mDNSInterfaceData
* ) InterfaceID
;
1531 struct sockaddr_in6
* saddr6
= ( struct sockaddr_in6
* ) &saddr
;
1532 saddr6
->sin6_port
= htons( 9 );
1536 saddr6
->sin6_scope_id
= ifd
->scopeID
;
1539 len
= sizeof( *saddr6
);
1541 if ( memcmp( &saddr6
->sin6_addr
, &in6addr_any
, sizeof( IN6_ADDR
) ) != 0 )
1548 if ( ( iteration
< 2 ) && ( unicast
) )
1550 SendWakeupPacket( m
, ( LPSOCKADDR
) &saddr
, len
, ( const char* ) buf
, sizeof( buf
), kUnicastWakeupNumTries
, kUnicastWakeupSleepBetweenTries
);
1553 info
= ( MulticastWakeupStruct
* ) malloc( sizeof( MulticastWakeupStruct
) );
1554 require_action( info
, exit
, err
= mStatus_NoMemoryErr
);
1556 memset( &info
->addr
, 0, sizeof( info
->addr
) );
1557 info
->addr
.sin_family
= AF_INET
;
1558 info
->addr
.sin_addr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1559 info
->addr
.sin_port
= htons( 9 );
1560 info
->addrLen
= sizeof( info
->addr
);
1561 memcpy( info
->data
, buf
, sizeof( buf
) );
1562 info
->dataLen
= sizeof( buf
);
1563 info
->numTries
= kMulticastWakeupNumTries
;
1564 info
->msecSleep
= kMulticastWakeupSleepBetweenTries
;
1566 _beginthread( SendMulticastWakeupPacket
, 0, ( void* ) info
);
1574 mDNSexport mDNSBool
mDNSPlatformValidRecordForInterface(AuthRecord
*rr
, const NetworkInterfaceInfo
*intf
)
1577 DEBUG_UNUSED( intf
);
1582 mDNSexport mDNSBool
mDNSPlatformValidQuestionForInterface(DNSQuestion
*q
, const NetworkInterfaceInfo
*intf
)
1585 DEBUG_UNUSED( intf
);
1590 mDNSexport
void mDNSPlatformSendRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1592 DEBUG_UNUSED( msg
);
1593 DEBUG_UNUSED( end
);
1594 DEBUG_UNUSED( InterfaceID
);
1597 // Used for debugging purposes. For now, just set the buffer to zero
1598 mDNSexport
void mDNSPlatformFormatTime(unsigned long te
, mDNSu8
*buf
, int bufsize
)
1601 if (bufsize
) buf
[0] = 0;
1605 mDNSexport
void mDNSPlatformSetLocalAddressCacheEntry(mDNS
*const m
, const mDNSAddr
*const tpa
, const mDNSEthAddr
*const tha
, mDNSInterfaceID InterfaceID
)
1608 DEBUG_UNUSED( tpa
);
1609 DEBUG_UNUSED( tha
);
1610 DEBUG_UNUSED( InterfaceID
);
1614 mDNSexport
void mDNSPlatformReceiveRawPacket(const void *const msg
, const mDNSu8
*const end
, mDNSInterfaceID InterfaceID
)
1616 DEBUG_UNUSED( msg
);
1617 DEBUG_UNUSED( end
);
1618 DEBUG_UNUSED( InterfaceID
);
1621 mDNSexport
void mDNSPlatformSetLocalARP( const mDNSv4Addr
* const tpa
, const mDNSEthAddr
* const tha
, mDNSInterfaceID InterfaceID
)
1623 DEBUG_UNUSED( tpa
);
1624 DEBUG_UNUSED( tha
);
1625 DEBUG_UNUSED( InterfaceID
);
1628 mDNSexport
void mDNSPlatformWriteDebugMsg(const char *msg
)
1630 dlog( kDebugLevelInfo
, "%s\n", msg
);
1633 mDNSexport
void mDNSPlatformWriteLogMsg( const char * ident
, const char * msg
, mDNSLogLevel_t loglevel
)
1635 extern mDNS mDNSStorage
;
1638 DEBUG_UNUSED( ident
);
1640 type
= EVENTLOG_ERROR_TYPE
;
1644 case MDNS_LOG_MSG
: type
= EVENTLOG_ERROR_TYPE
; break;
1645 case MDNS_LOG_OPERATION
: type
= EVENTLOG_WARNING_TYPE
; break;
1646 case MDNS_LOG_SPS
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1647 case MDNS_LOG_INFO
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1648 case MDNS_LOG_DEBUG
: type
= EVENTLOG_INFORMATION_TYPE
; break;
1650 fprintf(stderr
, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel
);
1654 mDNSStorage
.p
->reportStatusFunc( type
, msg
);
1655 dlog( kDebugLevelInfo
, "%s\n", msg
);
1658 mDNSexport
void mDNSPlatformSourceAddrForDest( mDNSAddr
* const src
, const mDNSAddr
* const dst
)
1660 DEBUG_UNUSED( src
);
1661 DEBUG_UNUSED( dst
);
1664 //===========================================================================================================================
1665 // mDNSPlatformTLSSetupCerts
1666 //===========================================================================================================================
1669 mDNSPlatformTLSSetupCerts(void)
1671 return mStatus_UnsupportedErr
;
1674 //===========================================================================================================================
1675 // mDNSPlatformTLSTearDownCerts
1676 //===========================================================================================================================
1679 mDNSPlatformTLSTearDownCerts(void)
1683 //===========================================================================================================================
1684 // mDNSPlatformSetDNSConfig
1685 //===========================================================================================================================
1687 mDNSlocal
void SetDNSServers( mDNS
*const m
);
1688 mDNSlocal
void SetSearchDomainList( void );
1690 mDNSexport mDNSBool
mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**regDomains
, DNameListElem
**browseDomains
, mDNSBool ackConfig
)
1694 if (setservers
) SetDNSServers(m
);
1695 if (setsearch
) SetSearchDomainList();
1699 GetDDNSFQDN( fqdn
);
1702 if ( browseDomains
)
1704 GetDDNSDomains( browseDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains
);
1709 GetDDNSDomains( regDomains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1715 //===========================================================================================================================
1716 // mDNSPlatformDynDNSHostNameStatusChanged
1717 //===========================================================================================================================
1720 mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
1722 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1729 ConvertDomainNameToCString(dname
, uname
);
1735 *p
= (char) tolower(*p
);
1736 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1740 check( strlen( p
) <= MAX_ESCAPED_DOMAIN_NAME
);
1741 name
= kServiceParametersNode
TEXT("\\DynDNS\\State\\HostNames");
1742 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, name
, &key
);
1743 require_noerr( err
, exit
);
1745 bStatus
= ( status
) ? 0 : 1;
1746 err
= RegSetValueEx( key
, kServiceDynDNSStatus
, 0, REG_DWORD
, (const LPBYTE
) &bStatus
, sizeof(DWORD
) );
1747 require_noerr( err
, exit
);
1760 //===========================================================================================================================
1762 //===========================================================================================================================
1764 // This routine needs to be called whenever the system secrets database changes.
1765 // We call it from DynDNSConfigDidChange and mDNSPlatformInit
1768 SetDomainSecrets( mDNS
* const m
)
1770 DomainAuthInfo
*ptr
;
1772 DNameListElem
* regDomains
= NULL
;
1774 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
1775 // In the case where the user simultaneously removes their DDNS host name and the key
1776 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
1777 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
1778 // address records behind that we no longer have permission to delete.
1780 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
1781 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
1783 GetDDNSFQDN( &fqdn
);
1787 SetDomainSecret( m
, &fqdn
);
1790 GetDDNSDomains( ®Domains
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains
);
1792 while ( regDomains
)
1794 DNameListElem
* current
= regDomains
;
1795 SetDomainSecret( m
, ¤t
->name
);
1796 regDomains
= regDomains
->next
;
1802 //===========================================================================================================================
1803 // SetSearchDomainList
1804 //===========================================================================================================================
1806 mDNSlocal
void SetDomainFromDHCP( void );
1807 mDNSlocal
void SetReverseMapSearchDomainList( void );
1810 SetSearchDomainList( void )
1812 char * searchList
= NULL
;
1813 DWORD searchListLen
;
1814 //DNameListElem * head = NULL;
1815 //DNameListElem * current = NULL;
1820 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key
);
1821 require_noerr( err
, exit
);
1823 err
= RegQueryString( key
, "SearchList", &searchList
, &searchListLen
, NULL
);
1824 require_noerr( err
, exit
);
1826 // Windows separates the search domains with ','
1828 tok
= strtok( searchList
, "," );
1831 if ( ( strcmp( tok
, "" ) != 0 ) && ( strcmp( tok
, "." ) != 0 ) )
1832 mDNS_AddSearchDomain_CString(tok
, mDNSNULL
);
1833 tok
= strtok( NULL
, "," );
1848 SetDomainFromDHCP();
1849 SetReverseMapSearchDomainList();
1853 //===========================================================================================================================
1854 // SetReverseMapSearchDomainList
1855 //===========================================================================================================================
1858 SetReverseMapSearchDomainList( void )
1860 struct ifaddrs
* ifa
;
1862 ifa
= myGetIfAddrs( 1 );
1867 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
1872 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
1874 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
1875 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
1876 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
1877 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
1878 mDNS_AddSearchDomain_CString(buffer
, mDNSNULL
);
1882 ifa
= ifa
->ifa_next
;
1889 //===========================================================================================================================
1891 //===========================================================================================================================
1894 SetDNSServers( mDNS
*const m
)
1896 PIP_PER_ADAPTER_INFO pAdapterInfo
= NULL
;
1897 FIXED_INFO
* fixedInfo
= NULL
;
1899 IP_ADDR_STRING
* dnsServerList
;
1900 IP_ADDR_STRING
* ipAddr
;
1903 mStatus err
= kUnknownErr
;
1905 // Get the primary interface.
1907 index
= GetPrimaryInterface();
1909 // This should have the interface index of the primary index. Fall back in cases where
1910 // it can't be determined.
1916 for ( i
= 0; i
< 100; i
++ )
1918 err
= GetPerAdapterInfo( index
, pAdapterInfo
, &bufLen
);
1920 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1925 pAdapterInfo
= (PIP_PER_ADAPTER_INFO
) realloc( pAdapterInfo
, bufLen
);
1926 require_action( pAdapterInfo
, exit
, err
= mStatus_NoMemoryErr
);
1929 require_noerr( err
, exit
);
1931 dnsServerList
= &pAdapterInfo
->DnsServerList
;
1935 bufLen
= sizeof( FIXED_INFO
);
1937 for ( i
= 0; i
< 100; i
++ )
1941 GlobalFree( fixedInfo
);
1945 fixedInfo
= (FIXED_INFO
*) GlobalAlloc( GPTR
, bufLen
);
1946 require_action( fixedInfo
, exit
, err
= mStatus_NoMemoryErr
);
1948 err
= GetNetworkParams( fixedInfo
, &bufLen
);
1950 if ( err
!= ERROR_BUFFER_OVERFLOW
)
1956 require_noerr( err
, exit
);
1958 dnsServerList
= &fixedInfo
->DnsServerList
;
1961 for ( ipAddr
= dnsServerList
; ipAddr
; ipAddr
= ipAddr
->Next
)
1964 err
= StringToAddress( &addr
, ipAddr
->IpAddress
.String
);
1965 if ( !err
) mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, 0, &addr
, UnicastDNSPort
, kScopeNone
, DEFAULT_UDNS_TIMEOUT
, mDNSfalse
, 0, mDNStrue
, mDNStrue
, mDNSfalse
);
1972 free( pAdapterInfo
);
1977 GlobalFree( fixedInfo
);
1982 //===========================================================================================================================
1983 // SetDomainFromDHCP
1984 //===========================================================================================================================
1987 SetDomainFromDHCP( void )
1990 IP_ADAPTER_INFO
* pAdapterInfo
;
1991 IP_ADAPTER_INFO
* pAdapter
;
1995 LPSTR domain
= NULL
;
1997 mStatus err
= mStatus_NoError
;
1999 pAdapterInfo
= NULL
;
2001 for ( i
= 0; i
< 100; i
++ )
2003 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2005 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2010 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2011 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2014 require_noerr( err
, exit
);
2016 index
= GetPrimaryInterface();
2018 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2020 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2021 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2022 pAdapter
->GatewayList
.IpAddress
.String
&&
2023 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2024 ( !index
|| ( pAdapter
->Index
== index
) ) )
2026 // Found one that will work
2030 _snprintf( keyName
, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter
->AdapterName
);
2032 err
= RegCreateKeyA( HKEY_LOCAL_MACHINE
, keyName
, &key
);
2033 require_noerr( err
, exit
);
2035 err
= RegQueryString( key
, "Domain", &domain
, &dwSize
, NULL
);
2038 if ( !domain
|| !domain
[0] )
2046 err
= RegQueryString( key
, "DhcpDomain", &domain
, &dwSize
, NULL
);
2050 if ( domain
&& domain
[0] ) mDNS_AddSearchDomain_CString(domain
, mDNSNULL
);
2060 free( pAdapterInfo
);
2075 //===========================================================================================================================
2076 // mDNSPlatformGetPrimaryInterface
2077 //===========================================================================================================================
2080 mDNSPlatformGetPrimaryInterface( mDNS
* const m
, mDNSAddr
* v4
, mDNSAddr
* v6
, mDNSAddr
* router
)
2082 IP_ADAPTER_INFO
* pAdapterInfo
;
2083 IP_ADAPTER_INFO
* pAdapter
;
2088 mStatus err
= mStatus_NoError
;
2094 pAdapterInfo
= NULL
;
2098 for ( i
= 0; i
< 100; i
++ )
2100 err
= GetAdaptersInfo( pAdapterInfo
, &bufLen
);
2102 if ( err
!= ERROR_BUFFER_OVERFLOW
)
2107 pAdapterInfo
= (IP_ADAPTER_INFO
*) realloc( pAdapterInfo
, bufLen
);
2108 require_action( pAdapterInfo
, exit
, err
= kNoMemoryErr
);
2111 require_noerr( err
, exit
);
2113 index
= GetPrimaryInterface();
2115 for ( pAdapter
= pAdapterInfo
; pAdapter
; pAdapter
= pAdapter
->Next
)
2117 if ( pAdapter
->IpAddressList
.IpAddress
.String
&&
2118 pAdapter
->IpAddressList
.IpAddress
.String
[0] &&
2119 pAdapter
->GatewayList
.IpAddress
.String
&&
2120 pAdapter
->GatewayList
.IpAddress
.String
[0] &&
2121 ( StringToAddress( v4
, pAdapter
->IpAddressList
.IpAddress
.String
) == mStatus_NoError
) &&
2122 ( StringToAddress( router
, pAdapter
->GatewayList
.IpAddress
.String
) == mStatus_NoError
) &&
2123 ( !index
|| ( pAdapter
->Index
== index
) ) )
2125 // Found one that will work
2127 if ( pAdapter
->AddressLength
== sizeof( m
->PrimaryMAC
) )
2129 memcpy( &m
->PrimaryMAC
, pAdapter
->Address
, pAdapter
->AddressLength
);
2141 free( pAdapterInfo
);
2147 mDNSexport
void mDNSPlatformSendKeepalive(mDNSAddr
*sadd
, mDNSAddr
*dadd
, mDNSIPPort
*lport
, mDNSIPPort
*rport
, mDNSu32 seq
, mDNSu32 ack
, mDNSu16 win
)
2149 (void) sadd
; // Unused
2150 (void) dadd
; // Unused
2151 (void) lport
; // Unused
2152 (void) rport
; // Unused
2153 (void) seq
; // Unused
2154 (void) ack
; // Unused
2155 (void) win
; // Unused
2158 mDNSexport mStatus
mDNSPlatformGetRemoteMacAddr(mDNSAddr
*raddr
, char *eth
)
2160 (void) raddr
; // Unused
2161 (void) eth
; // Unused
2164 mDNSexport mStatus
mDNSPlatformStoreSPSMACAddr(mDNSAddr
*spsaddr
, char *ifname
)
2166 (void) spsaddr
; // Unused
2167 (void) ifname
; // Unused
2170 mDNSexport mStatus
mDNSPlatformClearSPSMACAddr(void)
2174 mDNSexport mStatus
mDNSPlatformRetrieveTCPInfo(mDNS
*const m
, mDNSAddr
*laddr
, mDNSIPPort
*lport
, mDNSAddr
*raddr
, mDNSIPPort
*rport
, mDNSTCPInfo
*mti
)
2177 (void) laddr
; // Unused
2178 (void) raddr
; // Unused
2179 (void) lport
; // Unused
2180 (void) rport
; // Unused
2181 (void) mti
; // Unused
2184 mDNSexport mDNSBool
mDNSPlatformAllowPID(mDNS
*const m
, DNSQuestion
*q
)
2191 mDNSexport mDNSs32
mDNSPlatformGetServiceID(mDNS
*const m
, DNSQuestion
*q
)
2198 mDNSexport
void mDNSPlatformSetDelegatePID(UDPSocket
*src
, const mDNSAddr
*dst
, DNSQuestion
*q
)
2205 mDNSexport mDNSs32
mDNSPlatformGetPID()
2210 mDNSexport mDNSu16
mDNSPlatformGetUDPPort(UDPSocket
*sock
)
2212 DEBUG_UNUSED( sock
);
2217 mDNSexport mDNSBool
mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID
)
2219 DEBUG_UNUSED( InterfaceID
);
2228 //===========================================================================================================================
2230 //===========================================================================================================================
2231 #if( MDNS_DEBUGMSGS )
2232 mDNSexport
void debugf_( const char *inFormat
, ... )
2238 va_start( args
, inFormat
);
2239 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2242 dlog( kDebugLevelInfo
, "%s\n", buffer
);
2246 //===========================================================================================================================
2248 //===========================================================================================================================
2250 #if( MDNS_DEBUGMSGS > 1 )
2251 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
2257 va_start( args
, inFormat
);
2258 length
= mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
2261 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
2268 #pragma mark == Platform Internals ==
2272 //===========================================================================================================================
2274 //===========================================================================================================================
2276 mStatus
SetupNiceName( mDNS
* const inMDNS
)
2278 HKEY descKey
= NULL
;
2282 NETSETUP_JOIN_STATUS joinStatus
;
2289 // Set up the nice name.
2292 // First try and open the registry key that contains the computer description value
2293 s
= TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
2294 err
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
, s
, 0, KEY_READ
, &descKey
);
2295 check_translated_errno( err
== 0, errno_compat(), kNameErr
);
2300 DWORD descSize
= sizeof( desc
);
2302 // look for the computer description
2303 err
= RegQueryValueEx( descKey
, TEXT("srvcomment"), 0, NULL
, (LPBYTE
) &desc
, &descSize
);
2307 err
= TCHARtoUTF8( desc
, utf8
, sizeof( utf8
) );
2316 // if we can't find it in the registry, then use the hostname of the machine
2317 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2319 TCHAR hostname
[256];
2321 namelen
= sizeof( hostname
) / sizeof( TCHAR
);
2323 ok
= GetComputerNameExW( ComputerNamePhysicalDnsHostname
, hostname
, &namelen
);
2324 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2329 err
= TCHARtoUTF8( hostname
, utf8
, sizeof( utf8
) );
2338 // if we can't get the hostname
2339 if ( err
|| ( utf8
[ 0 ] == '\0' ) )
2341 // Invalidate name so fall back to a default name.
2343 strcpy( utf8
, kMDNSDefaultName
);
2346 utf8
[ sizeof( utf8
) - 1 ] = '\0';
2347 inMDNS
->nicelabel
.c
[ 0 ] = (mDNSu8
) (strlen( utf8
) < MAX_DOMAIN_LABEL
? strlen( utf8
) : MAX_DOMAIN_LABEL
);
2348 memcpy( &inMDNS
->nicelabel
.c
[ 1 ], utf8
, inMDNS
->nicelabel
.c
[ 0 ] );
2350 dlog( kDebugLevelInfo
, DEBUG_NAME
"nice name \"%.*s\"\n", inMDNS
->nicelabel
.c
[ 0 ], &inMDNS
->nicelabel
.c
[ 1 ] );
2354 RegCloseKey( descKey
);
2357 ZeroMemory( inMDNS
->p
->nbname
, sizeof( inMDNS
->p
->nbname
) );
2358 ZeroMemory( inMDNS
->p
->nbdomain
, sizeof( inMDNS
->p
->nbdomain
) );
2360 namelen
= sizeof( inMDNS
->p
->nbname
);
2361 ok
= GetComputerNameExA( ComputerNamePhysicalNetBIOS
, inMDNS
->p
->nbname
, &namelen
);
2363 if ( ok
) dlog( kDebugLevelInfo
, DEBUG_NAME
"netbios name \"%s\"\n", inMDNS
->p
->nbname
);
2365 err
= NetGetJoinInformation( NULL
, &joinName
, &joinStatus
);
2366 check ( err
== NERR_Success
);
2367 if ( err
== NERR_Success
)
2369 if ( ( joinStatus
== NetSetupWorkgroupName
) || ( joinStatus
== NetSetupDomainName
) )
2371 err
= TCHARtoUTF8( joinName
, inMDNS
->p
->nbdomain
, sizeof( inMDNS
->p
->nbdomain
) );
2373 if ( !err
) dlog( kDebugLevelInfo
, DEBUG_NAME
"netbios domain/workgroup \"%s\"\n", inMDNS
->p
->nbdomain
);
2376 NetApiBufferFree( joinName
);
2385 //===========================================================================================================================
2387 //===========================================================================================================================
2389 mDNSlocal mStatus
SetupHostName( mDNS
* const inMDNS
)
2392 char tempString
[ 256 ];
2393 DWORD tempStringLen
;
2394 domainlabel tempLabel
;
2399 // Set up the nice name.
2400 tempString
[ 0 ] = '\0';
2402 // use the hostname of the machine
2403 tempStringLen
= sizeof( tempString
);
2404 ok
= GetComputerNameExA( ComputerNamePhysicalDnsHostname
, tempString
, &tempStringLen
);
2405 err
= translate_errno( ok
, (mStatus
) GetLastError(), kNameErr
);
2408 // if we can't get the hostname
2409 if( err
|| ( tempString
[ 0 ] == '\0' ) )
2411 // Invalidate name so fall back to a default name.
2413 strcpy( tempString
, kMDNSDefaultName
);
2416 tempString
[ sizeof( tempString
) - 1 ] = '\0';
2417 tempLabel
.c
[ 0 ] = (mDNSu8
) (strlen( tempString
) < MAX_DOMAIN_LABEL
? strlen( tempString
) : MAX_DOMAIN_LABEL
);
2418 memcpy( &tempLabel
.c
[ 1 ], tempString
, tempLabel
.c
[ 0 ] );
2420 // Set up the host name.
2422 ConvertUTF8PstringToRFC1034HostLabel( tempLabel
.c
, &inMDNS
->hostlabel
);
2423 if( inMDNS
->hostlabel
.c
[ 0 ] == 0 )
2425 // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
2427 MakeDomainLabelFromLiteralString( &inMDNS
->hostlabel
, kMDNSDefaultName
);
2430 check( inMDNS
->hostlabel
.c
[ 0 ] != 0 );
2432 mDNS_SetFQDN( inMDNS
);
2434 dlog( kDebugLevelInfo
, DEBUG_NAME
"host name \"%.*s\"\n", inMDNS
->hostlabel
.c
[ 0 ], &inMDNS
->hostlabel
.c
[ 1 ] );
2439 //===========================================================================================================================
2441 //===========================================================================================================================
2443 mDNSlocal mStatus
SetupName( mDNS
* const inMDNS
)
2449 err
= SetupNiceName( inMDNS
);
2452 err
= SetupHostName( inMDNS
);
2459 //===========================================================================================================================
2460 // SetupInterfaceList
2461 //===========================================================================================================================
2463 mStatus
SetupInterfaceList( mDNS
* const inMDNS
)
2466 mDNSInterfaceData
** next
;
2467 mDNSInterfaceData
* ifd
;
2468 struct ifaddrs
* addrs
;
2470 struct ifaddrs
* loopbackv4
;
2471 struct ifaddrs
* loopbackv6
;
2476 mDNSBool foundUnicastSock4DestAddr
;
2477 mDNSBool foundUnicastSock6DestAddr
;
2479 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list\n" );
2483 inMDNS
->p
->registeredLoopback4
= mDNSfalse
;
2484 inMDNS
->p
->nextDHCPLeaseExpires
= 0x7FFFFFFF;
2486 foundv4
= mDNSfalse
;
2487 foundv6
= mDNSfalse
;
2488 foundUnicastSock4DestAddr
= mDNSfalse
;
2489 foundUnicastSock6DestAddr
= mDNSfalse
;
2491 // Tear down any existing interfaces that may be set up.
2493 TearDownInterfaceList( inMDNS
);
2495 // Set up the name of this machine.
2497 err
= SetupName( inMDNS
);
2500 // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
2501 // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
2503 err
= getifaddrs( &addrs
);
2504 require_noerr( err
, exit
);
2508 next
= &inMDNS
->p
->interfaceList
;
2510 flagMask
= IFF_UP
| IFF_MULTICAST
;
2511 flagTest
= IFF_UP
| IFF_MULTICAST
;
2513 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2514 for( p
= addrs
; p
; p
= p
->ifa_next
)
2516 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2520 if( p
->ifa_flags
& IFF_LOOPBACK
)
2528 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2529 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2531 err
= SetupInterface( inMDNS
, p
, &ifd
);
2532 require_noerr( err
, exit
);
2534 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2535 // register him, but we also want to note that we haven't found a v4 interface
2536 // so that we register loopback so same host operations work
2538 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2543 if ( p
->ifa_dhcpEnabled
&& ( p
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2545 inMDNS
->p
->nextDHCPLeaseExpires
= p
->ifa_dhcpLeaseExpires
;
2548 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2549 // of determing the destination address of a packet that is sent to us.
2550 // For multicast packets, that's easy to determine. But for the unicast
2551 // sockets, we'll fake it by taking the address of the first interface
2552 // that is successfully setup.
2554 if ( !foundUnicastSock4DestAddr
)
2556 inMDNS
->p
->unicastSock4
.addr
= ifd
->interfaceInfo
.ip
;
2557 foundUnicastSock4DestAddr
= TRUE
;
2562 ++inMDNS
->p
->interfaceCount
;
2566 // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
2568 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2572 for( p
= addrs
; p
; p
= p
->ifa_next
)
2574 if( !p
->ifa_addr
|| ( p
->ifa_addr
->sa_family
!= AF_INET6
) || ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2578 if( p
->ifa_flags
& IFF_LOOPBACK
)
2586 dlog( kDebugLevelVerbose
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2587 p
->ifa_name
? p
->ifa_name
: "<null>", p
->ifa_extra
.index
, p
->ifa_addr
);
2589 err
= SetupInterface( inMDNS
, p
, &ifd
);
2590 require_noerr( err
, exit
);
2592 // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
2593 // register him, but we also want to note that we haven't found a v4 interface
2594 // so that we register loopback so same host operations work
2596 if ( ifd
->interfaceInfo
.McastTxRx
== mDNStrue
)
2601 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2602 // of determing the destination address of a packet that is sent to us.
2603 // For multicast packets, that's easy to determine. But for the unicast
2604 // sockets, we'll fake it by taking the address of the first interface
2605 // that is successfully setup.
2607 if ( !foundUnicastSock6DestAddr
)
2609 inMDNS
->p
->unicastSock6
.addr
= ifd
->interfaceInfo
.ip
;
2610 foundUnicastSock6DestAddr
= TRUE
;
2615 ++inMDNS
->p
->interfaceCount
;
2621 // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
2623 #if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
2625 flagMask
|= IFF_LOOPBACK
;
2626 flagTest
|= IFF_LOOPBACK
;
2628 for( p
= addrs
; p
; p
= p
->ifa_next
)
2630 if( !p
->ifa_addr
|| ( ( p
->ifa_flags
& flagMask
) != flagTest
) )
2634 if( ( p
->ifa_addr
->sa_family
!= AF_INET
) && ( p
->ifa_addr
->sa_family
!= AF_INET6
) )
2645 if ( !foundv4
&& loopbackv4
)
2647 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2648 loopbackv4
->ifa_name
? loopbackv4
->ifa_name
: "<null>", loopbackv4
->ifa_extra
.index
, loopbackv4
->ifa_addr
);
2650 err
= SetupInterface( inMDNS
, loopbackv4
, &ifd
);
2651 require_noerr( err
, exit
);
2653 inMDNS
->p
->registeredLoopback4
= mDNStrue
;
2655 #if( MDNS_WINDOWS_ENABLE_IPV4 )
2657 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2658 // of determing the destination address of a packet that is sent to us.
2659 // For multicast packets, that's easy to determine. But for the unicast
2660 // sockets, we'll fake it by taking the address of the first interface
2661 // that is successfully setup.
2663 if ( !foundUnicastSock4DestAddr
)
2665 inMDNS
->p
->unicastSock4
.addr
= ifd
->sock
.addr
;
2666 foundUnicastSock4DestAddr
= TRUE
;
2672 ++inMDNS
->p
->interfaceCount
;
2675 if ( !foundv6
&& loopbackv6
)
2677 dlog( kDebugLevelInfo
, DEBUG_NAME
"Interface %40s (0x%08X) %##a\n",
2678 loopbackv6
->ifa_name
? loopbackv6
->ifa_name
: "<null>", loopbackv6
->ifa_extra
.index
, loopbackv6
->ifa_addr
);
2680 err
= SetupInterface( inMDNS
, loopbackv6
, &ifd
);
2681 require_noerr( err
, exit
);
2683 #if( MDNS_WINDOWS_ENABLE_IPV6 )
2687 // If we're on a platform that doesn't have WSARecvMsg(), there's no way
2688 // of determing the destination address of a packet that is sent to us.
2689 // For multicast packets, that's easy to determine. But for the unicast
2690 // sockets, we'll fake it by taking the address of the first interface
2691 // that is successfully setup.
2693 if ( !foundUnicastSock6DestAddr
)
2695 inMDNS
->p
->unicastSock6
.addr
= ifd
->sock
.addr
;
2696 foundUnicastSock6DestAddr
= TRUE
;
2704 ++inMDNS
->p
->interfaceCount
;
2707 CheckFileShares( inMDNS
);
2712 TearDownInterfaceList( inMDNS
);
2716 freeifaddrs( addrs
);
2718 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface list done (err=%d %m)\n", err
, err
);
2722 //===========================================================================================================================
2723 // TearDownInterfaceList
2724 //===========================================================================================================================
2726 mStatus
TearDownInterfaceList( mDNS
* const inMDNS
)
2728 mDNSInterfaceData
** p
;
2729 mDNSInterfaceData
* ifd
;
2731 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list\n" );
2735 // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
2736 // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
2737 // so that remove events that occur after an interface goes away can still report the correct interface.
2739 p
= &inMDNS
->p
->inactiveInterfaceList
;
2743 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) ifd
) > 0 )
2749 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing unreferenced, inactive interface %#p %#a\n", ifd
, &ifd
->interfaceInfo
.ip
);
2752 QueueUserAPC( ( PAPCFUNC
) FreeInterface
, inMDNS
->p
->mainThread
, ( ULONG_PTR
) ifd
);
2755 // Tear down all the interfaces.
2757 while( inMDNS
->p
->interfaceList
)
2759 ifd
= inMDNS
->p
->interfaceList
;
2760 inMDNS
->p
->interfaceList
= ifd
->next
;
2762 TearDownInterface( inMDNS
, ifd
);
2764 inMDNS
->p
->interfaceCount
= 0;
2766 dlog( kDebugLevelTrace
, DEBUG_NAME
"tearing down interface list done\n" );
2767 return( mStatus_NoError
);
2770 //===========================================================================================================================
2772 //===========================================================================================================================
2774 mDNSlocal mStatus
SetupInterface( mDNS
* const inMDNS
, const struct ifaddrs
*inIFA
, mDNSInterfaceData
**outIFD
)
2776 mDNSInterfaceData
* ifd
;
2777 mDNSInterfaceData
* p
;
2781 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface\n" );
2785 check( inIFA
->ifa_addr
);
2788 // Allocate memory for the interface and initialize it.
2790 ifd
= (mDNSInterfaceData
*) calloc( 1, sizeof( *ifd
) );
2791 require_action( ifd
, exit
, err
= mStatus_NoMemoryErr
);
2792 ifd
->sock
.fd
= kInvalidSocketRef
;
2793 ifd
->sock
.ifd
= ifd
;
2794 ifd
->sock
.next
= NULL
;
2795 ifd
->sock
.m
= inMDNS
;
2796 ifd
->index
= inIFA
->ifa_extra
.index
;
2797 ifd
->scopeID
= inIFA
->ifa_extra
.index
;
2798 check( strlen( inIFA
->ifa_name
) < sizeof( ifd
->name
) );
2799 strncpy( ifd
->name
, inIFA
->ifa_name
, sizeof( ifd
->name
) - 1 );
2800 ifd
->name
[ sizeof( ifd
->name
) - 1 ] = '\0';
2802 strncpy(ifd
->interfaceInfo
.ifname
, inIFA
->ifa_name
, sizeof(ifd
->interfaceInfo
.ifname
));
2803 ifd
->interfaceInfo
.ifname
[sizeof(ifd
->interfaceInfo
.ifname
)-1] = 0;
2805 // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
2806 // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
2807 // on a large configured network, which means there's a good chance that most or all the other devices on that
2808 // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
2809 // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
2810 // devices on a large configured network, so we are willing to make that sacrifice.
2812 ifd
->interfaceInfo
.McastTxRx
= ( ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTTOPOINT
) ) ? mDNStrue
: mDNSfalse
;
2813 ifd
->interfaceInfo
.InterfaceID
= NULL
;
2815 for( p
= inMDNS
->p
->interfaceList
; p
; p
= p
->next
)
2817 if ( strcmp( p
->name
, ifd
->name
) == 0 )
2819 if (!ifd
->interfaceInfo
.InterfaceID
)
2821 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) p
;
2824 if ( ( inIFA
->ifa_addr
->sa_family
!= AF_INET
) &&
2825 ( p
->interfaceInfo
.ip
.type
== mDNSAddrType_IPv4
) &&
2826 ( p
->interfaceInfo
.ip
.ip
.v4
.b
[ 0 ] != 169 || p
->interfaceInfo
.ip
.ip
.v4
.b
[ 1 ] != 254 ) )
2828 ifd
->interfaceInfo
.McastTxRx
= mDNSfalse
;
2835 if ( !ifd
->interfaceInfo
.InterfaceID
)
2837 ifd
->interfaceInfo
.InterfaceID
= (mDNSInterfaceID
) ifd
;
2840 // Set up a socket for this interface (if needed).
2842 if( ifd
->interfaceInfo
.McastTxRx
)
2846 err
= SetupSocket( inMDNS
, inIFA
->ifa_addr
, MulticastDNSPort
, &ifd
->sock
.fd
);
2847 require_noerr( err
, exit
);
2848 ifd
->sock
.addr
= ( inIFA
->ifa_addr
->sa_family
== AF_INET6
) ? AllDNSLinkGroup_v6
: AllDNSLinkGroup_v4
;
2849 ifd
->sock
.port
= MulticastDNSPort
;
2851 // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
2853 err
= WSAIoctl( ifd
->sock
.fd
, SIO_GET_EXTENSION_FUNCTION_POINTER
, &kWSARecvMsgGUID
, sizeof( kWSARecvMsgGUID
), &ifd
->sock
.recvMsgPtr
, sizeof( ifd
->sock
.recvMsgPtr
), &size
, NULL
, NULL
);
2857 ifd
->sock
.recvMsgPtr
= NULL
;
2861 if ( inIFA
->ifa_dhcpEnabled
&& ( inIFA
->ifa_dhcpLeaseExpires
< inMDNS
->p
->nextDHCPLeaseExpires
) )
2863 inMDNS
->p
->nextDHCPLeaseExpires
= inIFA
->ifa_dhcpLeaseExpires
;
2866 ifd
->interfaceInfo
.NetWake
= inIFA
->ifa_womp
;
2868 // Register this interface with mDNS.
2870 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ifd
->interfaceInfo
.ip
, NULL
);
2871 require_noerr( err
, exit
);
2873 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &ifd
->interfaceInfo
.mask
, NULL
);
2874 require_noerr( err
, exit
);
2876 memcpy( ifd
->interfaceInfo
.MAC
.b
, inIFA
->ifa_physaddr
, sizeof( ifd
->interfaceInfo
.MAC
.b
) );
2878 ifd
->interfaceInfo
.Advertise
= ( mDNSu8
) inMDNS
->AdvertiseLocalAddresses
;
2880 if ( ifd
->sock
.fd
!= kInvalidSocketRef
)
2882 err
= mDNSPollRegisterSocket( ifd
->sock
.fd
, FD_READ
, UDPSocketNotification
, &ifd
->sock
);
2883 require_noerr( err
, exit
);
2886 // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
2887 // and skip the probe phase of the probe/announce packet sequence.
2888 ifd
->interfaceInfo
.DirectLink
= mDNSfalse
;
2890 err
= mDNS_RegisterInterface( inMDNS
, &ifd
->interfaceInfo
, mDNSfalse
);
2891 require_noerr( err
, exit
);
2892 ifd
->hostRegistered
= mDNStrue
;
2894 dlog( kDebugLevelInfo
, DEBUG_NAME
"Registered interface %##a with mDNS\n", inIFA
->ifa_addr
);
2905 TearDownInterface( inMDNS
, ifd
);
2907 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up interface done (err=%d %m)\n", err
, err
);
2911 //===========================================================================================================================
2912 // TearDownInterface
2913 //===========================================================================================================================
2915 mDNSlocal mStatus
TearDownInterface( mDNS
* const inMDNS
, mDNSInterfaceData
*inIFD
)
2920 // Deregister this interface with mDNS.
2922 dlog( kDebugLevelInfo
, DEBUG_NAME
"Deregistering interface %#a with mDNS\n", &inIFD
->interfaceInfo
.ip
);
2924 if( inIFD
->hostRegistered
)
2926 inIFD
->hostRegistered
= mDNSfalse
;
2927 mDNS_DeregisterInterface( inMDNS
, &inIFD
->interfaceInfo
, mDNSfalse
);
2930 // Tear down the multicast socket.
2932 UDPCloseSocket( &inIFD
->sock
);
2934 // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
2935 // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
2937 if( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) inIFD
) > 0 )
2939 inIFD
->next
= inMDNS
->p
->inactiveInterfaceList
;
2940 inMDNS
->p
->inactiveInterfaceList
= inIFD
;
2941 dlog( kDebugLevelInfo
, DEBUG_NAME
"deferring free of interface %#p %#a\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2945 dlog( kDebugLevelInfo
, DEBUG_NAME
"freeing interface %#p %#a immediately\n", inIFD
, &inIFD
->interfaceInfo
.ip
);
2946 QueueUserAPC( ( PAPCFUNC
) FreeInterface
, inMDNS
->p
->mainThread
, ( ULONG_PTR
) inIFD
);
2949 return( mStatus_NoError
);
2952 mDNSlocal
void CALLBACK
FreeInterface( mDNSInterfaceData
*inIFD
)
2957 //===========================================================================================================================
2959 //===========================================================================================================================
2961 mDNSlocal mStatus
SetupSocket( mDNS
* const inMDNS
, const struct sockaddr
*inAddr
, mDNSIPPort port
, SocketRef
*outSocketRef
)
2966 DWORD bytesReturned
= 0;
2967 BOOL behavior
= FALSE
;
2969 DEBUG_UNUSED( inMDNS
);
2971 dlog( kDebugLevelTrace
, DEBUG_NAME
"setting up socket %##a\n", inAddr
);
2973 check( outSocketRef
);
2975 // Set up an IPv4 or IPv6 UDP socket.
2977 sock
= socket( inAddr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
2978 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
2979 require_noerr( err
, exit
);
2981 // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
2982 // if we're creating a multicast socket
2984 if ( !mDNSIPPortIsZero( port
) )
2987 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &option
, sizeof( option
) );
2988 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
2991 // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
2993 // Not sure why, but the default behavior for sockets is to behave incorrectly
2994 // when using them in Overlapped I/O mode on XP. According to MSDN:
2996 // SIO_UDP_CONNRESET (opcode setting: I, T==3)
2997 // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
2998 // Set to FALSE to disable reporting.
3000 // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
3001 // messages were being sent to us after we sent out packets to a multicast address. This is clearly
3002 // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
3003 // will no longer receive any packets from that socket, which is not harmless. This behavior is only
3006 // So we turn off port unreachable reporting to make sure our sockets that are reading
3007 // multicast packets function correctly under all circumstances.
3009 err
= WSAIoctl( sock
, SIO_UDP_CONNRESET
, &behavior
, sizeof(behavior
), NULL
, 0, &bytesReturned
, NULL
, NULL
);
3010 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3012 if( inAddr
->sa_family
== AF_INET
)
3015 struct sockaddr_in sa4
;
3016 struct ip_mreq mreqv4
;
3018 // Bind the socket to the desired port
3020 ipv4
.NotAnInteger
= ( (const struct sockaddr_in
*) inAddr
)->sin_addr
.s_addr
;
3021 mDNSPlatformMemZero( &sa4
, sizeof( sa4
) );
3022 sa4
.sin_family
= AF_INET
;
3023 sa4
.sin_port
= port
.NotAnInteger
;
3024 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
3026 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
3027 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
3029 // Turn on option to receive destination addresses and receiving interface.
3032 err
= setsockopt( sock
, IPPROTO_IP
, IP_PKTINFO
, (char *) &option
, sizeof( option
) );
3033 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3035 if ( !mDNSIPPortIsZero( port
) )
3037 // Join the all-DNS multicast group so we receive Multicast DNS packets
3039 mreqv4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
3040 mreqv4
.imr_interface
.s_addr
= ipv4
.NotAnInteger
;
3041 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqv4
, sizeof( mreqv4
) );
3042 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3044 // Specify the interface to send multicast packets on this socket.
3046 sa4
.sin_addr
.s_addr
= ipv4
.NotAnInteger
;
3047 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &sa4
.sin_addr
, sizeof( sa4
.sin_addr
) );
3048 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3050 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3053 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3054 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3057 // Send unicast packets with TTL 255 (helps against spoofing).
3060 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &option
, sizeof( option
) );
3061 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3063 // Send multicast packets with TTL 255 (helps against spoofing).
3066 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &option
, sizeof( option
) );
3067 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3070 else if( inAddr
->sa_family
== AF_INET6
)
3072 struct sockaddr_in6
* sa6p
;
3073 struct sockaddr_in6 sa6
;
3074 struct ipv6_mreq mreqv6
;
3076 sa6p
= (struct sockaddr_in6
*) inAddr
;
3078 // Bind the socket to the desired port
3080 mDNSPlatformMemZero( &sa6
, sizeof( sa6
) );
3081 sa6
.sin6_family
= AF_INET6
;
3082 sa6
.sin6_port
= port
.NotAnInteger
;
3083 sa6
.sin6_flowinfo
= 0;
3084 sa6
.sin6_addr
= sa6p
->sin6_addr
;
3085 sa6
.sin6_scope_id
= sa6p
->sin6_scope_id
;
3087 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
3088 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
3090 // Turn on option to receive destination addresses and receiving interface.
3093 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &option
, sizeof( option
) );
3094 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3096 // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
3097 // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
3098 // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
3100 #if( defined( IPV6_V6ONLY ) )
3102 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &option
, sizeof( option
) );
3103 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3106 if ( !mDNSIPPortIsZero( port
) )
3108 // Join the all-DNS multicast group so we receive Multicast DNS packets.
3110 mreqv6
.ipv6mr_multiaddr
= *( (struct in6_addr
*) &AllDNSLinkGroup_v6
.ip
.v6
);
3111 mreqv6
.ipv6mr_interface
= sa6p
->sin6_scope_id
;
3112 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqv6
, sizeof( mreqv6
) );
3113 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3115 // Specify the interface to send multicast packets on this socket.
3117 option
= (int) sa6p
->sin6_scope_id
;
3118 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &option
, sizeof( option
) );
3119 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3121 // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
3124 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &option
, sizeof( option
) );
3125 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3128 // Send unicast packets with TTL 255 (helps against spoofing).
3131 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &option
, sizeof( option
) );
3132 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3134 // Send multicast packets with TTL 255 (helps against spoofing).
3137 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &option
, sizeof( option
) );
3138 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
3142 dlog( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inAddr
->sa_family
);
3143 err
= kUnsupportedErr
;
3149 *outSocketRef
= sock
;
3150 sock
= kInvalidSocketRef
;
3151 err
= mStatus_NoError
;
3154 if( IsValidSocket( sock
) )
3156 close_compat( sock
);
3161 //===========================================================================================================================
3163 //===========================================================================================================================
3165 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
, mDNSIPPort
*outPort
)
3172 if( inSA
->sa_family
== AF_INET
)
3174 struct sockaddr_in
* sa4
;
3176 sa4
= (struct sockaddr_in
*) inSA
;
3177 outIP
->type
= mDNSAddrType_IPv4
;
3178 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
3181 outPort
->NotAnInteger
= sa4
->sin_port
;
3183 err
= mStatus_NoError
;
3185 else if( inSA
->sa_family
== AF_INET6
)
3187 struct sockaddr_in6
* sa6
;
3189 sa6
= (struct sockaddr_in6
*) inSA
;
3190 outIP
->type
= mDNSAddrType_IPv6
;
3191 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
3192 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) )
3194 outIP
->ip
.v6
.w
[ 1 ] = 0;
3198 outPort
->NotAnInteger
= sa6
->sin6_port
;
3200 err
= mStatus_NoError
;
3204 dlog( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family %d", __ROUTINE__
, inSA
->sa_family
);
3205 err
= mStatus_BadParamErr
;
3215 //===========================================================================================================================
3216 // UDPSocketNotification
3217 //===========================================================================================================================
3219 mDNSlocal
void CALLBACK
3220 UDPSocketNotification( SOCKET sock
, LPWSANETWORKEVENTS event
, void *context
)
3222 UDPSocket
*udpSock
= ( UDPSocket
* ) context
;
3225 struct sockaddr_storage sockSrcAddr
; // This is filled in by the WSARecv* function
3226 INT sockSrcAddrLen
; // See above
3228 mDNSInterfaceID iid
;
3232 uint8_t controlBuffer
[ 128 ];
3238 DEBUG_UNUSED( sock
);
3239 DEBUG_UNUSED( event
);
3241 require_action( udpSock
!= NULL
, exit
, err
= mStatus_BadStateErr
);
3243 dlog( kDebugLevelChatty
, DEBUG_NAME
"%s: sock = %d\n", __ROUTINE__
, udpSock
->fd
);
3245 // Initialize the buffer structure
3247 wbuf
.buf
= (char *) &udpSock
->packet
;
3248 wbuf
.len
= (u_long
) sizeof( udpSock
->packet
);
3249 sockSrcAddrLen
= sizeof( sockSrcAddr
);
3255 if ( udpSock
->recvMsgPtr
)
3259 wmsg
.name
= ( LPSOCKADDR
) &sockSrcAddr
;
3260 wmsg
.namelen
= sockSrcAddrLen
;
3261 wmsg
.lpBuffers
= &wbuf
;
3262 wmsg
.dwBufferCount
= 1;
3263 wmsg
.Control
.buf
= ( CHAR
* ) controlBuffer
;
3264 wmsg
.Control
.len
= sizeof( controlBuffer
);
3267 err
= udpSock
->recvMsgPtr( udpSock
->fd
, &wmsg
, &size
, NULL
, NULL
);
3268 err
= translate_errno( ( err
== 0 ), (OSStatus
) WSAGetLastError(), kUnknownErr
);
3271 // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
3273 // There seems to be a bug in some network device drivers that involves calling WSARecvMsg().
3274 // Although all the parameters to WSARecvMsg() are correct, it returns a
3275 // WSAEFAULT error code when there is no actual error. We have found experientially that falling
3276 // back to using WSARecvFrom() when this happens will work correctly.
3278 if ( err
== WSAEFAULT
) udpSock
->recvMsgPtr
= NULL
;
3284 num
= WSARecvFrom( udpSock
->fd
, &wbuf
, 1, NULL
, &flags
, ( LPSOCKADDR
) &sockSrcAddr
, &sockSrcAddrLen
, NULL
, NULL
);
3285 err
= translate_errno( ( num
>= 0 ), ( OSStatus
) WSAGetLastError(), kUnknownErr
);
3288 // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
3290 // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
3291 // send operation resulted in an ICMP "Port Unreachable" message."
3293 // Because this is the case, we want to ignore this error and try again. Just in case
3294 // this is some kind of pathological condition, we'll break out of the retry loop
3295 // after 100 iterations
3297 require_action( !err
|| ( err
== WSAECONNRESET
) || ( err
== WSAEFAULT
), exit
, err
= WSAGetLastError() );
3299 while ( ( ( err
== WSAECONNRESET
) || ( err
== WSAEFAULT
) ) && ( numTries
++ < 100 ) );
3301 require_noerr( err
, exit
);
3303 // Translate the source of this packet into mDNS data types
3305 SockAddrToMDNSAddr( (struct sockaddr
* ) &sockSrcAddr
, &srcAddr
, &srcPort
);
3307 // Initialize the destination of this packet. Just in case
3308 // we can't determine this info because we couldn't call
3309 // WSARecvMsg (recvMsgPtr)
3311 dstAddr
= udpSock
->addr
;
3312 dstPort
= udpSock
->port
;
3314 if ( udpSock
->recvMsgPtr
)
3316 LPWSACMSGHDR header
;
3317 LPWSACMSGHDR last
= NULL
;
3320 // Parse the control information. Reject packets received on the wrong interface.
3322 // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
3324 // There seems to be an interaction between Bullguard and this next bit of code.
3325 // When a user's machine is running Bullguard, the control information that is
3326 // returned is corrupted, and the code would go into an infinite loop. We'll add
3327 // two bits of defensive coding here. The first will check that each pointer to
3328 // the LPWSACMSGHDR that is returned in the for loop is different than the last.
3329 // This fixes the problem with Bullguard. The second will break out of this loop
3330 // after 100 iterations, just in case the corruption isn't caught by the first
3333 for ( header
= WSA_CMSG_FIRSTHDR( &wmsg
); header
; header
= WSA_CMSG_NXTHDR( &wmsg
, header
) )
3335 if ( ( header
!= last
) && ( ++count
< 100 ) )
3339 if ( ( header
->cmsg_level
== IPPROTO_IP
) && ( header
->cmsg_type
== IP_PKTINFO
) )
3341 IN_PKTINFO
* ipv4PacketInfo
;
3343 ipv4PacketInfo
= (IN_PKTINFO
*) WSA_CMSG_DATA( header
);
3345 if ( udpSock
->ifd
!= NULL
)
3347 require_action( ipv4PacketInfo
->ipi_ifindex
== udpSock
->ifd
->index
, exit
, err
= ( DWORD
) kMismatchErr
);
3350 dstAddr
.type
= mDNSAddrType_IPv4
;
3351 dstAddr
.ip
.v4
.NotAnInteger
= ipv4PacketInfo
->ipi_addr
.s_addr
;
3353 else if( ( header
->cmsg_level
== IPPROTO_IPV6
) && ( header
->cmsg_type
== IPV6_PKTINFO
) )
3355 IN6_PKTINFO
* ipv6PacketInfo
;
3357 ipv6PacketInfo
= (IN6_PKTINFO
*) WSA_CMSG_DATA( header
);
3359 if ( udpSock
->ifd
!= NULL
)
3361 require_action( ipv6PacketInfo
->ipi6_ifindex
== ( udpSock
->ifd
->index
- kIPv6IfIndexBase
), exit
, err
= ( DWORD
) kMismatchErr
);
3364 dstAddr
.type
= mDNSAddrType_IPv6
;
3365 dstAddr
.ip
.v6
= *( (mDNSv6Addr
*) &ipv6PacketInfo
->ipi6_addr
);
3370 static BOOL loggedMessage
= FALSE
;
3372 if ( !loggedMessage
)
3374 LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
3375 loggedMessage
= TRUE
;
3383 dlog( kDebugLevelChatty
, DEBUG_NAME
"packet received\n" );
3384 dlog( kDebugLevelChatty
, DEBUG_NAME
" size = %d\n", num
);
3385 dlog( kDebugLevelChatty
, DEBUG_NAME
" src = %#a:%u\n", &srcAddr
, ntohs( srcPort
.NotAnInteger
) );
3386 dlog( kDebugLevelChatty
, DEBUG_NAME
" dst = %#a:%u\n", &dstAddr
, ntohs( dstPort
.NotAnInteger
) );
3388 if ( udpSock
->ifd
!= NULL
)
3390 dlog( kDebugLevelChatty
, DEBUG_NAME
" interface = %#a (index=0x%08X)\n", &udpSock
->ifd
->interfaceInfo
.ip
, udpSock
->ifd
->index
);
3393 dlog( kDebugLevelChatty
, DEBUG_NAME
"\n" );
3395 iid
= udpSock
->ifd
? udpSock
->ifd
->interfaceInfo
.InterfaceID
: NULL
;
3396 end
= ( (mDNSu8
*) &udpSock
->packet
) + num
;
3398 mDNSCoreReceive( udpSock
->m
, &udpSock
->packet
, end
, &srcAddr
, srcPort
, &dstAddr
, dstPort
, iid
);
3406 //===========================================================================================================================
3407 // InterfaceListDidChange
3408 //===========================================================================================================================
3409 void InterfaceListDidChange( mDNS
* const inMDNS
)
3413 dlog( kDebugLevelInfo
, DEBUG_NAME
"interface list changed\n" );
3416 // Tear down the existing interfaces and set up new ones using the new IP info.
3418 err
= TearDownInterfaceList( inMDNS
);
3421 err
= SetupInterfaceList( inMDNS
);
3424 err
= uDNS_SetupDNSConfig( inMDNS
);
3427 // Inform clients of the change.
3429 mDNS_ConfigChanged(inMDNS
);
3431 // Force mDNS to update.
3433 mDNSCoreMachineSleep( inMDNS
, mDNSfalse
); // What is this for? Mac OS X does not do this
3437 //===========================================================================================================================
3438 // ComputerDescriptionDidChange
3439 //===========================================================================================================================
3440 void ComputerDescriptionDidChange( mDNS
* const inMDNS
)
3442 dlog( kDebugLevelInfo
, DEBUG_NAME
"computer description has changed\n" );
3446 SetupNiceName( inMDNS
);
3450 //===========================================================================================================================
3451 // TCPIPConfigDidChange
3452 //===========================================================================================================================
3453 void TCPIPConfigDidChange( mDNS
* const inMDNS
)
3457 dlog( kDebugLevelInfo
, DEBUG_NAME
"TCP/IP config has changed\n" );
3460 err
= uDNS_SetupDNSConfig( inMDNS
);
3465 //===========================================================================================================================
3466 // DynDNSConfigDidChange
3467 //===========================================================================================================================
3468 void DynDNSConfigDidChange( mDNS
* const inMDNS
)
3472 dlog( kDebugLevelInfo
, DEBUG_NAME
"DynDNS config has changed\n" );
3475 SetDomainSecrets( inMDNS
);
3477 err
= uDNS_SetupDNSConfig( inMDNS
);
3482 //===========================================================================================================================
3483 // FileSharingDidChange
3484 //===========================================================================================================================
3485 void FileSharingDidChange( mDNS
* const inMDNS
)
3487 dlog( kDebugLevelInfo
, DEBUG_NAME
"File shares has changed\n" );
3490 CheckFileShares( inMDNS
);
3494 //===========================================================================================================================
3495 // FilewallDidChange
3496 //===========================================================================================================================
3497 void FirewallDidChange( mDNS
* const inMDNS
)
3499 dlog( kDebugLevelInfo
, DEBUG_NAME
"Firewall has changed\n" );
3502 CheckFileShares( inMDNS
);
3508 #pragma mark == Utilities ==
3511 //===========================================================================================================================
3513 //===========================================================================================================================
3515 mDNSlocal
int getifaddrs( struct ifaddrs
**outAddrs
)
3519 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3521 // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
3522 // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
3524 if( !gIPHelperLibraryInstance
)
3526 gIPHelperLibraryInstance
= LoadLibrary( TEXT( "Iphlpapi" ) );
3527 if( gIPHelperLibraryInstance
)
3529 gGetAdaptersAddressesFunctionPtr
=
3530 (GetAdaptersAddressesFunctionPtr
) GetProcAddress( gIPHelperLibraryInstance
, "GetAdaptersAddresses" );
3531 if( !gGetAdaptersAddressesFunctionPtr
)
3535 ok
= FreeLibrary( gIPHelperLibraryInstance
);
3536 check_translated_errno( ok
, GetLastError(), kUnknownErr
);
3537 gIPHelperLibraryInstance
= NULL
;
3542 // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
3543 // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
3544 // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
3546 if( !gGetAdaptersAddressesFunctionPtr
|| ( ( ( err
= getifaddrs_ipv6( outAddrs
) ) != mStatus_NoError
) || ( ( outAddrs
!= NULL
) && ( *outAddrs
== NULL
) ) ) )
3548 err
= getifaddrs_ipv4( outAddrs
);
3549 require_noerr( err
, exit
);
3554 err
= getifaddrs_ipv4( outAddrs
);
3555 require_noerr( err
, exit
);
3563 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
3564 //===========================================================================================================================
3566 //===========================================================================================================================
3568 mDNSlocal
int getifaddrs_ipv6( struct ifaddrs
**outAddrs
)
3573 struct ifaddrs
* head
;
3574 struct ifaddrs
** next
;
3575 IP_ADAPTER_ADDRESSES
* iaaList
;
3577 IP_ADAPTER_ADDRESSES
* iaa
;
3579 struct ifaddrs
* ifa
;
3581 check( gGetAdaptersAddressesFunctionPtr
);
3587 // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
3588 // This loops to handle the case where the interface changes in the window after getting the size, but before the
3589 // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
3591 flags
= GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME
;
3596 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, NULL
, &iaaListSize
);
3597 check( err
== ERROR_BUFFER_OVERFLOW
);
3598 check( iaaListSize
>= sizeof( IP_ADAPTER_ADDRESSES
) );
3600 iaaList
= (IP_ADAPTER_ADDRESSES
*) malloc( iaaListSize
);
3601 require_action( iaaList
, exit
, err
= ERROR_NOT_ENOUGH_MEMORY
);
3603 err
= gGetAdaptersAddressesFunctionPtr( AF_UNSPEC
, flags
, NULL
, iaaList
, &iaaListSize
);
3604 if( err
== ERROR_SUCCESS
) break;
3609 require( i
< 100, exit
);
3610 dlog( kDebugLevelWarning
, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__
, i
, err
, err
);
3613 for( iaa
= iaaList
; iaa
; iaa
= iaa
->Next
)
3616 IP_ADAPTER_UNICAST_ADDRESS
* addr
;
3618 IP_ADAPTER_PREFIX
* firstPrefix
;
3620 if( iaa
->IfIndex
> 0xFFFFFF )
3622 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->IfIndex
);
3624 if( iaa
->Ipv6IfIndex
> 0xFF )
3626 dlog( kDebugLevelAlert
, DEBUG_NAME
"%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__
, iaa
->Ipv6IfIndex
);
3629 // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
3630 // following code to crash when iterating through the prefix list. This seems
3631 // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
3632 // This shouldn't happen according to Microsoft docs which states:
3634 // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
3636 // So the data structure seems to be corrupted when we return from
3637 // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
3638 // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
3639 // modify iaa to have the correct values.
3641 if ( iaa
->Length
>= sizeof( IP_ADAPTER_ADDRESSES
) )
3643 ipv6IfIndex
= iaa
->Ipv6IfIndex
;
3644 firstPrefix
= iaa
->FirstPrefix
;
3652 // Skip pseudo and tunnel interfaces.
3654 if( ( ( ipv6IfIndex
== 1 ) && ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) ) || ( iaa
->IfType
== IF_TYPE_TUNNEL
) )
3659 // Add each address as a separate interface to emulate the way getifaddrs works.
3661 for( addrIndex
= 0, addr
= iaa
->FirstUnicastAddress
; addr
; ++addrIndex
, addr
= addr
->Next
)
3664 IP_ADAPTER_PREFIX
* prefix
;
3666 struct sockaddr_in ipv4Netmask
;
3668 family
= addr
->Address
.lpSockaddr
->sa_family
;
3669 if( ( family
!= AF_INET
) && ( family
!= AF_INET6
) ) continue;
3671 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3672 // Seems as if the problem here is a buggy implementation of some network interface
3673 // driver. It is reporting that is has a link-local address when it is actually
3674 // disconnected. This was causing a problem in AddressToIndexAndMask.
3675 // The solution is to call AddressToIndexAndMask first, and if unable to lookup
3676 // the address, to ignore that address.
3679 memset( &ipv4Netmask
, 0, sizeof( ipv4Netmask
) );
3681 if ( family
== AF_INET
)
3683 err
= AddressToIndexAndMask( addr
->Address
.lpSockaddr
, &ipv4Index
, ( struct sockaddr
* ) &ipv4Netmask
);
3692 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3693 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3696 next
= &ifa
->ifa_next
;
3700 size
= strlen( iaa
->AdapterName
) + 1;
3701 ifa
->ifa_name
= (char *) malloc( size
);
3702 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3703 memcpy( ifa
->ifa_name
, iaa
->AdapterName
, size
);
3705 // Get interface flags.
3708 if( iaa
->OperStatus
== IfOperStatusUp
) ifa
->ifa_flags
|= IFF_UP
;
3709 if( iaa
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) ifa
->ifa_flags
|= IFF_LOOPBACK
;
3710 else if ( IsPointToPoint( addr
) ) ifa
->ifa_flags
|= IFF_POINTTOPOINT
;
3711 if( !( iaa
->Flags
& IP_ADAPTER_NO_MULTICAST
) ) ifa
->ifa_flags
|= IFF_MULTICAST
;
3714 // <rdar://problem/4045657> Interface index being returned is 512
3716 // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
3717 // This code used to shift the IPv4 index up to ensure uniqueness between
3718 // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
3719 // then see interface indexes passed back that don't correspond to anything
3720 // that is seen in Win32 APIs or command line tools like "route". As a relatively
3721 // small percentage of developers are actively using IPv6, it seems to
3722 // make sense to make our use of IPv4 as confusion free as possible.
3723 // So now, IPv6 interface indexes will be shifted up by a
3724 // constant value which will serve to uniquely identify them, and we will
3725 // leave IPv4 interface indexes unmodified.
3729 case AF_INET
: ifa
->ifa_extra
.index
= iaa
->IfIndex
; break;
3730 case AF_INET6
: ifa
->ifa_extra
.index
= ipv6IfIndex
+ kIPv6IfIndexBase
; break;
3734 // Get lease lifetime
3736 if ( ( iaa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
) && ( addr
->LeaseLifetime
!= 0 ) && ( addr
->ValidLifetime
!= 0xFFFFFFFF ) )
3738 ifa
->ifa_dhcpEnabled
= TRUE
;
3739 ifa
->ifa_dhcpLeaseExpires
= time( NULL
) + addr
->ValidLifetime
;
3743 ifa
->ifa_dhcpEnabled
= FALSE
;
3744 ifa
->ifa_dhcpLeaseExpires
= 0;
3747 if ( iaa
->PhysicalAddressLength
== sizeof( ifa
->ifa_physaddr
) )
3749 memcpy( ifa
->ifa_physaddr
, iaa
->PhysicalAddress
, iaa
->PhysicalAddressLength
);
3752 // Because we don't get notified of womp changes, we're going to just assume
3753 // that all wired interfaces have it enabled. Before we go to sleep, we'll check
3754 // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
3757 ifa
->ifa_womp
= ( iaa
->IfType
== IF_TYPE_ETHERNET_CSMACD
) ? mDNStrue
: mDNSfalse
;
3765 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, (size_t) addr
->Address
.iSockaddrLength
);
3766 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
3767 memcpy( ifa
->ifa_addr
, addr
->Address
.lpSockaddr
, (size_t) addr
->Address
.iSockaddrLength
);
3773 check( ifa
->ifa_addr
);
3775 // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
3781 struct sockaddr_in
* sa4
;
3783 sa4
= (struct sockaddr_in
*) calloc( 1, sizeof( *sa4
) );
3784 require_action( sa4
, exit
, err
= WSAENOBUFS
);
3785 sa4
->sin_family
= AF_INET
;
3786 sa4
->sin_addr
.s_addr
= ipv4Netmask
.sin_addr
.s_addr
;
3788 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv4 mask = %s\n", __ROUTINE__
, inet_ntoa( sa4
->sin_addr
) );
3789 ifa
->ifa_netmask
= (struct sockaddr
*) sa4
;
3795 struct sockaddr_in6
*sa6
;
3796 char buf
[ 256 ] = { 0 };
3797 DWORD buflen
= sizeof( buf
);
3799 sa6
= (struct sockaddr_in6
*) calloc( 1, sizeof( *sa6
) );
3800 require_action( sa6
, exit
, err
= WSAENOBUFS
);
3801 sa6
->sin6_family
= AF_INET6
;
3802 memset( sa6
->sin6_addr
.s6_addr
, 0xFF, sizeof( sa6
->sin6_addr
.s6_addr
) );
3803 ifa
->ifa_netmask
= (struct sockaddr
*) sa6
;
3805 for ( prefix
= firstPrefix
; prefix
; prefix
= prefix
->Next
)
3808 IN6_ADDR maskedAddr
;
3812 // According to MSDN:
3813 // "On Windows Vista and later, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
3814 // include three IP adapter prefixes for each IP address assigned to the adapter. These include the host IP address prefix,
3815 // the subnet IP address prefix, and the subnet broadcast IP address prefix.
3816 // In addition, for each adapter there is a multicast address prefix and a broadcast address prefix.
3817 // On Windows XP with SP1 and later prior to Windows Vista, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
3818 // include only a single IP adapter prefix for each IP address assigned to the adapter."
3820 // We're only interested in the subnet IP address prefix. We'll determine if the prefix is the
3821 // subnet prefix by masking our address with a mask (computed from the prefix length) and see if that is the same
3822 // as the prefix address.
3824 if ( ( prefix
->PrefixLength
== 0 ) ||
3825 ( prefix
->PrefixLength
> 128 ) ||
3826 ( addr
->Address
.iSockaddrLength
!= prefix
->Address
.iSockaddrLength
) ||
3827 ( memcmp( addr
->Address
.lpSockaddr
, prefix
->Address
.lpSockaddr
, addr
->Address
.iSockaddrLength
) == 0 ) )
3834 memset( mask
.s6_addr
, 0, sizeof( mask
.s6_addr
) );
3836 for ( len
= (int) prefix
->PrefixLength
, maskIndex
= 0; len
> 0; len
-= 8 )
3838 uint8_t maskByte
= ( len
>= 8 ) ? 0xFF : (uint8_t)( ( 0xFFU
<< ( 8 - len
) ) & 0xFFU
);
3839 mask
.s6_addr
[ maskIndex
++ ] = maskByte
;
3844 for ( i
= 0; i
< 16; i
++ )
3846 maskedAddr
.s6_addr
[ i
] = ( ( struct sockaddr_in6
* ) addr
->Address
.lpSockaddr
)->sin6_addr
.s6_addr
[ i
] & mask
.s6_addr
[ i
];
3851 if ( memcmp( ( ( struct sockaddr_in6
* ) prefix
->Address
.lpSockaddr
)->sin6_addr
.s6_addr
, maskedAddr
.s6_addr
, sizeof( maskedAddr
.s6_addr
) ) == 0 )
3853 memcpy( sa6
->sin6_addr
.s6_addr
, mask
.s6_addr
, sizeof( mask
.s6_addr
) );
3858 WSAAddressToStringA( ( LPSOCKADDR
) sa6
, sizeof( struct sockaddr_in6
), NULL
, buf
, &buflen
);
3859 dlog( kDebugLevelInfo
, DEBUG_NAME
"%s: IPv6 mask = %s\n", __ROUTINE__
, buf
);
3877 err
= ERROR_SUCCESS
;
3882 freeifaddrs( head
);
3888 return( (int) err
);
3891 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
3893 //===========================================================================================================================
3895 //===========================================================================================================================
3897 mDNSlocal
int getifaddrs_ipv4( struct ifaddrs
**outAddrs
)
3903 INTERFACE_INFO
* buffer
;
3904 INTERFACE_INFO
* tempBuffer
;
3905 INTERFACE_INFO
* ifInfo
;
3908 struct ifaddrs
* head
;
3909 struct ifaddrs
** next
;
3910 struct ifaddrs
* ifa
;
3912 sock
= INVALID_SOCKET
;
3917 // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
3918 // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
3919 // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
3921 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3922 err
= translate_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
3923 require_noerr( err
, exit
);
3926 size
= 16 * sizeof( INTERFACE_INFO
);
3929 tempBuffer
= (INTERFACE_INFO
*) realloc( buffer
, size
);
3930 require_action( tempBuffer
, exit
, err
= WSAENOBUFS
);
3931 buffer
= tempBuffer
;
3933 err
= WSAIoctl( sock
, SIO_GET_INTERFACE_LIST
, NULL
, 0, buffer
, size
, &actualSize
, NULL
, NULL
);
3940 require_action( n
< 100, exit
, err
= WSAEADDRNOTAVAIL
);
3942 size
+= ( 16 * sizeof( INTERFACE_INFO
) );
3944 check( actualSize
<= size
);
3945 check( ( actualSize
% sizeof( INTERFACE_INFO
) ) == 0 );
3946 n
= (int)( actualSize
/ sizeof( INTERFACE_INFO
) );
3948 // Process the raw interface list and build a linked list of IPv4 interfaces.
3950 for( i
= 0; i
< n
; ++i
)
3953 struct sockaddr_in netmask
;
3955 ifInfo
= &buffer
[ i
];
3956 if( ifInfo
->iiAddress
.Address
.sa_family
!= AF_INET
)
3961 // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
3962 // See comment in getifaddrs_ipv6
3965 memset( &netmask
, 0, sizeof( netmask
) );
3966 err
= AddressToIndexAndMask( ( struct sockaddr
* ) &ifInfo
->iiAddress
.AddressIn
, &ifIndex
, ( struct sockaddr
* ) &netmask
);
3973 ifa
= (struct ifaddrs
*) calloc( 1, sizeof( struct ifaddrs
) );
3974 require_action( ifa
, exit
, err
= WSAENOBUFS
);
3977 next
= &ifa
->ifa_next
;
3981 ifa
->ifa_name
= (char *) malloc( 16 );
3982 require_action( ifa
->ifa_name
, exit
, err
= WSAENOBUFS
);
3983 sprintf( ifa
->ifa_name
, "%d", i
+ 1 );
3985 // Get interface flags.
3987 ifa
->ifa_flags
= (u_int
) ifInfo
->iiFlags
;
3991 if ( ifInfo
->iiAddress
.Address
.sa_family
== AF_INET
)
3993 struct sockaddr_in
* sa4
;
3995 sa4
= &ifInfo
->iiAddress
.AddressIn
;
3996 ifa
->ifa_addr
= (struct sockaddr
*) calloc( 1, sizeof( *sa4
) );
3997 require_action( ifa
->ifa_addr
, exit
, err
= WSAENOBUFS
);
3998 memcpy( ifa
->ifa_addr
, sa4
, sizeof( *sa4
) );
4000 ifa
->ifa_netmask
= (struct sockaddr
*) calloc(1, sizeof( *sa4
) );
4001 require_action( ifa
->ifa_netmask
, exit
, err
= WSAENOBUFS
);
4003 // <rdar://problem/4076478> Service won't start on Win2K. The address
4004 // family field was not being initialized.
4006 ifa
->ifa_netmask
->sa_family
= AF_INET
;
4007 ( ( struct sockaddr_in
* ) ifa
->ifa_netmask
)->sin_addr
= netmask
.sin_addr
;
4008 ifa
->ifa_extra
.index
= ifIndex
;
4012 // Emulate an interface index.
4014 ifa
->ifa_extra
.index
= (uint32_t)( i
+ 1 );
4031 freeifaddrs( head
);
4037 if( sock
!= INVALID_SOCKET
)
4039 closesocket( sock
);
4044 //===========================================================================================================================
4046 //===========================================================================================================================
4048 mDNSlocal
void freeifaddrs( struct ifaddrs
*inIFAs
)
4053 // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
4055 for( p
= inIFAs
; p
; p
= q
)
4061 free( p
->ifa_name
);
4066 free( p
->ifa_addr
);
4069 if( p
->ifa_netmask
)
4071 free( p
->ifa_netmask
);
4072 p
->ifa_netmask
= NULL
;
4074 if( p
->ifa_broadaddr
)
4076 free( p
->ifa_broadaddr
);
4077 p
->ifa_broadaddr
= NULL
;
4079 if( p
->ifa_dstaddr
)
4081 free( p
->ifa_dstaddr
);
4082 p
->ifa_dstaddr
= NULL
;
4086 free( p
->ifa_data
);
4094 //===========================================================================================================================
4095 // GetPrimaryInterface
4096 //===========================================================================================================================
4099 GetPrimaryInterface()
4101 PMIB_IPFORWARDTABLE pIpForwardTable
= NULL
;
4103 BOOL bOrder
= FALSE
;
4107 unsigned long int i
;
4109 // Find out how big our buffer needs to be.
4111 err
= GetIpForwardTable(NULL
, &dwSize
, bOrder
);
4112 require_action( err
== ERROR_INSUFFICIENT_BUFFER
, exit
, err
= kUnknownErr
);
4114 // Allocate the memory for the table
4116 pIpForwardTable
= (PMIB_IPFORWARDTABLE
) malloc( dwSize
);
4117 require_action( pIpForwardTable
, exit
, err
= kNoMemoryErr
);
4119 // Now get the table.
4121 err
= GetIpForwardTable(pIpForwardTable
, &dwSize
, bOrder
);
4122 require_noerr( err
, exit
);
4125 // Search for the row in the table we want.
4127 for ( i
= 0; i
< pIpForwardTable
->dwNumEntries
; i
++)
4129 // Look for a default route
4131 if ( pIpForwardTable
->table
[i
].dwForwardDest
== 0 )
4133 if ( index
&& ( pIpForwardTable
->table
[i
].dwForwardMetric1
>= metric
) )
4138 index
= pIpForwardTable
->table
[i
].dwForwardIfIndex
;
4139 metric
= pIpForwardTable
->table
[i
].dwForwardMetric1
;
4145 if ( pIpForwardTable
!= NULL
)
4147 free( pIpForwardTable
);
4154 //===========================================================================================================================
4155 // AddressToIndexAndMask
4156 //===========================================================================================================================
4159 AddressToIndexAndMask( struct sockaddr
* addr
, uint32_t * ifIndex
, struct sockaddr
* mask
)
4161 // Before calling AddIPAddress we use GetIpAddrTable to get
4162 // an adapter to which we can add the IP.
4164 PMIB_IPADDRTABLE pIPAddrTable
= NULL
;
4166 mStatus err
= mStatus_UnknownErr
;
4169 // For now, this is only for IPv4 addresses. That is why we can safely cast
4170 // addr's to sockaddr_in.
4172 require_action( addr
->sa_family
== AF_INET
, exit
, err
= mStatus_UnknownErr
);
4174 // Make an initial call to GetIpAddrTable to get the
4175 // necessary size into the dwSize variable
4177 for ( i
= 0; i
< 100; i
++ )
4179 err
= GetIpAddrTable( pIPAddrTable
, &dwSize
, 0 );
4181 if ( err
!= ERROR_INSUFFICIENT_BUFFER
)
4186 pIPAddrTable
= (MIB_IPADDRTABLE
*) realloc( pIPAddrTable
, dwSize
);
4187 require_action( pIPAddrTable
, exit
, err
= WSAENOBUFS
);
4190 require_noerr( err
, exit
);
4191 err
= mStatus_UnknownErr
;
4193 for ( i
= 0; i
< pIPAddrTable
->dwNumEntries
; i
++ )
4195 if ( ( ( struct sockaddr_in
* ) addr
)->sin_addr
.s_addr
== pIPAddrTable
->table
[i
].dwAddr
)
4197 *ifIndex
= pIPAddrTable
->table
[i
].dwIndex
;
4198 ( ( struct sockaddr_in
*) mask
)->sin_addr
.s_addr
= pIPAddrTable
->table
[i
].dwMask
;
4199 err
= mStatus_NoError
;
4208 free( pIPAddrTable
);
4215 //===========================================================================================================================
4216 // CanReceiveUnicast
4217 //===========================================================================================================================
4219 mDNSlocal mDNSBool
CanReceiveUnicast( void )
4223 struct sockaddr_in addr
;
4225 // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
4227 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4228 check_translated_errno( IsValidSocket( sock
), errno_compat(), kUnknownErr
);
4229 ok
= IsValidSocket( sock
);
4232 mDNSPlatformMemZero( &addr
, sizeof( addr
) );
4233 addr
.sin_family
= AF_INET
;
4234 addr
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4235 addr
.sin_addr
.s_addr
= htonl( INADDR_ANY
);
4237 ok
= ( bind( sock
, (struct sockaddr
*) &addr
, sizeof( addr
) ) == 0 );
4238 close_compat( sock
);
4241 dlog( kDebugLevelInfo
, DEBUG_NAME
"Unicast UDP responses %s\n", ok
? "okay" : "*not allowed*" );
4246 //===========================================================================================================================
4248 //===========================================================================================================================
4250 mDNSlocal mDNSBool
IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS
* addr
)
4252 struct ifaddrs
* addrs
= NULL
;
4253 struct ifaddrs
* p
= NULL
;
4255 mDNSBool ret
= mDNSfalse
;
4257 // For now, only works for IPv4 interfaces
4259 if ( addr
->Address
.lpSockaddr
->sa_family
== AF_INET
)
4261 // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
4263 err
= getifaddrs_ipv4( &addrs
);
4264 require_noerr( err
, exit
);
4266 for ( p
= addrs
; p
; p
= p
->ifa_next
)
4268 if ( ( addr
->Address
.lpSockaddr
->sa_family
== p
->ifa_addr
->sa_family
) &&
4269 ( ( ( struct sockaddr_in
* ) addr
->Address
.lpSockaddr
)->sin_addr
.s_addr
== ( ( struct sockaddr_in
* ) p
->ifa_addr
)->sin_addr
.s_addr
) )
4271 ret
= ( p
->ifa_flags
& IFF_POINTTOPOINT
) ? mDNStrue
: mDNSfalse
;
4281 freeifaddrs( addrs
);
4288 //===========================================================================================================================
4289 // GetWindowsVersionString
4290 //===========================================================================================================================
4292 mDNSlocal OSStatus
GetWindowsVersionString( char *inBuffer
, size_t inBufferSize
)
4294 #if( !defined( VER_PLATFORM_WIN32_CE ) )
4295 #define VER_PLATFORM_WIN32_CE 3
4299 OSVERSIONINFO osInfo
;
4301 const char * versionString
;
4307 versionString
= "unknown Windows version";
4309 osInfo
.dwOSVersionInfoSize
= sizeof( OSVERSIONINFO
);
4310 ok
= GetVersionEx( &osInfo
);
4311 err
= translate_errno( ok
, (OSStatus
) GetLastError(), kUnknownErr
);
4312 require_noerr( err
, exit
);
4314 platformID
= osInfo
.dwPlatformId
;
4315 majorVersion
= osInfo
.dwMajorVersion
;
4316 minorVersion
= osInfo
.dwMinorVersion
;
4317 buildNumber
= osInfo
.dwBuildNumber
& 0xFFFF;
4319 if( ( platformID
== VER_PLATFORM_WIN32_WINDOWS
) && ( majorVersion
== 4 ) )
4321 if( ( minorVersion
< 10 ) && ( buildNumber
== 950 ) )
4323 versionString
= "Windows 95";
4325 else if( ( minorVersion
< 10 ) && ( ( buildNumber
> 950 ) && ( buildNumber
<= 1080 ) ) )
4327 versionString
= "Windows 95 SP1";
4329 else if( ( minorVersion
< 10 ) && ( buildNumber
> 1080 ) )
4331 versionString
= "Windows 95 OSR2";
4333 else if( ( minorVersion
== 10 ) && ( buildNumber
== 1998 ) )
4335 versionString
= "Windows 98";
4337 else if( ( minorVersion
== 10 ) && ( ( buildNumber
> 1998 ) && ( buildNumber
< 2183 ) ) )
4339 versionString
= "Windows 98 SP1";
4341 else if( ( minorVersion
== 10 ) && ( buildNumber
>= 2183 ) )
4343 versionString
= "Windows 98 SE";
4345 else if( minorVersion
== 90 )
4347 versionString
= "Windows ME";
4350 else if( platformID
== VER_PLATFORM_WIN32_NT
)
4352 if( ( majorVersion
== 3 ) && ( minorVersion
== 51 ) )
4354 versionString
= "Windows NT 3.51";
4356 else if( ( majorVersion
== 4 ) && ( minorVersion
== 0 ) )
4358 versionString
= "Windows NT 4";
4360 else if( ( majorVersion
== 5 ) && ( minorVersion
== 0 ) )
4362 versionString
= "Windows 2000";
4364 else if( ( majorVersion
== 5 ) && ( minorVersion
== 1 ) )
4366 versionString
= "Windows XP";
4368 else if( ( majorVersion
== 5 ) && ( minorVersion
== 2 ) )
4370 versionString
= "Windows Server 2003";
4373 else if( platformID
== VER_PLATFORM_WIN32_CE
)
4375 versionString
= "Windows CE";
4379 if( inBuffer
&& ( inBufferSize
> 0 ) )
4382 strncpy( inBuffer
, versionString
, inBufferSize
);
4383 inBuffer
[ inBufferSize
] = '\0';
4389 //===========================================================================================================================
4391 //===========================================================================================================================
4394 RegQueryString( HKEY key
, LPCSTR valueName
, LPSTR
* string
, DWORD
* stringLen
, DWORD
* enabled
)
4400 *stringLen
= MAX_ESCAPED_DOMAIN_NAME
;
4411 *string
= (char*) malloc( *stringLen
);
4412 require_action( *string
, exit
, err
= mStatus_NoMemoryErr
);
4414 err
= RegQueryValueExA( key
, valueName
, 0, &type
, (LPBYTE
) *string
, stringLen
);
4418 while ( ( err
== ERROR_MORE_DATA
) && ( i
< 100 ) );
4420 require_noerr_quiet( err
, exit
);
4424 DWORD dwSize
= sizeof( DWORD
);
4426 err
= RegQueryValueEx( key
, TEXT("Enabled"), NULL
, NULL
, (LPBYTE
) enabled
, &dwSize
);
4438 //===========================================================================================================================
4440 //===========================================================================================================================
4442 mDNSlocal mStatus
StringToAddress( mDNSAddr
* ip
, LPSTR string
)
4444 struct sockaddr_in6 sa6
;
4445 struct sockaddr_in sa4
;
4449 sa6
.sin6_family
= AF_INET6
;
4450 dwSize
= sizeof( sa6
);
4452 err
= WSAStringToAddressA( string
, AF_INET6
, NULL
, (struct sockaddr
*) &sa6
, &dwSize
);
4454 if ( err
== mStatus_NoError
)
4456 err
= SetupAddr( ip
, (struct sockaddr
*) &sa6
);
4457 require_noerr( err
, exit
);
4461 sa4
.sin_family
= AF_INET
;
4462 dwSize
= sizeof( sa4
);
4464 err
= WSAStringToAddressA( string
, AF_INET
, NULL
, (struct sockaddr
*) &sa4
, &dwSize
);
4465 err
= translate_errno( err
== 0, WSAGetLastError(), kUnknownErr
);
4466 require_noerr( err
, exit
);
4468 err
= SetupAddr( ip
, (struct sockaddr
*) &sa4
);
4469 require_noerr( err
, exit
);
4478 //===========================================================================================================================
4480 //===========================================================================================================================
4482 mDNSlocal
struct ifaddrs
*
4483 myGetIfAddrs(int refresh
)
4485 static struct ifaddrs
*ifa
= NULL
;
4502 //===========================================================================================================================
4504 //===========================================================================================================================
4507 TCHARtoUTF8( const TCHAR
*inString
, char *inBuffer
, size_t inBufferSize
)
4509 #if( defined( UNICODE ) || defined( _UNICODE ) )
4513 len
= WideCharToMultiByte( CP_UTF8
, 0, inString
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4514 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4515 require_noerr( err
, exit
);
4520 return( WindowsLatin1toUTF8( inString
, inBuffer
, inBufferSize
) );
4525 //===========================================================================================================================
4526 // WindowsLatin1toUTF8
4527 //===========================================================================================================================
4530 WindowsLatin1toUTF8( const char *inString
, char *inBuffer
, size_t inBufferSize
)
4538 // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
4540 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, NULL
, 0 );
4541 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4542 require_noerr( err
, exit
);
4544 utf16
= (WCHAR
*) malloc( len
* sizeof( *utf16
) );
4545 require_action( utf16
, exit
, err
= kNoMemoryErr
);
4547 len
= MultiByteToWideChar( CP_ACP
, 0, inString
, -1, utf16
, len
);
4548 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4549 require_noerr( err
, exit
);
4551 // Now convert the temporary UTF-16 to UTF-8.
4553 len
= WideCharToMultiByte( CP_UTF8
, 0, utf16
, -1, inBuffer
, (int) inBufferSize
, NULL
, NULL
);
4554 err
= translate_errno( len
> 0, errno_compat(), kUnknownErr
);
4555 require_noerr( err
, exit
);
4558 if( utf16
) free( utf16
);
4563 //===========================================================================================================================
4565 //===========================================================================================================================
4568 TCPCloseSocket( TCPSocket
* sock
)
4570 dlog( kDebugLevelChatty
, DEBUG_NAME
"closing TCPSocket 0x%x:%d\n", sock
, sock
->fd
);
4572 if ( sock
->fd
!= INVALID_SOCKET
)
4574 closesocket( sock
->fd
);
4575 sock
->fd
= INVALID_SOCKET
;
4580 //===========================================================================================================================
4582 //===========================================================================================================================
4585 UDPCloseSocket( UDPSocket
* sock
)
4587 dlog( kDebugLevelChatty
, DEBUG_NAME
"closing UDPSocket %d\n", sock
->fd
);
4589 if ( sock
->fd
!= INVALID_SOCKET
)
4591 mDNSPollUnregisterSocket( sock
->fd
);
4592 closesocket( sock
->fd
);
4593 sock
->fd
= INVALID_SOCKET
;
4598 //===========================================================================================================================
4600 //===========================================================================================================================
4602 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
4604 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
4606 if (sa
->sa_family
== AF_INET
)
4608 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
4609 ip
->type
= mDNSAddrType_IPv4
;
4610 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
4611 return(mStatus_NoError
);
4614 if (sa
->sa_family
== AF_INET6
)
4616 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
4617 ip
->type
= mDNSAddrType_IPv6
;
4618 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.u
.Word
[1] = 0;
4619 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
4620 return(mStatus_NoError
);
4623 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
4624 return(mStatus_Invalid
);
4628 mDNSlocal
void GetDDNSFQDN( domainname
*const fqdn
)
4642 // Get info from Bonjour registry key
4644 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode
TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames
, &key
);
4645 require_noerr( err
, exit
);
4647 err
= RegQueryString( key
, "", &name
, &dwSize
, &enabled
);
4648 if ( !err
&& ( name
[0] != '\0' ) && enabled
)
4650 if ( !MakeDomainNameFromDNSNameString( fqdn
, name
) || !fqdn
->c
[0] )
4652 dlog( kDebugLevelError
, "bad DDNS host name in registry: %s", name
[0] ? name
: "(unknown)");
4673 mDNSlocal
void GetDDNSDomains( DNameListElem
** domains
, LPCWSTR lpSubKey
)
4675 mDNSlocal
void GetDDNSConfig( DNameListElem
** domains
, LPCSTR lpSubKey
)
4678 char subKeyName
[kRegistryMaxKeyLength
+ 1];
4695 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, lpSubKey
, &key
);
4696 require_noerr( err
, exit
);
4698 // Get information about this node
4700 err
= RegQueryInfoKey( key
, NULL
, NULL
, NULL
, &cSubKeys
, &cbMaxSubKey
, &cchMaxClass
, NULL
, NULL
, NULL
, NULL
, NULL
);
4701 require_noerr( err
, exit
);
4703 for ( i
= 0; i
< cSubKeys
; i
++)
4707 dwSize
= kRegistryMaxKeyLength
;
4709 err
= RegEnumKeyExA( key
, i
, subKeyName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
4713 err
= RegOpenKeyExA( key
, subKeyName
, 0, KEY_READ
, &subKey
);
4714 require_noerr( err
, exit
);
4716 dwSize
= sizeof( DWORD
);
4717 err
= RegQueryValueExA( subKey
, "Enabled", NULL
, NULL
, (LPBYTE
) &enabled
, &dwSize
);
4719 if ( !err
&& ( subKeyName
[0] != '\0' ) && enabled
)
4721 if ( !MakeDomainNameFromDNSNameString( &dname
, subKeyName
) || !dname
.c
[0] )
4723 dlog( kDebugLevelError
, "bad DDNS domain in registry: %s", subKeyName
[0] ? subKeyName
: "(unknown)");
4727 DNameListElem
* domain
= (DNameListElem
*) malloc( sizeof( DNameListElem
) );
4728 require_action( domain
, exit
, err
= mStatus_NoMemoryErr
);
4730 AssignDomainName(&domain
->name
, &dname
);
4731 domain
->next
= *domains
;
4737 RegCloseKey( subKey
);
4746 RegCloseKey( subKey
);
4756 mDNSlocal
void SetDomainSecret( mDNS
* const m
, const domainname
* inDomain
)
4758 char domainUTF8
[ 256 ];
4759 DomainAuthInfo
*foundInList
;
4760 DomainAuthInfo
*ptr
;
4761 char outDomain
[ 256 ];
4763 char outSecret
[ 256 ];
4766 ConvertDomainNameToCString( inDomain
, domainUTF8
);
4768 // If we're able to find a secret for this domain
4770 if ( LsaGetSecret( domainUTF8
, outDomain
, sizeof( outDomain
), outKey
, sizeof( outKey
), outSecret
, sizeof( outSecret
) ) )
4775 // Tell the core about this secret
4777 MakeDomainNameFromDNSNameString( &domain
, outDomain
);
4778 MakeDomainNameFromDNSNameString( &key
, outKey
);
4780 for (foundInList
= m
->AuthInfoList
; foundInList
; foundInList
= foundInList
->next
)
4781 if (SameDomainName(&foundInList
->domain
, &domain
) ) break;
4787 ptr
= (DomainAuthInfo
*)malloc(sizeof(DomainAuthInfo
));
4788 require_action( ptr
, exit
, err
= mStatus_NoMemoryErr
);
4791 err
= mDNS_SetSecretForDomain(m
, ptr
, &domain
, &key
, outSecret
, NULL
, NULL
, FALSE
);
4792 require_action( err
!= mStatus_BadParamErr
, exit
, if (!foundInList
) mDNSPlatformMemFree( ptr
) );
4794 debugf("Setting shared secret for zone %s with key %##s", outDomain
, key
.c
);
4803 mDNSlocal VOID CALLBACK
4804 CheckFileSharesProc( LPVOID arg
, DWORD dwTimerLowValue
, DWORD dwTimerHighValue
)
4806 mDNS
* const m
= ( mDNS
* const ) arg
;
4808 ( void ) dwTimerLowValue
;
4809 ( void ) dwTimerHighValue
;
4811 CheckFileShares( m
);
4815 mDNSlocal
unsigned __stdcall
4816 SMBRegistrationThread( void * arg
)
4818 mDNS
* const m
= ( mDNS
* const ) arg
;
4819 DNSServiceRef sref
= NULL
;
4820 HANDLE handles
[ 3 ];
4821 mDNSu8 txtBuf
[ 256 ];
4825 mDNSIPPort port
= { { SMBPortAsNumber
>> 8, SMBPortAsNumber
& 0xFF } };
4826 DNSServiceErrorType err
;
4828 DEBUG_UNUSED( arg
);
4830 handles
[ 0 ] = gSMBThreadStopEvent
;
4831 handles
[ 1 ] = gSMBThreadRegisterEvent
;
4832 handles
[ 2 ] = gSMBThreadDeregisterEvent
;
4834 memset( txtBuf
, 0, sizeof( txtBuf
) );
4836 keyLen
= strlen( "netbios=" );
4837 valLen
= strlen( m
->p
->nbname
);
4838 require_action( valLen
< 32, exit
, err
= kUnknownErr
); // This should never happen, but check to avoid further memory corruption
4839 *txtPtr
++ = ( mDNSu8
) ( keyLen
+ valLen
);
4840 memcpy( txtPtr
, "netbios=", keyLen
);
4842 if ( valLen
) { memcpy( txtPtr
, m
->p
->nbname
, valLen
); txtPtr
+= ( mDNSu8
) valLen
; }
4843 keyLen
= strlen( "domain=" );
4844 valLen
= strlen( m
->p
->nbdomain
);
4845 require_action( valLen
< 32, exit
, err
= kUnknownErr
); // This should never happen, but check to avoid further memory corruption
4846 *txtPtr
++ = ( mDNSu8
)( keyLen
+ valLen
);
4847 memcpy( txtPtr
, "domain=", keyLen
);
4849 if ( valLen
) { memcpy( txtPtr
, m
->p
->nbdomain
, valLen
); txtPtr
+= valLen
; }
4855 ret
= WaitForMultipleObjects( 3, handles
, FALSE
, INFINITE
);
4857 if ( ret
!= WAIT_FAILED
)
4859 if ( ret
== kSMBStopEvent
)
4863 else if ( ret
== kSMBRegisterEvent
)
4865 err
= gDNSServiceRegister( &sref
, 0, 0, NULL
, "_smb._tcp,_file", NULL
, NULL
, ( uint16_t ) port
.NotAnInteger
, ( mDNSu16
)( txtPtr
- txtBuf
), txtBuf
, NULL
, NULL
);
4869 LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err
);
4874 else if ( ret
== kSMBDeregisterEvent
)
4878 gDNSServiceRefDeallocate( sref
);
4885 LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
4894 gDNSServiceRefDeallocate( sref
);
4898 SetEvent( gSMBThreadQuitEvent
);
4905 CheckFileShares( mDNS
* const m
)
4907 PSHARE_INFO_1 bufPtr
= ( PSHARE_INFO_1
) NULL
;
4908 DWORD entriesRead
= 0;
4909 DWORD totalEntries
= 0;
4911 mDNSBool advertise
= mDNSfalse
;
4912 mDNSBool fileSharing
= mDNSfalse
;
4913 mDNSBool printSharing
= mDNSfalse
;
4921 // Only do this if we're not shutting down
4923 require_action_quiet( m
->AdvertiseLocalAddresses
&& !m
->ShutdownTime
, exit
, err
= kNoErr
);
4925 err
= RegCreateKey( HKEY_LOCAL_MACHINE
, kServiceParametersNode L
"\\Services\\SMB", &key
);
4929 DWORD dwSize
= sizeof( DWORD
);
4930 RegQueryValueEx( key
, L
"Advertise", NULL
, NULL
, (LPBYTE
) &advertise
, &dwSize
);
4933 if ( advertise
&& mDNSIsFileAndPrintSharingEnabled( &retry
) )
4935 dlog( kDebugLevelTrace
, DEBUG_NAME
"Sharing is enabled\n" );
4937 res
= NetShareEnum( NULL
, 1, ( LPBYTE
* )&bufPtr
, MAX_PREFERRED_LENGTH
, &entriesRead
, &totalEntries
, &resume
);
4939 if ( ( res
== ERROR_SUCCESS
) || ( res
== ERROR_MORE_DATA
) )
4941 PSHARE_INFO_1 p
= bufPtr
;
4944 for( i
= 0; i
< entriesRead
; i
++ )
4946 // We are only interested if the user is sharing anything other
4947 // than the built-in "print$" source
4949 if ( ( p
->shi1_type
== STYPE_DISKTREE
) && ( wcscmp( p
->shi1_netname
, TEXT( "print$" ) ) != 0 ) )
4951 fileSharing
= mDNStrue
;
4953 else if ( p
->shi1_type
== STYPE_PRINTQ
)
4955 printSharing
= mDNStrue
;
4961 NetApiBufferFree( bufPtr
);
4965 else if ( res
== NERR_ServerNotStarted
)
4974 LARGE_INTEGER liTimeout
;
4976 qwTimeout
= -m
->p
->checkFileSharesTimeout
* 10000000;
4977 liTimeout
.LowPart
= ( DWORD
)( qwTimeout
& 0xFFFFFFFF );
4978 liTimeout
.HighPart
= ( LONG
)( qwTimeout
>> 32 );
4980 SetWaitableTimer( m
->p
->checkFileSharesTimer
, &liTimeout
, 0, CheckFileSharesProc
, m
, FALSE
);
4983 if ( !m
->p
->smbFileSharing
&& fileSharing
)
4987 if ( !gDNSSDLibrary
)
4989 gDNSSDLibrary
= LoadLibrary( TEXT( "dnssd.dll" ) );
4990 require_action( gDNSSDLibrary
, exit
, err
= GetLastError() );
4993 if ( !gDNSServiceRegister
)
4995 gDNSServiceRegister
= ( DNSServiceRegisterFunc
) GetProcAddress( gDNSSDLibrary
, "DNSServiceRegister" );
4996 require_action( gDNSServiceRegister
, exit
, err
= GetLastError() );
4999 if ( !gDNSServiceRefDeallocate
)
5001 gDNSServiceRefDeallocate
= ( DNSServiceRefDeallocateFunc
) GetProcAddress( gDNSSDLibrary
, "DNSServiceRefDeallocate" );
5002 require_action( gDNSServiceRefDeallocate
, exit
, err
= GetLastError() );
5005 if ( !gSMBThreadRegisterEvent
)
5007 gSMBThreadRegisterEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5008 require_action( gSMBThreadRegisterEvent
!= NULL
, exit
, err
= GetLastError() );
5011 if ( !gSMBThreadDeregisterEvent
)
5013 gSMBThreadDeregisterEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5014 require_action( gSMBThreadDeregisterEvent
!= NULL
, exit
, err
= GetLastError() );
5017 if ( !gSMBThreadStopEvent
)
5019 gSMBThreadStopEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5020 require_action( gSMBThreadStopEvent
!= NULL
, exit
, err
= GetLastError() );
5023 if ( !gSMBThreadQuitEvent
)
5025 gSMBThreadQuitEvent
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
5026 require_action( gSMBThreadQuitEvent
!= NULL
, exit
, err
= GetLastError() );
5029 gSMBThread
= ( HANDLE
) _beginthreadex( NULL
, 0, SMBRegistrationThread
, m
, 0, NULL
);
5030 require_action( gSMBThread
!= NULL
, exit
, err
= GetLastError() );
5033 SetEvent( gSMBThreadRegisterEvent
);
5035 m
->p
->smbFileSharing
= mDNStrue
;
5037 else if ( m
->p
->smbFileSharing
&& !fileSharing
)
5039 dlog( kDebugLevelTrace
, DEBUG_NAME
"deregistering smb type\n" );
5041 if ( gSMBThreadDeregisterEvent
!= NULL
)
5043 SetEvent( gSMBThreadDeregisterEvent
);
5046 m
->p
->smbFileSharing
= mDNSfalse
;
5059 IsWOMPEnabled( mDNS
* const m
)
5063 mDNSInterfaceData
* ifd
;
5067 for( ifd
= m
->p
->interfaceList
; ifd
; ifd
= ifd
->next
)
5069 if ( IsWOMPEnabledForAdapter( ifd
->name
) )
5081 IsWOMPEnabledForAdapter( const char * adapterName
)
5086 HANDLE handle
= INVALID_HANDLE_VALUE
;
5087 NDIS_PNP_CAPABILITIES
* pNPC
= NULL
;
5091 require_action( adapterName
!= NULL
, exit
, ok
= FALSE
);
5093 dlog( kDebugLevelTrace
, DEBUG_NAME
"IsWOMPEnabledForAdapter: %s\n", adapterName
);
5095 // Construct a device name to pass to CreateFile
5097 strncpy_s( fileName
, sizeof( fileName
), DEVICE_PREFIX
, strlen( DEVICE_PREFIX
) );
5098 strcat_s( fileName
, sizeof( fileName
), adapterName
);
5099 handle
= CreateFileA( fileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, INVALID_HANDLE_VALUE
);
5100 require_action ( handle
!= INVALID_HANDLE_VALUE
, exit
, ok
= FALSE
);
5102 // We successfully opened the driver, format the IOCTL to pass the driver.
5104 oid
= OID_PNP_CAPABILITIES
;
5105 pNPC
= ( NDIS_PNP_CAPABILITIES
* ) malloc( sizeof( NDIS_PNP_CAPABILITIES
) );
5106 require_action( pNPC
!= NULL
, exit
, ok
= FALSE
);
5107 ok
= ( mDNSu8
) DeviceIoControl( handle
, IOCTL_NDIS_QUERY_GLOBAL_STATS
, &oid
, sizeof( oid
), pNPC
, sizeof( NDIS_PNP_CAPABILITIES
), &count
, NULL
);
5108 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
5109 require_action( !err
, exit
, ok
= FALSE
);
5110 ok
= ( mDNSu8
) ( ( count
== sizeof( NDIS_PNP_CAPABILITIES
) ) && ( pNPC
->Flags
& NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE
) );
5119 if ( handle
!= INVALID_HANDLE_VALUE
)
5121 CloseHandle( handle
);
5124 dlog( kDebugLevelTrace
, DEBUG_NAME
"IsWOMPEnabledForAdapter returns %s\n", ok
? "true" : "false" );
5126 return ( mDNSu8
) ok
;
5131 SendWakeupPacket( mDNS
* const inMDNS
, LPSOCKADDR addr
, INT addrlen
, const char * buf
, INT buflen
, INT numTries
, INT msecSleep
)
5133 mDNSBool repeat
= ( numTries
== 1 ) ? mDNStrue
: mDNSfalse
;
5140 sock
= socket( addr
->sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
5141 require_action( sock
!= INVALID_SOCKET
, exit
, err
= mStatus_UnknownErr
);
5143 while ( numTries
-- )
5145 num
= sendto( sock
, ( const char* ) buf
, buflen
, 0, addr
, addrlen
);
5147 if ( num
!= buflen
)
5149 LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num
, WSAGetLastError() );
5154 num
= sendto( sock
, buf
, buflen
, 0, addr
, addrlen
);
5156 if ( num
!= buflen
)
5158 LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num
, WSAGetLastError() );
5170 if ( sock
!= INVALID_SOCKET
)
5172 closesocket( sock
);
5177 mDNSlocal
void _cdecl
5178 SendMulticastWakeupPacket( void *arg
)
5180 MulticastWakeupStruct
*info
= ( MulticastWakeupStruct
* ) arg
;
5184 SendWakeupPacket( info
->inMDNS
, ( LPSOCKADDR
) &info
->addr
, sizeof( info
->addr
), ( const char* ) info
->data
, sizeof( info
->data
), info
->numTries
, info
->msecSleep
);
5192 mDNSexport
void FreeEtcHosts(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
5196 DEBUG_UNUSED( result
);