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