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