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