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