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