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