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