1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
24 Change History (most recent first):
26 $Log: mDNSMacOSX.c,v $
27 Revision 1.318 2005/10/20 00:10:34 cheshire
28 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
30 Revision 1.317 2005/09/24 01:10:26 cheshire
33 Revision 1.316 2005/07/29 18:04:22 ksekar
34 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
36 Revision 1.315 2005/07/22 21:50:55 ksekar
37 Fix GCC 4.0/Intel compiler warnings
39 Revision 1.314 2005/07/11 02:12:09 cheshire
40 <rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
41 Fix copy-and-paste error: "CFRelease(StatusVals[0]);" should be "CFRelease(StateVals[0]);"
43 Revision 1.313 2005/07/04 23:52:25 cheshire
44 <rdar://problem/3923098> Things are showing up with a bogus interface index
46 Revision 1.312 2005/07/04 22:24:36 cheshire
47 Export NotifyOfElusiveBug() so other files can call it
49 Revision 1.311 2005/06/15 13:20:43 cheshire
50 <rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
52 Revision 1.310 2005/04/07 00:49:58 cheshire
53 <rdar://problem/4080074> PPP connection disables Bonjour ".local" lookups
55 Revision 1.309 2005/03/23 05:53:29 cheshire
56 Fix %s where it should have been %##s in debugf & LogMsg calls
58 Revision 1.308 2005/03/09 00:48:44 cheshire
59 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
60 Move "m->p->NetworkChanged = 0;" line from caller to callee
62 Revision 1.307 2005/03/03 03:12:02 cheshire
63 Add comment about mDNSMacOSXSystemBuildNumber()
65 Revision 1.306 2005/03/02 22:18:00 cheshire
66 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
68 Revision 1.305 2005/02/26 05:08:28 cheshire
69 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
70 Added dnsinfo.h to project directory
72 Revision 1.304 2005/02/25 23:51:22 cheshire
73 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
74 Return mStatus_UnknownErr instead of -1
76 Revision 1.303 2005/02/25 17:47:45 ksekar
77 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
79 Revision 1.302 2005/02/25 02:34:14 cheshire
80 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
81 Show status as 1 (in progress) while we're trying
83 Revision 1.301 2005/02/24 21:55:57 ksekar
84 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
86 Revision 1.300 2005/02/15 20:03:13 ksekar
87 <rdar://problem/4005868> Crash when SCPreferences contains empty array
89 Revision 1.299 2005/02/15 02:46:53 cheshire
90 <rdar://problem/3967876> Don't log ENETUNREACH errors for unicast destinations
92 Revision 1.298 2005/02/10 00:41:59 cheshire
95 Revision 1.297 2005/02/09 23:38:51 ksekar
96 <rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
98 Revision 1.296 2005/02/01 21:06:52 ksekar
99 Avoid spurious log message
101 Revision 1.295 2005/02/01 19:33:30 ksekar
102 <rdar://problem/3985239> Keychain format too restrictive
104 Revision 1.294 2005/01/27 21:30:23 cheshire
105 <rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
106 Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
108 Revision 1.293 2005/01/27 19:15:41 cheshire
109 Remove extraneous LogMsg() call
111 Revision 1.292 2005/01/27 17:48:38 cheshire
112 Added comment about CFSocketInvalidate closing the underlying socket
114 Revision 1.291 2005/01/27 00:10:58 cheshire
115 <rdar://problem/3967867> Name change log messages every time machine boots
117 Revision 1.290 2005/01/25 23:18:30 ksekar
118 fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
120 Revision 1.289 2005/01/25 18:08:31 ksekar
121 Removed redundant debug output
123 Revision 1.288 2005/01/25 17:42:26 ksekar
124 Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
125 cleaned up duplicate log messages when adding/removing browse domains
127 Revision 1.287 2005/01/25 16:59:23 ksekar
128 <rdar://problem/3971138> sa_len not set checking reachability for TCP connections
130 Revision 1.286 2005/01/25 02:02:37 cheshire
131 <rdar://problem/3970673> mDNSResponder leaks
132 GetSearchDomains() was not calling dns_configuration_free().
134 Revision 1.285 2005/01/22 00:07:54 ksekar
135 <rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
137 Revision 1.284 2005/01/21 23:07:17 ksekar
138 <rdar://problem/3960795> mDNSResponder causes Dial on Demand
140 Revision 1.283 2005/01/19 21:16:16 cheshire
141 Make sure when we set NetworkChanged that we don't set it to zero
143 Revision 1.282 2005/01/19 19:19:21 ksekar
144 <rdar://problem/3960191> Need a way to turn off domain discovery
146 Revision 1.281 2005/01/18 18:10:55 ksekar
147 <rdar://problem/3954575> Use 10.4 resolver API to get search domains
149 Revision 1.280 2005/01/17 22:48:52 ksekar
150 No longer need to call MarkSearchListElem for registration domain
152 Revision 1.279 2005/01/17 20:40:34 ksekar
153 SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
155 Revision 1.278 2005/01/17 19:53:34 ksekar
156 Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
158 Revision 1.277 2005/01/12 00:17:50 ksekar
159 <rdar://problem/3933573> Update LLQs *after* setting DNS
161 Revision 1.276 2005/01/10 17:39:10 ksekar
162 Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
164 Revision 1.275 2005/01/10 04:02:22 ksekar
165 Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
167 Revision 1.274 2005/01/10 03:41:36 ksekar
168 Correction to checkin 1.272 - check that registration domain is set
169 before trying to remove it as an implicit browse domain
171 Revision 1.273 2005/01/08 00:42:18 ksekar
172 <rdar://problem/3922758> Clean up syslog messages
174 Revision 1.272 2005/01/07 23:21:42 ksekar
175 <rdar://problem/3891628> Clean up SCPreferences format
177 Revision 1.271 2004/12/20 23:18:12 cheshire
178 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
179 One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
181 Revision 1.270 2004/12/20 21:28:14 cheshire
182 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
183 Additional refinements to handle sleep/wake better
185 Revision 1.269 2004/12/20 20:48:11 cheshire
186 Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
188 Revision 1.268 2004/12/18 03:19:04 cheshire
189 Show netmask in error log
191 Revision 1.267 2004/12/18 00:51:52 cheshire
192 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
194 Revision 1.266 2004/12/17 23:49:38 cheshire
195 <rdar://problem/3922754> Computer Name change is slow
196 Also treat changes to "Setup:/Network/DynamicDNS" the same way
198 Revision 1.265 2004/12/17 23:37:47 cheshire
199 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
200 (and other repetitive configuration changes)
202 Revision 1.264 2004/12/17 19:03:05 cheshire
203 Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
205 Revision 1.263 2004/12/17 05:25:46 cheshire
206 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
208 Revision 1.262 2004/12/17 04:48:32 cheshire
209 <rdar://problem/3922754> Computer Name change is slow
211 Revision 1.261 2004/12/17 02:40:08 cheshire
212 Undo last change -- it was too strict
214 Revision 1.260 2004/12/16 22:17:16 cheshire
215 Only accept multicast packets on interfaces that have McastTxRx set
217 Revision 1.259 2004/12/16 20:13:01 cheshire
218 <rdar://problem/3324626> Cache memory management improvements
220 Revision 1.258 2004/12/14 00:18:05 cheshire
221 Don't log dns_configuration_copy() failures in the first three minutes after boot
223 Revision 1.257 2004/12/10 19:45:46 cheshire
224 <rdar://problem/3915074> Reduce egregious stack space usage
225 Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
227 Revision 1.256 2004/12/10 04:35:43 cheshire
228 <rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
230 Revision 1.255 2004/12/10 04:12:54 ksekar
231 <rdar://problem/3890764> Need new DefaultBrowseDomain key
233 Revision 1.254 2004/12/10 01:55:31 ksekar
234 <rdar://problem/3899067> Keychain lookups should be in lower case.
236 Revision 1.253 2004/12/09 03:15:41 ksekar
237 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
239 Revision 1.252 2004/12/07 01:32:42 cheshire
240 Don't log dns_configuration_copy() failure when running on 10.3
242 Revision 1.251 2004/12/06 22:30:31 cheshire
243 Added debugging log message
245 Revision 1.250 2004/12/06 06:59:08 ksekar
246 RegisterSplitDNS should return Unsupported error when compiled on Panther
248 Revision 1.249 2004/12/04 00:29:46 cheshire
249 Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
250 (When compiled on 10.3, code will not include split-DNS support.)
252 Revision 1.248 2004/12/01 20:57:20 ksekar
253 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
255 Revision 1.247 2004/12/01 03:26:58 cheshire
256 Remove unused variables
258 Revision 1.246 2004/12/01 01:51:34 cheshire
259 Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
261 Revision 1.245 2004/11/30 03:24:04 cheshire
262 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
264 Revision 1.244 2004/11/30 02:59:35 cheshire
265 For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
267 Revision 1.243 2004/11/29 19:17:29 ksekar
268 <rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
270 Revision 1.242 2004/11/29 18:37:38 ksekar
271 <rdar://problem/3889341> Buffer overflow in GetConfigOption
273 Revision 1.241 2004/11/25 01:37:04 ksekar
274 <rdar://problem/3894854> Config file and SCPreferences don't play well together
276 Revision 1.240 2004/11/25 01:29:42 ksekar
277 Remove unnecessary log messages
279 Revision 1.239 2004/11/25 01:27:19 ksekar
280 <rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
282 Revision 1.238 2004/11/24 22:00:59 cheshire
283 Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
285 Revision 1.237 2004/11/24 21:54:44 cheshire
286 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
288 Revision 1.236 2004/11/23 03:39:46 cheshire
289 Let interface name/index mapping capability live directly in JNISupport.c,
290 instead of having to call through to the daemon via IPC to get this information.
292 Revision 1.235 2004/11/17 01:45:35 cheshire
293 <rdar://problem/3847435> mDNS buddy list frequently becomes empty if you let the machine sleep
294 Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
295 in case we get no System Configuration Framework "network changed" event.
297 Revision 1.234 2004/11/17 00:32:56 ksekar
298 <rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
300 Revision 1.233 2004/11/12 03:16:45 rpantos
301 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
303 Revision 1.232 2004/11/10 20:40:54 ksekar
304 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
306 Revision 1.231 2004/11/06 00:59:33 ksekar
307 Don't log ENETDOWN errors for unicast destinations (pollutes log on
310 Revision 1.230 2004/11/05 01:04:10 ksekar
311 <rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
313 Revision 1.229 2004/11/03 03:45:16 cheshire
314 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
316 Revision 1.228 2004/11/02 23:47:32 cheshire
317 <rdar://problem/3863214> Default hostname and Computer Name should be unique
319 Revision 1.227 2004/11/02 04:23:03 cheshire
320 Change to more informative name "GetUserSpecifiedLocalHostName()"
322 Revision 1.226 2004/11/01 20:36:19 ksekar
323 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
325 Revision 1.225 2004/10/28 19:03:04 cheshire
326 Remove \n from LogMsg() calls
328 Revision 1.224 2004/10/28 17:47:34 cheshire
329 Oops. Forgot the %d in the log message.
331 Revision 1.223 2004/10/28 17:24:28 cheshire
332 Updated "bad ifa_netmask" log message to give more information
334 Revision 1.222 2004/10/28 03:36:34 cheshire
335 <rdar://problem/3856535> Share the same port for both multicast and unicast receiving
337 Revision 1.221 2004/10/28 03:24:41 cheshire
338 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
340 Revision 1.220 2004/10/28 00:53:57 cheshire
341 Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
342 Add LogOperation() call to record when we get network change events
344 Revision 1.219 2004/10/27 20:42:20 cheshire
345 Clean up debugging messages
347 Revision 1.218 2004/10/27 02:03:59 cheshire
348 Update debugging messages
350 Revision 1.217 2004/10/26 20:48:21 cheshire
351 Improve logging messages
353 Revision 1.216 2004/10/26 01:02:37 cheshire
356 Revision 1.215 2004/10/25 20:09:00 ksekar
357 Cleaned up config file parsing.
359 Revision 1.214 2004/10/25 19:30:53 ksekar
360 <rdar://problem/3827956> Simplify dynamic host name structures
362 Revision 1.213 2004/10/23 01:16:01 cheshire
363 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
365 Revision 1.212 2004/10/22 20:52:08 ksekar
366 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
368 Revision 1.211 2004/10/22 01:07:11 cheshire
369 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
370 Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
371 These are all supposed to be remapped to /dev/null
373 Revision 1.210 2004/10/20 02:19:54 cheshire
374 Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
376 Revision 1.209 2004/10/16 00:17:00 cheshire
377 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
379 Revision 1.208 2004/10/15 23:00:18 ksekar
380 <rdar://problem/3799242> Need to update LLQs on location changes
382 Revision 1.207 2004/10/13 22:45:23 cheshire
383 <rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
385 Revision 1.206 2004/10/13 22:11:46 cheshire
386 Update debugging messages
388 Revision 1.205 2004/10/12 21:10:11 cheshire
389 <rdar://problem/3438376> mach_absolute_time() not monotonically increasing
390 Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
392 Revision 1.204 2004/10/12 03:20:52 ksekar
393 <rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
395 Revision 1.203 2004/10/08 04:29:25 ksekar
396 <rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
398 Revision 1.202 2004/10/04 05:56:04 cheshire
399 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
401 Revision 1.201 2004/09/30 00:24:59 ksekar
402 <rdar://problem/3695802> Dynamically update default registration domains on config change
404 Revision 1.200 2004/09/26 23:20:35 ksekar
405 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
407 Revision 1.199 2004/09/24 23:54:55 cheshire
408 <rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
410 Revision 1.198 2004/09/24 23:47:49 cheshire
411 Correct comment and error message
413 Revision 1.197 2004/09/24 23:39:27 cheshire
414 <rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
416 Revision 1.196 2004/09/24 20:53:04 cheshire
417 Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
419 Revision 1.195 2004/09/24 19:21:45 cheshire
420 <rdar://problem/3671626> Report "Address already in use" errors
422 Revision 1.194 2004/09/24 19:16:54 cheshire
423 Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
424 Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
426 Revision 1.193 2004/09/22 00:41:59 cheshire
427 Move tcp connection status codes into the legal range allocated for mDNS use
429 Revision 1.192 2004/09/21 21:02:55 cheshire
430 Set up ifname before calling mDNS_RegisterInterface()
432 Revision 1.191 2004/09/21 19:19:36 cheshire
433 <rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
435 Revision 1.190 2004/09/21 19:04:45 cheshire
436 Strip trailing white space from the ends of lines
438 Revision 1.189 2004/09/21 00:13:28 cheshire
439 Fix build failure (io_connect_t and io_object_t are integers, not pointers)
441 Revision 1.188 2004/09/20 23:52:02 cheshire
442 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
444 Revision 1.187 2004/09/18 01:37:01 cheshire
447 Revision 1.186 2004/09/18 01:11:57 ksekar
448 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
450 Revision 1.185 2004/09/17 01:08:52 cheshire
451 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
452 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
453 declared in that file are ONLY appropriate to single-address-space embedded applications.
454 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
456 Revision 1.184 2004/09/17 00:19:10 cheshire
457 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
459 Revision 1.183 2004/09/17 00:15:56 cheshire
460 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
462 Revision 1.182 2004/09/16 21:36:36 cheshire
463 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
464 Changes to add necessary locking calls around unicast DNS operations
466 Revision 1.181 2004/09/16 02:03:42 cheshire
467 <rdar://problem/3802944> Change address to notify user of kernel flaw
469 Revision 1.180 2004/09/16 01:58:22 cheshire
470 Fix compiler warnings
472 Revision 1.179 2004/09/16 00:24:49 cheshire
473 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
475 Revision 1.178 2004/09/15 21:51:34 cheshire
476 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
477 Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
478 the machine, so make sure we don't do this until at least three minutes after boot.
480 Revision 1.177 2004/09/15 01:16:29 cheshire
481 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
483 Revision 1.176 2004/09/14 23:42:36 cheshire
484 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
486 Revision 1.175 2004/09/14 21:35:46 cheshire
487 Minor code tidying, and added comments about CFRetainCounts
489 Revision 1.174 2004/09/14 19:14:57 ksekar
490 <rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
492 Revision 1.173 2004/08/25 23:35:22 ksekar
493 <rdar://problem/3770615>: Error converting shared secret from base-64 to binary
495 Revision 1.172 2004/08/25 02:01:45 cheshire
496 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
498 Revision 1.171 2004/08/25 01:04:42 cheshire
499 Don't need to CFRelease name and array
501 Revision 1.170 2004/08/25 00:37:28 ksekar
502 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
504 Revision 1.169 2004/08/18 17:35:41 ksekar
505 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
507 Revision 1.168 2004/08/17 03:16:24 ksekar
508 Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
510 Revision 1.167 2004/08/17 00:52:43 ksekar
511 Fix config file parse error, make semantics match SCPreferences
514 Revision 1.166 2004/08/16 19:55:07 ksekar
515 Change enumeration type to BrowseDefault to construct empty-string
516 browse list as result of checking 1.161.
518 Revision 1.165 2004/08/16 19:52:40 ksekar
519 Pass computer name + zone for FQDN after keychain notification,
520 setting global default service registration domain to the zone.
522 Revision 1.164 2004/08/16 16:52:37 ksekar
523 Pass in zone read from keychain to mDNS_SetFQDNs.
525 Revision 1.163 2004/08/14 03:22:42 cheshire
526 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
527 Add GetUserSpecifiedDDNSName() routine
528 Convert ServiceRegDomain to domainname instead of C string
529 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
531 Revision 1.162 2004/08/12 22:34:00 cheshire
532 All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
534 Revision 1.161 2004/08/11 00:17:46 ksekar
535 <rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
536 set default bit for their domains
538 Revision 1.160 2004/07/29 19:27:16 ksekar
539 NATPMP Support - minor fixes and cleanup
541 Revision 1.159 2004/07/26 22:49:31 ksekar
542 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
544 Revision 1.158 2004/07/13 21:24:24 rpantos
545 Fix for <rdar://problem/3701120>.
547 Revision 1.157 2004/06/08 18:54:48 ksekar
548 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
550 Revision 1.156 2004/06/05 00:04:26 cheshire
551 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
553 Revision 1.155 2004/06/04 08:58:30 ksekar
554 <rdar://problem/3668624>: Keychain integration for secure dynamic update
556 Revision 1.154 2004/05/31 22:22:28 ksekar
557 <rdar://problem/3668639>: wide-area domains should be returned in
558 reg. domain enumeration
560 Revision 1.153 2004/05/26 17:06:33 cheshire
561 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
563 Revision 1.152 2004/05/18 23:51:26 cheshire
564 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
566 Revision 1.151 2004/05/17 21:46:34 cheshire
567 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
568 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
570 Revision 1.150 2004/05/13 04:54:20 ksekar
571 Unified list copy/free code. Added symetric list for
573 Revision 1.149 2004/05/13 03:55:14 ksekar
574 Fixed list traversal bug in FoundDefSearchDomain.
576 Revision 1.148 2004/05/12 22:03:08 ksekar
577 Made GetSearchDomainList a true platform-layer call (declaration moved
578 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
579 only on non-OSX platforms. Changed call to return a copy of the list
580 to avoid shared memory issues. Added a routine to free the list.
582 Revision 1.147 2004/05/12 02:03:25 ksekar
583 Non-local domains will only be browsed by default, and show up in
584 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
586 Revision 1.146 2004/04/27 02:49:15 cheshire
587 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
589 Revision 1.145 2004/04/21 03:08:03 cheshire
590 Rename 'alias' to more descriptive name 'primary'
592 Revision 1.144 2004/04/21 03:04:35 cheshire
593 Minor cleanup for clarity
595 Revision 1.143 2004/04/21 03:03:30 cheshire
596 Preparation work: AddInterfaceToList() should return pointer to structure it creates
598 Revision 1.142 2004/04/21 02:49:11 cheshire
599 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
601 Revision 1.141 2004/04/21 02:20:47 cheshire
602 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
604 Revision 1.140 2004/04/14 23:09:29 ksekar
605 Support for TSIG signed dynamic updates.
607 Revision 1.139 2004/04/09 17:40:26 cheshire
608 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
610 Revision 1.138 2004/04/09 16:37:16 cheshire
611 Suggestion from Bob Bradley:
612 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
614 Revision 1.137 2004/04/08 00:59:55 cheshire
615 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
616 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
618 Revision 1.136 2004/04/07 01:08:57 cheshire
619 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
621 Revision 1.135 2004/03/19 01:01:03 ksekar
622 Fixed config file parsing to chop newline
624 Revision 1.134 2004/03/13 01:57:34 ksekar
625 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
627 Revision 1.133 2004/02/02 22:46:56 cheshire
628 Move "CFRelease(dict);" inside the "if (dict)" check
630 Revision 1.132 2004/01/28 02:30:08 ksekar
631 Added default Search Domains to unicast browsing, controlled via
632 Networking sharing prefs pane. Stopped sending unicast messages on
633 every interface. Fixed unicast resolving via mach-port API.
635 Revision 1.131 2004/01/27 22:57:48 cheshire
636 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
638 Revision 1.130 2004/01/27 22:28:40 cheshire
639 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
640 Additional lingering port 53 code deleted
642 Revision 1.129 2004/01/27 20:15:23 cheshire
643 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
645 Revision 1.128 2004/01/24 23:58:17 cheshire
646 Change to use mDNSVal16() instead of shifting and ORing
648 Revision 1.127 2004/01/24 04:59:16 cheshire
649 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
651 Revision 1.126 2004/01/23 23:23:15 ksekar
652 Added TCP support for truncated unicast messages.
654 Revision 1.125 2004/01/22 03:43:09 cheshire
655 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
657 Revision 1.124 2004/01/21 21:53:19 cheshire
658 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
660 Revision 1.123 2004/01/20 03:18:25 cheshire
661 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
663 Revision 1.122 2003/12/17 20:43:59 cheshire
664 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
666 Revision 1.121 2003/12/13 03:05:28 ksekar
667 <rdar://problem/3192548>: DynDNS: Unicast query of service records
669 Revision 1.120 2003/12/08 21:00:46 rpantos
670 Changes to support mDNSResponder on Linux.
672 Revision 1.119 2003/12/03 02:35:15 cheshire
673 Also report value of m->timenow when logging sendto() failure
675 Revision 1.118 2003/11/14 20:59:09 cheshire
676 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
677 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
679 Revision 1.117 2003/11/08 22:18:29 cheshire
680 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
682 Revision 1.116 2003/09/23 16:39:49 cheshire
683 When LogAllOperations is set, also report registration and deregistration of interfaces
685 Revision 1.115 2003/09/10 00:45:55 cheshire
686 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
688 Revision 1.114 2003/08/27 02:55:13 cheshire
689 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
691 Revision 1.113 2003/08/19 22:20:00 cheshire
692 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
693 More minor refinements
695 Revision 1.112 2003/08/19 03:04:43 cheshire
696 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
698 Revision 1.111 2003/08/18 22:53:37 cheshire
699 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
701 Revision 1.110 2003/08/16 03:39:00 cheshire
702 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
704 Revision 1.109 2003/08/15 02:19:49 cheshire
705 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
706 Also limit number of messages to at most 100
708 Revision 1.108 2003/08/12 22:24:52 cheshire
709 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
710 This message indicates a kernel bug, but still we don't want to flood syslog.
711 Do a sleep(1) after writing this log message, to limit the rate.
713 Revision 1.107 2003/08/12 19:56:25 cheshire
716 Revision 1.106 2003/08/12 13:48:32 cheshire
717 Add comment explaining clockdivisor calculation
719 Revision 1.105 2003/08/12 13:44:14 cheshire
720 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
721 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
722 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
724 Revision 1.104 2003/08/12 13:12:07 cheshire
725 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
727 Revision 1.103 2003/08/08 18:36:04 cheshire
728 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
730 Revision 1.102 2003/08/06 00:14:52 cheshire
731 <rdar://problem/3330324> Need to check IP TTL on responses
732 Also add corresponding checks in the IPv6 code path
734 Revision 1.101 2003/08/05 22:20:16 cheshire
735 <rdar://problem/3330324> Need to check IP TTL on responses
737 Revision 1.100 2003/08/05 21:18:50 cheshire
738 <rdar://problem/3363185> mDNSResponder should ignore 6to4
739 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
741 Revision 1.99 2003/08/05 20:13:52 cheshire
742 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
743 Ignore interfaces with the IN6_IFF_NOTREADY flag set
745 Revision 1.98 2003/07/20 03:38:51 ksekar
746 <rdar://problem/3320722>
747 Completed support for Unix-domain socket based API.
749 Revision 1.97 2003/07/19 03:15:16 cheshire
750 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
751 and add the obvious trivial implementations to each platform support layer
753 Revision 1.96 2003/07/18 00:30:00 cheshire
754 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
756 Revision 1.95 2003/07/12 03:15:20 cheshire
757 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
758 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
760 Revision 1.94 2003/07/03 00:51:54 cheshire
761 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
763 Revision 1.93 2003/07/03 00:09:14 cheshire
764 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
765 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
767 Revision 1.92 2003/07/02 21:19:51 cheshire
768 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
770 Revision 1.91 2003/06/24 01:53:51 cheshire
771 Minor update to comments
773 Revision 1.90 2003/06/24 01:51:47 cheshire
774 <rdar://problem/3303118> Oops: Double-dispose of sockets
775 Don't need to close sockets: CFSocketInvalidate() does that for us
777 Revision 1.89 2003/06/21 18:12:47 cheshire
778 <rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
779 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
781 Revision 1.88 2003/06/12 23:38:37 cheshire
782 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
783 Also check that scope_id matches before concluding that two interfaces are the same
785 Revision 1.87 2003/06/10 01:14:11 cheshire
786 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
788 Revision 1.86 2003/05/28 02:41:52 cheshire
789 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
791 Revision 1.85 2003/05/28 02:39:47 cheshire
792 Minor change to debugging messages
794 Revision 1.84 2003/05/27 22:29:40 cheshire
795 Remove out-dated comment
797 Revision 1.83 2003/05/26 03:21:29 cheshire
798 Tidy up address structure naming:
799 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
800 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
801 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
803 Revision 1.82 2003/05/26 03:01:27 cheshire
804 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
806 Revision 1.81 2003/05/24 02:06:42 cheshire
807 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
808 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
809 However, it is probably wise to have the code explicitly set this socket
810 option anyway, in case the default changes in later versions of Unix.
812 Revision 1.80 2003/05/24 02:02:24 cheshire
813 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
814 Fix error in myIfIndexToName; was returning prematurely
816 Revision 1.79 2003/05/23 23:07:44 cheshire
817 <rdar://problem/3268199> Must not write to stderr when running as daemon
819 Revision 1.78 2003/05/23 01:19:04 cheshire
820 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
821 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
823 Revision 1.77 2003/05/23 01:12:05 cheshire
826 Revision 1.76 2003/05/22 01:26:01 cheshire
829 Revision 1.75 2003/05/22 00:07:09 cheshire
830 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
831 Extra logging to determine whether there is a bug in CFSocket
833 Revision 1.74 2003/05/21 20:20:12 cheshire
834 Fix warnings (mainly printf format string warnings, like using "%d" where
835 it should say "%lu", etc.) and improve error logging (use strerror()
836 to include textual error message as well as numeric error in log messages).
838 Revision 1.73 2003/05/21 17:56:29 ksekar
839 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
841 Revision 1.72 2003/05/14 18:48:41 cheshire
842 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
843 More minor refinements:
844 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
845 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
847 Revision 1.71 2003/05/14 07:08:37 cheshire
848 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
849 Previously, when there was any network configuration change, mDNSResponder
850 would tear down the entire list of active interfaces and start again.
851 That was very disruptive, and caused the entire cache to be flushed,
852 and caused lots of extra network traffic. Now it only removes interfaces
853 that have really gone, and only adds new ones that weren't there before.
855 Revision 1.70 2003/05/07 18:30:24 cheshire
856 Fix signed/unsigned comparison warning
858 Revision 1.69 2003/05/06 20:14:44 cheshire
861 Revision 1.68 2003/05/06 00:00:49 cheshire
862 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
864 Revision 1.67 2003/04/29 00:43:44 cheshire
865 Fix compiler warnings
867 Revision 1.66 2003/04/26 02:41:58 cheshire
868 <rdar://problem/3241281> Change timenow from a local variable to a structure member
870 Revision 1.65 2003/04/26 02:34:01 cheshire
871 Add missing mDNSexport
873 Revision 1.64 2003/04/15 16:48:06 jgraessl
874 <rdar://problem/3228833>
875 Modified code in CFSocket notifier function to read all packets on the socket
876 instead of reading only one packet every time the notifier was called.
878 Revision 1.63 2003/04/15 16:33:50 jgraessl
879 <rdar://problem/3221880>
880 Switched to our own copy of if_indextoname to improve performance.
882 Revision 1.62 2003/03/28 01:55:44 cheshire
883 Minor improvements to debugging messages
885 Revision 1.61 2003/03/27 03:30:56 cheshire
886 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
887 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
889 1. Make mDNS_DeregisterInterface() safe to call from a callback
890 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
891 (it never really needed to deregister the interface at all)
893 Revision 1.60 2003/03/15 04:40:38 cheshire
894 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
896 Revision 1.59 2003/03/11 01:23:26 cheshire
897 <rdar://problem/3194246> mDNSResponder socket problems
899 Revision 1.58 2003/03/06 01:43:04 cheshire
900 <rdar://problem/3189097> Additional debugging code in mDNSResponder
901 Improve "LIST_ALL_INTERFACES" output
903 Revision 1.57 2003/03/05 22:36:27 cheshire
904 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
905 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
907 Revision 1.56 2003/03/05 01:50:38 cheshire
908 <rdar://problem/3189097> Additional debugging code in mDNSResponder
910 Revision 1.55 2003/02/21 01:54:09 cheshire
911 <rdar://problem/3099194> mDNSResponder needs performance improvements
912 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
914 Revision 1.54 2003/02/20 06:48:35 cheshire
915 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
916 Reviewed by: Josh Graessley, Bob Bradley
918 Revision 1.53 2003/01/29 02:21:23 cheshire
919 Return mStatus_Invalid if can't send packet because socket not available
921 Revision 1.52 2003/01/28 19:39:43 jgraessl
922 Enabling AAAA over IPv4 support.
924 Revision 1.51 2003/01/28 05:11:23 cheshire
925 Fixed backwards comparison in SearchForInterfaceByName
927 Revision 1.50 2003/01/13 23:49:44 jgraessl
928 Merged changes for the following fixes in to top of tree:
929 <rdar://problem/3086540> computer name changes not handled properly
930 <rdar://problem/3124348> service name changes are not properly handled
931 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
933 Revision 1.49 2002/12/23 22:13:30 jgraessl
934 Reviewed by: Stuart Cheshire
935 Initial IPv6 support for mDNSResponder.
937 Revision 1.48 2002/11/22 01:37:52 cheshire
938 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
940 Revision 1.47 2002/09/21 20:44:51 zarzycki
943 Revision 1.46 2002/09/19 21:25:35 cheshire
944 mDNS_snprintf() doesn't need to be in a separate file
946 Revision 1.45 2002/09/17 01:45:13 cheshire
947 Add LIST_ALL_INTERFACES symbol for debugging
949 Revision 1.44 2002/09/17 01:36:23 cheshire
950 Move Puma support to mDNSMacOSXPuma.c
952 Revision 1.43 2002/09/17 01:05:28 cheshire
953 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
955 Revision 1.42 2002/09/16 23:13:50 cheshire
960 // ***************************************************************************
962 // Supporting routines to run mDNS on a CFRunLoop platform
963 // ***************************************************************************
965 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
966 // including ones that mDNSResponder chooses not to use.
967 #define LIST_ALL_INTERFACES 0
969 // For enabling AAAA records over IPv4. Setting this to 0 sends only
970 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
971 // AAAA and A records over both IPv4 and IPv6.
972 #define AAAA_OVER_V4 1
974 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
975 #include "DNSCommon.h"
976 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
977 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
978 #include "PlatformCommon.h"
981 #include <stdarg.h> // For va_list support
983 #include <net/if_types.h> // For IFT_ETHER
984 #include <net/if_dl.h>
986 #include <sys/param.h>
987 #include <sys/socket.h>
988 #include <sys/sysctl.h>
990 #include <sys/ioctl.h>
991 #include <time.h> // platform support for UTC time
992 #include <arpa/inet.h> // for inet_aton
994 #include <netinet/in.h> // For IP_RECVTTL
996 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
999 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
1000 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
1001 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
1003 #include <Security/Security.h>
1005 #include "dnsinfo.h"
1007 // Code contributed by Dave Heller:
1008 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
1009 // work on Mac OS X 10.1, which does not have the getifaddrs call.
1010 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
1011 #if RUN_ON_PUMA_WITHOUT_IFADDRS
1012 #include "mDNSMacOSXPuma.c"
1014 #include <ifaddrs.h>
1017 #include <IOKit/IOKitLib.h>
1018 #include <IOKit/IOMessage.h>
1019 #include <mach/mach_time.h>
1021 typedef struct SearchListElem
1023 struct SearchListElem
*next
;
1026 DNSQuestion BrowseQ
;
1027 DNSQuestion DefBrowseQ
;
1028 DNSQuestion LegacyBrowseQ
;
1029 DNSQuestion RegisterQ
;
1030 DNSQuestion DefRegisterQ
;
1031 ARListElem
*AuthRecs
;
1035 // ***************************************************************************
1038 static mDNSu32 clockdivisor
= 0;
1040 // for domain enumeration and default browsing/registration
1041 static SearchListElem
*SearchList
= NULL
; // where we search for _browse domains
1042 static DNSQuestion LegacyBrowseDomainQ
; // our local enumeration query for _legacy._browse domains
1043 static DNameListElem
*DefBrowseList
= NULL
; // cache of answers to above query (where we search for empty string browses)
1044 static DNameListElem
*DefRegList
= NULL
; // manually generated list of domains where we register for empty string registrations
1045 static ARListElem
*SCPrefBrowseDomains
= NULL
; // manually generated local-only PTR records for browse domains we get from SCPreferences
1047 static domainname DynDNSRegDomain
; // Default wide-area zone for service registration
1048 static CFArrayRef DynDNSBrowseDomains
= NULL
; // Default wide-area zones for legacy ("empty string") browses
1049 static domainname DynDNSHostname
;
1051 static mDNSBool DomainDiscoveryDisabled
= mDNSfalse
;
1053 #define CONFIG_FILE "/etc/mDNSResponder.conf"
1054 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
1055 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
1057 // Function Prototypes
1058 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
);
1060 // ***************************************************************************
1063 // routines to allow access to default domain lists from daemon layer
1065 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
1067 return mDNS_CopyDNameList(DefBrowseList
);
1070 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
1072 return mDNS_CopyDNameList(DefRegList
);
1075 // utility routines to manage registration domain lists
1077 mDNSlocal
void AddDefRegDomain(domainname
*d
)
1079 DNameListElem
*newelem
= NULL
, *ptr
;
1081 // make sure name not already in list
1082 for (ptr
= DefRegList
; ptr
; ptr
= ptr
->next
)
1084 if (SameDomainName(&ptr
->name
, d
))
1085 { debugf("duplicate addition of default reg domain %##s", d
->c
); return; }
1088 newelem
= mallocL("DNameListElem", sizeof(*newelem
));
1089 if (!newelem
) { LogMsg("Error - malloc"); return; }
1090 AssignDomainName(&newelem
->name
, d
);
1091 newelem
->next
= DefRegList
;
1092 DefRegList
= newelem
;
1094 DefaultRegDomainChanged(d
, mDNStrue
);
1095 udsserver_default_reg_domain_changed(d
, mDNStrue
);
1098 mDNSlocal
void RemoveDefRegDomain(domainname
*d
)
1100 DNameListElem
*ptr
= DefRegList
, *prev
= NULL
;
1104 if (SameDomainName(&ptr
->name
, d
))
1106 if (prev
) prev
->next
= ptr
->next
;
1107 else DefRegList
= ptr
->next
;
1108 freeL("DNameListElem", ptr
);
1109 DefaultRegDomainChanged(d
, mDNSfalse
);
1110 udsserver_default_reg_domain_changed(d
, mDNSfalse
);
1116 debugf("Requested removal of default registration domain %##s not in contained in list", d
->c
);
1119 mDNSexport
void NotifyOfElusiveBug(const char *title
, mDNSu32 radarid
, const char *msg
)
1121 static int notifyCount
= 0;
1122 if (notifyCount
) return;
1124 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1125 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1126 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
1128 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1131 // Determine if we're at Apple (17.*.*.*)
1132 extern mDNS mDNSStorage
;
1133 NetworkInterfaceInfoOSX
*i
;
1134 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
1135 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
1137 if (!i
) return; // If not at Apple, don't show the alert
1141 // Send a notification to the user to contact coreos-networking
1143 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
1144 CFStringRef alertFormat
= CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
1145 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, alertFormat
, radarid
, msg
);
1146 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
1149 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
1151 static struct ifaddrs
*ifa
= NULL
;
1159 if (ifa
== NULL
) getifaddrs(&ifa
);
1164 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
1166 NetworkInterfaceInfoOSX
*i
;
1167 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1168 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
1170 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1171 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1175 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
1177 struct ifaddrs
*ifa
;
1178 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
1179 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1180 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
1181 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
1185 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
1187 NetworkInterfaceInfoOSX
*i
;
1188 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
1190 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1191 // Don't get tricked by inactive interfaces with no InterfaceID set
1192 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
1196 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
1198 NetworkInterfaceInfoOSX
*i
;
1199 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
1201 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1202 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1203 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
1207 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
1209 mDNSBool result
= mDNSfalse
;
1210 SCNetworkConnectionFlags flags
;
1211 SCNetworkReachabilityRef ReachRef
= NULL
;
1213 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
1214 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
1215 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
1216 result
= flags
& kSCNetworkFlagsConnectionRequired
;
1219 if (ReachRef
) CFRelease(ReachRef
);
1223 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1224 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1225 // OR send via our primary v4 unicast socket
1226 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1227 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
1231 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1232 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1233 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1234 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
1235 char *ifa_name
= info
? info
->ifa_name
: "unicast";
1236 struct sockaddr_storage to
;
1239 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
1240 // anonymous socket created for this purpose, so that we'll receive the response.
1241 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
1242 if (info
&& !mDNSAddrIsDNSMulticast(dst
))
1244 const DNSMessage
*const m
= (DNSMessage
*)msg
;
1245 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
1246 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
1249 if (dst
->type
== mDNSAddrType_IPv4
)
1251 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1252 sin_to
->sin_len
= sizeof(*sin_to
);
1253 sin_to
->sin_family
= AF_INET
;
1254 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1255 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1256 s
= info
? info
->ss
.sktv4
: m
->p
->unicastsockets
.sktv4
;
1258 else if (dst
->type
== mDNSAddrType_IPv6
)
1260 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1261 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1262 sin6_to
->sin6_family
= AF_INET6
;
1263 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1264 sin6_to
->sin6_flowinfo
= 0;
1265 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1266 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1267 s
= info
? info
->ss
.sktv6
: m
->p
->unicastsockets
.sktv6
;
1271 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1272 return mStatus_BadParamErr
;
1275 // Don't send if it would cause dial on demand connection initiation. As an optimization,
1276 // don't bother consulting reachability API / routing table when sending Multicast DNS
1277 // since we ignore PPP interfaces for mDNS traffic
1278 if (!mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
1280 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1281 return mStatus_NoError
;
1285 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1286 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1288 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1289 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1291 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1292 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1293 if (s
< 0) return(mStatus_Invalid
);
1295 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1298 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1299 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1300 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1301 // Don't report EHOSTUNREACH in the first three minutes after boot
1302 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1303 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1304 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1305 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1306 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1307 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1308 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1309 return(mStatus_UnknownErr
);
1312 return(mStatus_NoError
);
1315 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1316 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1318 static unsigned int numLogMessages
= 0;
1319 struct iovec databuffers
= { (char *)buffer
, max
};
1322 struct cmsghdr
*cmPtr
;
1323 char ancillary
[1024];
1325 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1327 // Set up the message
1328 msg
.msg_name
= (caddr_t
)from
;
1329 msg
.msg_namelen
= *fromlen
;
1330 msg
.msg_iov
= &databuffers
;
1332 msg
.msg_control
= (caddr_t
)&ancillary
;
1333 msg
.msg_controllen
= sizeof(ancillary
);
1337 n
= recvmsg(s
, &msg
, 0);
1340 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1343 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1345 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1346 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1349 if (msg
.msg_flags
& MSG_CTRUNC
)
1351 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1355 *fromlen
= msg
.msg_namelen
;
1357 // Parse each option out of the ancillary data.
1358 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1360 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1361 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1363 dstaddr
->type
= mDNSAddrType_IPv4
;
1364 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
1366 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1368 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1369 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1371 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
1372 ifname
[sdl
->sdl_nlen
] = 0;
1373 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1376 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1378 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1380 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1382 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1383 dstaddr
->type
= mDNSAddrType_IPv6
;
1384 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1385 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1387 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1389 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1396 // On entry, context points to our CFSocketSet
1397 // If ss->info is NULL, we received this packet on our anonymous unicast socket
1398 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
1399 mDNSlocal
void myCFSocketCallBack(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
1401 const CFSocketSet
*const ss
= (const CFSocketSet
*)context
;
1402 mDNS
*const m
= ss
->m
;
1403 const int skt
= CFSocketGetNative(cfs
);
1404 const int s1
= (cfs
== ss
->cfsv4
) ? ss
->sktv4
: (cfs
== ss
->cfsv6
) ? ss
->sktv6
: -1;
1407 (void)address
; // Parameter not used
1408 (void)data
; // Parameter not used
1410 if (CallBackType
!= kCFSocketReadCallBack
)
1411 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
1413 if (s1
< 0 || s1
!= skt
)
1415 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
1416 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss
->cfsv4
, ss
->sktv4
);
1417 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss
->cfsv6
, ss
->sktv6
);
1422 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1423 mDNSInterfaceID InterfaceID
= ss
->info
? ss
->info
->ifinfo
.InterfaceID
: mDNSNULL
;
1424 mDNSAddr senderAddr
, destAddr
;
1425 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1426 struct sockaddr_storage from
;
1427 size_t fromlen
= sizeof(from
);
1428 char packetifname
[IF_NAMESIZE
] = "";
1430 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1434 if (from
.ss_family
== AF_INET
)
1436 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1437 senderAddr
.type
= mDNSAddrType_IPv4
;
1438 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1439 senderPort
.NotAnInteger
= sin
->sin_port
;
1441 else if (from
.ss_family
== AF_INET6
)
1443 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1444 senderAddr
.type
= mDNSAddrType_IPv6
;
1445 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1446 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1450 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
1454 if (mDNSAddrIsDNSMulticast(&destAddr
))
1456 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
1457 // sockets API means that even though this socket has only officially joined the multicast group
1458 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1459 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1460 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
1461 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1462 if (!ss
->info
|| !ss
->info
->Exists
)
1464 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr
, &destAddr
);
1467 else if (strcmp(ss
->info
->ifa_name
, packetifname
))
1469 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
1470 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
, packetifname
);
1474 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
1475 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
);
1479 // Note: Unicast packets are delivered to *one* of our listening sockets,
1480 // not necessarily the one bound to the physical interface where the packet arrived.
1481 // To sort this out we search our interface list and update InterfaceID to reference
1482 // the mDNSCore interface object for the interface where the packet was actually received.
1483 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1484 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1485 if (intf
) InterfaceID
= intf
->InterfaceID
;
1488 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1491 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1493 // Something is busted here.
1494 // CFSocket says there is a packet, but myrecvfrom says there is not.
1495 // Try calling select() to get another opinion.
1496 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1497 // All of this is racy, as data may have arrived after the call to select()
1498 int save_errno
= errno
;
1502 socklen_t solen
= sizeof(int);
1505 FD_SET(s1
, &readfds
);
1506 struct timeval timeout
;
1508 timeout
.tv_usec
= 0;
1509 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1510 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1511 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1512 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1513 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1514 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1515 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
1516 static unsigned int numLogMessages
= 0;
1517 if (numLogMessages
++ < 100)
1518 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1519 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1520 if (numLogMessages
> 5)
1521 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
1522 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1523 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1525 sleep(1); // After logging this error, rate limit so we don't flood syslog
1529 // TCP socket support for unicast DNS and Dynamic DNS Update
1533 TCPConnectionCallback callback
;
1538 mDNSlocal
void tcpCFSocketCallback(CFSocketRef cfs
, CFSocketCallBackType CallbackType
, CFDataRef address
,
1539 const void *data
, void *context
)
1541 #pragma unused(CallbackType, address, data)
1542 mDNSBool connect
= mDNSfalse
;
1544 tcpInfo_t
*info
= context
;
1545 if (!info
->connected
)
1548 info
->connected
= mDNStrue
; // prevent connected flag from being set in future callbacks
1550 info
->callback(CFSocketGetNative(cfs
), info
->context
, connect
);
1551 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1554 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1555 TCPConnectionCallback callback
, void *context
, int *descriptor
)
1557 int sd
, on
= 1; // "on" for setsockopt
1558 struct sockaddr_in saddr
;
1559 CFSocketContext cfContext
= { 0, NULL
, 0, 0, 0 };
1562 CFRunLoopSourceRef rls
;
1564 (void)InterfaceID
; //!!!KRS use this if non-zero!!!
1567 if (dst
->type
!= mDNSAddrType_IPv4
)
1569 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1570 return mStatus_UnknownErr
;
1573 bzero(&saddr
, sizeof(saddr
));
1574 saddr
.sin_family
= AF_INET
;
1575 saddr
.sin_port
= dstport
.NotAnInteger
;
1576 saddr
.sin_len
= sizeof(saddr
);
1577 memcpy(&saddr
.sin_addr
, &dst
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1579 // Don't send if it would cause dial on demand connection initiation.
1580 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1582 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1583 return mStatus_UnknownErr
;
1586 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1587 if (sd
< 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd
, errno
, strerror(errno
)); return mStatus_UnknownErr
; }
1590 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
1592 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1593 return mStatus_UnknownErr
;
1596 // receive interface identifiers
1597 if (setsockopt(sd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1599 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
));
1600 return mStatus_UnknownErr
;
1602 // set up CF wrapper, add to Run Loop
1603 info
= mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t
));
1604 info
->callback
= callback
;
1605 info
->context
= context
;
1606 cfContext
.info
= info
;
1607 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
| kCFSocketConnectCallBack
,
1608 tcpCFSocketCallback
, &cfContext
);
1611 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
1612 freeL("mDNSPlatformTCPConnect", info
);
1613 return mStatus_UnknownErr
;
1616 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
1619 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
1620 freeL("mDNSPlatformTCPConnect", info
);
1621 return mStatus_UnknownErr
;
1624 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1627 // initiate connection wth peer
1628 if (connect(sd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1630 if (errno
== EINPROGRESS
)
1632 info
->connected
= 0;
1634 return mStatus_ConnPending
;
1636 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno
));
1637 freeL("mDNSPlatformTCPConnect", info
);
1638 CFSocketInvalidate(sr
); // Note: Also closes the underlying socket
1639 return mStatus_ConnFailed
;
1641 info
->connected
= 1;
1643 return mStatus_ConnEstablished
;
1646 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
1648 CFSocketContext cfContext
;
1652 if (sd
< 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd
);
1654 // Get the CFSocket for the descriptor
1655 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketNoCallBack
, NULL
, NULL
);
1656 if (!sr
) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
1658 CFSocketGetContext(sr
, &cfContext
);
1659 if (!cfContext
.info
)
1661 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
1665 CFRelease(sr
); // this only releases the copy we allocated with CreateWithNative above
1667 info
= cfContext
.info
;
1669 // Note: MUST NOT close the underlying native BSD socket.
1670 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1671 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1672 CFSocketInvalidate(sr
);
1674 freeL("mDNSPlatformTCPCloseConnection", info
);
1677 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
1679 int nread
= recv(sd
, buf
, buflen
, 0);
1682 if (errno
== EAGAIN
) return 0; // no data available (call would block)
1683 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno
));
1689 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
1691 int nsent
= send(sd
, msg
, len
, 0);
1695 if (errno
== EAGAIN
) return 0; // blocked
1696 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno
));
1702 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1703 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1705 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1706 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1709 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1714 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1715 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1717 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1720 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1725 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1728 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1729 if (!state
) return mDNSfalse
;
1730 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1731 return val
? mDNStrue
: mDNSfalse
;
1734 mDNSlocal
void GetUserSpecifiedDDNSConfig(domainname
*const fqdn
, domainname
*const regDomain
, CFArrayRef
*const browseDomains
)
1736 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1739 regDomain
->c
[0] = 0;
1741 *browseDomains
= NULL
;
1743 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL
, NULL
);
1746 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, CFSTR("Setup:/Network/DynamicDNS"));
1749 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("HostNames"));
1750 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
1752 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0); // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
1753 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
1755 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
1758 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1759 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
1760 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
1761 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
1766 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("RegistrationDomains"));
1767 if (regArray
&& CFArrayGetCount(regArray
) > 0)
1769 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
1770 if (regDict
&& DDNSSettingEnabled(regDict
))
1772 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
1775 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1776 !MakeDomainNameFromDNSNameString(regDomain
, buf
) || !regDomain
->c
[0])
1777 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
1778 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf
);
1782 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("BrowseDomains"));
1783 if (browseArray
&& CFArrayGetCount(browseArray
) > 0)
1785 CFRetain(browseArray
);
1786 *browseDomains
= browseArray
;
1794 mDNSlocal
void SetDDNSNameStatus(domainname
*const dname
, mStatus status
)
1796 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL
, NULL
);
1799 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1800 ConvertDomainNameToCString(dname
, uname
);
1806 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1810 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
1811 // That single entity is a CFDictionary with name "HostNames".
1812 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
1813 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
1814 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
1815 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
1816 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
1818 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
1819 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
1820 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
1821 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
1824 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
1825 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
1828 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
1831 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
1834 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
1837 SCDynamicStoreSetValue(store
, CFSTR("State:/Network/DynamicDNS"), StateDict
);
1838 CFRelease(StateDict
);
1840 CFRelease(StateVals
[0]);
1842 CFRelease(HostVals
[0]);
1844 CFRelease(StatusVals
[0]);
1846 CFRelease(HostKeys
[0]);
1852 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1853 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1854 mDNSlocal mStatus
SetupSocket(mDNS
*const m
, CFSocketSet
*cp
, mDNSBool mcast
, const mDNSAddr
*ifaddr
, u_short sa_family
)
1856 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1857 CFSocketRef
*c
= (sa_family
== AF_INET
) ? &cp
->cfsv4
: &cp
->cfsv6
;
1858 CFRunLoopSourceRef
*r
= (sa_family
== AF_INET
) ? &cp
->rlsv4
: &cp
->rlsv6
;
1860 const int twofivefive
= 255;
1861 mStatus err
= mStatus_NoError
;
1862 char *errstr
= mDNSNULL
;
1864 mDNSIPPort port
= (mcast
| m
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1866 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
1867 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
1869 // Open the socket...
1870 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1871 if (skt
< 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1873 // ... with a shared UDP port, if it's for multicast receiving
1874 if (port
.NotAnInteger
) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1875 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1877 if (sa_family
== AF_INET
)
1879 // We want to receive destination addresses
1880 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1881 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1883 // We want to receive interface identifiers
1884 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1885 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1887 // We want to receive packet TTL value so we can check it
1888 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1889 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1891 // Add multicast group membership on this interface, if it's for multicast receiving
1894 struct in_addr addr
= { ifaddr
->ip
.v4
.NotAnInteger
};
1896 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1897 imr
.imr_interface
= addr
;
1898 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
1899 if (err
< 0) { errstr
= "setsockopt - IP_ADD_MEMBERSHIP"; goto fail
; }
1901 // Specify outgoing interface too
1902 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
1903 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_IF"; goto fail
; }
1906 // Send unicast packets with TTL 255
1907 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1908 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1910 // And multicast packets with TTL 255 too
1911 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1912 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1914 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1915 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1916 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1917 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1919 // And start listening for packets
1920 struct sockaddr_in listening_sockaddr
;
1921 listening_sockaddr
.sin_family
= AF_INET
;
1922 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1923 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1924 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1925 if (err
) { errstr
= "bind"; goto fail
; }
1927 else if (sa_family
== AF_INET6
)
1929 // We want to receive destination addresses and receive interface identifiers
1930 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1931 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1933 // We want to receive packet hop count value so we can check it
1934 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1935 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1937 // We want to receive only IPv6 packets, without this option, we may
1938 // get IPv4 addresses as mapped addresses.
1939 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1940 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1944 // Add multicast group membership on this interface, if it's for multicast receiving
1945 int interface_id
= if_nametoindex(cp
->info
->ifa_name
);
1946 struct ipv6_mreq i6mr
;
1947 i6mr
.ipv6mr_interface
= interface_id
;
1948 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
1949 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
1950 if (err
< 0) { errstr
= "setsockopt - IPV6_JOIN_GROUP"; goto fail
; }
1952 // Specify outgoing interface too
1953 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
1954 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_IF"; goto fail
; }
1957 // Send unicast packets with TTL 255
1958 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1959 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1961 // And multicast packets with TTL 255 too
1962 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1963 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1965 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1967 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1968 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1969 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1970 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1973 // Want to receive our own packets
1974 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1975 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1977 // And start listening for packets
1978 struct sockaddr_in6 listening_sockaddr6
;
1979 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1980 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1981 listening_sockaddr6
.sin6_family
= AF_INET6
;
1982 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1983 listening_sockaddr6
.sin6_flowinfo
= 0;
1984 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
1985 listening_sockaddr6
.sin6_scope_id
= 0;
1986 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1987 if (err
) { errstr
= "bind"; goto fail
; }
1990 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1992 CFSocketContext myCFSocketContext
= { 0, cp
, NULL
, NULL
, NULL
};
1993 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
1994 *r
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
1995 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r
, kCFRunLoopDefaultMode
);
2000 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
2001 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
2002 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
2003 "Alternatively, you can send email to radar-3387020@group.apple.com. "
2004 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2009 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2011 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2013 if (sa
->sa_family
== AF_INET
)
2015 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2016 ip
->type
= mDNSAddrType_IPv4
;
2017 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2018 return(mStatus_NoError
);
2021 if (sa
->sa_family
== AF_INET6
)
2023 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2024 ip
->type
= mDNSAddrType_IPv6
;
2025 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2026 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2027 return(mStatus_NoError
);
2030 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2031 return(mStatus_Invalid
);
2034 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2036 mDNSEthAddr eth
= zeroEthAddr
;
2037 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2040 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2043 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2046 CFRange range
= { 0, 6 }; // Offset, length
2047 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2048 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2051 CFRelease(entityname
);
2058 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2060 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2061 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2064 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2065 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2067 NetworkInterfaceInfoOSX
**p
;
2068 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2069 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2071 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2072 (*p
)->Exists
= mDNStrue
;
2076 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2077 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2078 if (!i
) return(mDNSNULL
);
2079 bzero(i
, sizeof(NetworkInterfaceInfoOSX
));
2080 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2081 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2082 strcpy(i
->ifa_name
, ifa
->ifa_name
);
2084 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2086 i
->ifinfo
.mask
= mask
;
2087 strncpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2088 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2089 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2090 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2093 i
->Exists
= mDNStrue
;
2095 i
->scope_id
= scope_id
;
2097 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2098 i
->Multicast
= (ifa
->ifa_flags
& IFF_MULTICAST
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
);
2102 i
->ss
.sktv4
= i
->ss
.sktv6
= -1;
2103 i
->ss
.cfsv4
= i
->ss
.cfsv6
= NULL
;
2104 i
->ss
.rlsv4
= i
->ss
.rlsv6
= NULL
;
2110 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2112 NetworkInterfaceInfoOSX
*i
;
2113 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2114 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2115 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
2120 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2122 mDNSBool foundav4
= mDNSfalse
;
2123 mDNSBool foundav6
= mDNSfalse
;
2124 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2125 struct ifaddrs
*v4Loopback
= NULL
;
2126 struct ifaddrs
*v6Loopback
= NULL
;
2127 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2128 char defaultname
[32];
2129 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2130 if (InfoSocket
< 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2131 if (m
->SleepState
) ifa
= NULL
;
2135 #if LIST_ALL_INTERFACES
2136 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2137 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2138 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2139 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2140 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2141 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2142 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2143 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2144 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2145 if (!(ifa
->ifa_flags
& IFF_UP
))
2146 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2147 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2148 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2149 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2150 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2151 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2152 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2153 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2154 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2155 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2156 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2159 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2161 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2162 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2163 mDNSPlatformMemCopy(sdl
->sdl_data
+ sdl
->sdl_nlen
, PrimaryMAC
.b
, 6);
2166 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2167 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2169 if (!ifa
->ifa_netmask
)
2172 SetupAddr(&ip
, ifa
->ifa_addr
);
2173 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2174 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2176 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2179 SetupAddr(&ip
, ifa
->ifa_addr
);
2180 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2181 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2185 int ifru_flags6
= 0;
2186 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2188 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2189 struct in6_ifreq ifr6
;
2190 bzero((char *)&ifr6
, sizeof(ifr6
));
2191 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2192 ifr6
.ifr_addr
= *sin6
;
2193 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2194 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2195 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2197 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2199 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2200 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2201 else v6Loopback
= ifa
;
2204 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2205 if (i
&& i
->Multicast
)
2207 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2208 else foundav6
= mDNStrue
;
2214 ifa
= ifa
->ifa_next
;
2217 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2218 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2219 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2221 // Now the list is complete, set the McastTxRx setting for each interface.
2222 // We always send and receive using IPv4.
2223 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
2224 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
2225 // which means there's a good chance that most or all the other devices on that network should also have v4.
2226 // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
2227 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
2228 // so we are willing to make that sacrifice.
2229 NetworkInterfaceInfoOSX
*i
;
2230 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2233 mDNSBool txrx
= i
->Multicast
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2234 if (i
->ifinfo
.McastTxRx
!= txrx
)
2236 i
->ifinfo
.McastTxRx
= txrx
;
2237 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2240 if (InfoSocket
>= 0) close(InfoSocket
);
2242 mDNS_snprintf(defaultname
, sizeof(defaultname
), "Macintosh-%02X%02X%02X%02X%02X%02X",
2243 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2245 // Set up the nice label
2246 domainlabel nicelabel
;
2248 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2249 if (nicelabel
.c
[0] == 0)
2251 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2252 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2255 // Set up the RFC 1034-compliant label
2256 domainlabel hostlabel
;
2258 GetUserSpecifiedLocalHostName(&hostlabel
);
2259 if (hostlabel
.c
[0] == 0)
2261 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2262 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2265 if (SameDomainLabel(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2266 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2269 debugf("Updating m->nicelabel to %#s", nicelabel
.c
);
2270 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2273 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2274 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2277 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
2278 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2282 return(mStatus_NoError
);
2285 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2287 int i
= 0, bits
= 0;
2288 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2291 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2292 while (b
& 0x80) { bits
++; b
<<= 1; }
2295 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2299 // returns count of non-link local V4 addresses registered
2300 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2302 NetworkInterfaceInfoOSX
*i
;
2304 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2307 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
2308 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2309 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2311 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2313 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2314 n
->InterfaceID
= mDNSNULL
;
2317 if (!n
->InterfaceID
)
2319 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2320 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2321 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2322 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2323 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2324 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2325 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
2326 mDNSBool flapping
= (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2327 mDNS_RegisterInterface(m
, n
, flapping
? mDNSPlatformOneSecond
* 5 : 0);
2328 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2329 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
2330 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2331 flapping
? " (Flapping)" : "", n
->InterfaceActive
? " (Primary)" : "");
2335 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2338 if (i
->sa_family
== AF_INET
&& primary
->ss
.sktv4
== -1)
2340 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET
);
2341 if (err
== 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
, CountMaskBits(&n
->mask
));
2342 else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary
->ss
.sktv4
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
, CountMaskBits(&n
->mask
));
2345 if (i
->sa_family
== AF_INET6
&& primary
->ss
.sktv6
== -1)
2347 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET6
);
2348 if (err
== 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
, CountMaskBits(&n
->mask
));
2349 else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary
->ss
.sktv6
, i
->ifa_name
, i
->scope_id
, &i
->BSSID
, n
->InterfaceID
, &n
->ip
, CountMaskBits(&n
->mask
));
2356 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2358 NetworkInterfaceInfoOSX
*i
;
2359 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2361 if (i
->Exists
) i
->LastSeen
= utc
;
2362 i
->Exists
= mDNSfalse
;
2366 mDNSlocal
void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls
, CFSocketRef cfs
)
2368 // Note: CFSocketInvalidate also closes the underlying socket for us
2369 // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
2370 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); // rls 2 cfs 3
2371 CFRelease(rls
); // rls ? cfs 3
2372 CFSocketInvalidate(cfs
); // rls ? cfs 1
2373 CFRelease(cfs
); // rls ? cfs ?
2376 mDNSlocal
void CloseSocketSet(CFSocketSet
*ss
)
2378 // Note: MUST NOT close the underlying native BSD sockets.
2379 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
2380 // because it first has to unhook the sockets from its select() call, before it can safely close them.
2381 if (ss
->cfsv4
) CloseRunLoopSourceSocket(ss
->rlsv4
, ss
->cfsv4
);
2382 if (ss
->cfsv6
) CloseRunLoopSourceSocket(ss
->rlsv6
, ss
->cfsv6
);
2383 ss
->sktv4
= ss
->sktv6
= -1;
2384 ss
->cfsv4
= ss
->cfsv6
= NULL
;
2385 ss
->rlsv4
= ss
->rlsv6
= NULL
;
2388 // returns count of non-link local V4 addresses deregistered
2389 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2392 // If an interface is going away, then deregister this from the mDNSCore.
2393 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2394 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2395 // it refers to has gone away we'll crash.
2396 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2397 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2398 NetworkInterfaceInfoOSX
*i
;
2400 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2402 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
2403 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2404 if (i
->ifinfo
.InterfaceID
)
2405 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2407 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
2408 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2409 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2410 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
2411 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2412 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2413 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2414 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2415 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2420 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2421 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2425 // 2. Close all our CFSockets. We'll recreate them later as necessary.
2426 // (We may have previously had both v4 and v6, and we may not need both any more.)
2427 CloseSocketSet(&i
->ss
);
2428 // 3. If no longer active, delete interface from list and free memory
2431 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2432 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2433 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2434 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2435 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2436 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2440 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2441 freeL("NetworkInterfaceInfoOSX", i
);
2442 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2450 mDNSlocal mStatus
GetDNSConfig(void **result
)
2453 static int MessageShown
= 0;
2454 if (!MessageShown
) { MessageShown
= 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
2456 return mStatus_UnsupportedErr
;
2459 *result
= dns_configuration_copy();
2463 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2464 if (mDNSMacOSXSystemBuildNumber(NULL
) < 8) return mStatus_UnsupportedErr
;
2466 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2467 // Apparently this is expected behaviour -- "not a bug".
2468 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2469 // If we are still getting failures after three minutes, then we log them.
2470 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return mStatus_NoError
;
2472 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2473 return mStatus_UnknownErr
;
2475 return mStatus_NoError
;
2476 #endif // MDNS_NO_DNSINFO
2479 mDNSlocal mStatus
RegisterSplitDNS(mDNS
*m
, int *nAdditions
, int *nDeletions
)
2481 (void)m
; // unused on 10.3 systems
2483 *nAdditions
= *nDeletions
= 0;
2484 mStatus err
= GetDNSConfig(&v
);
2486 #if !MDNS_NO_DNSINFO
2491 dns_config_t
*config
= v
; // use void * to allow compilation on 10.3 systems
2493 p
= m
->uDNS_info
.Servers
;
2494 while (p
) { p
->del
= mDNStrue
; p
= p
->next
; } // mark all for deletion
2496 LogOperation("RegisterSplitDNS: Registering %d resolvers", config
->n_resolver
);
2497 for (i
= 0; i
< config
->n_resolver
; i
++)
2501 dns_resolver_t
*r
= config
->resolver
[i
];
2502 if (r
->port
== MulticastDNSPort
.NotAnInteger
) continue; // ignore configurations for .local
2503 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2504 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2506 // check if this is the lowest-weighted server for the domain
2507 for (j
= 0; j
< config
->n_resolver
; j
++)
2509 dns_resolver_t
*p
= config
->resolver
[j
];
2510 if (p
->port
== MulticastDNSPort
.NotAnInteger
) continue;
2511 if (p
->search_order
<= r
->search_order
)
2514 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2515 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2516 if (SameDomainName(&d
, &tmp
))
2517 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2520 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2521 { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
); continue; }
2522 // we're using this resolver - find the first IPv4 address
2523 for (n
= 0; n
< r
->n_nameserver
; n
++)
2525 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& !AddrRequiresPPPConnection(r
->nameserver
[n
]))
2527 // %%% This should use mDNS_AddDNSServer() instead of duplicating functionality here
2529 if (SetupAddr(&saddr
, r
->nameserver
[n
])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
2530 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
2531 debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i
, saddr
.ip
.v4
.b
[0], saddr
.ip
.v4
.b
[1], saddr
.ip
.v4
.b
[2], saddr
.ip
.v4
.b
[3], d
.c
);
2532 p
= m
->uDNS_info
.Servers
;
2535 if (mDNSSameAddress(&p
->addr
, &saddr
) && SameDomainName(&p
->domain
, &d
)) { p
->del
= mDNSfalse
; break; }
2540 p
= mallocL("DNSServer", sizeof(*p
));
2541 if (!p
) { LogMsg("Error: malloc"); mDNS_Unlock(m
); return mStatus_UnknownErr
; }
2544 p
->teststate
= DNSServer_Untested
;
2545 AssignDomainName(&p
->domain
, &d
);
2546 p
->next
= m
->uDNS_info
.Servers
;
2547 m
->uDNS_info
.Servers
= p
;
2550 break; // !!!KRS if we ever support round-robin servers, don't break here
2555 // remove all servers marked for deletion
2556 DNSServer
**s
= &m
->uDNS_info
.Servers
;
2563 freeL("DNSServer", p
);
2566 else s
= &(*s
)->next
;
2569 dns_configuration_free(config
);
2576 mDNSlocal mStatus
RegisterNameServers(mDNS
*const m
, CFDictionaryRef dict
)
2581 mDNSAddr saddr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
2584 mDNS_DeleteDNSServers(m
); // deregister orig list
2585 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
2586 if (!values
) return mStatus_NoError
;
2588 count
= CFArrayGetCount(values
);
2589 for (i
= 0; i
< count
; i
++)
2591 s
= CFArrayGetValueAtIndex(values
, i
);
2592 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
2593 if (!CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
))
2595 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
2598 if (!inet_aton(buf
, (struct in_addr
*)saddr
.ip
.v4
.b
))
2600 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf
);
2603 LogOperation("RegisterNameServers: Adding %#a", &saddr
);
2604 mDNS_AddDNSServer(m
, &saddr
, NULL
);
2606 return mStatus_NoError
;
2609 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2612 ARListElem
*elem
= rr
->RecordContext
;
2613 if (result
== mStatus_MemFree
) freeL("FreeARElemCallback", elem
);
2616 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2618 SearchListElem
*slElem
= question
->QuestionContext
;
2619 ARListElem
*arElem
, *ptr
, *prev
;
2626 arElem
= mallocL("FoundDomain - arElem", sizeof(ARListElem
));
2627 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
2628 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
2629 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
2630 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
2631 else if (question
== &slElem
->LegacyBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseLegacy
];
2632 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
2633 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
2634 else { LogMsg("FoundDomain - unknown question"); return; }
2636 MakeDomainNameFromDNSNameString(arElem
->ar
.resrec
.name
, name
);
2637 AppendDNSNameString (arElem
->ar
.resrec
.name
, "local");
2638 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
2639 err
= mDNS_Register(m
, &arElem
->ar
);
2642 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
);
2643 freeL("FoundDomain - arElem", arElem
);
2646 arElem
->next
= slElem
->AuthRecs
;
2647 slElem
->AuthRecs
= arElem
;
2651 ptr
= slElem
->AuthRecs
;
2655 if (SameDomainName(&ptr
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
2657 debugf("Deregistering PTR %##s -> %##s", ptr
->ar
.resrec
.name
->c
, ptr
->ar
.resrec
.rdata
->u
.name
.c
);
2659 if (prev
) prev
->next
= ptr
->next
;
2660 else slElem
->AuthRecs
= ptr
->next
;
2662 err
= mDNS_Deregister(m
, dereg
);
2663 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
2674 mDNSlocal
void MarkSearchListElem(const char *d
)
2676 SearchListElem
*new, *ptr
;
2679 if (!MakeDomainNameFromDNSNameString(&domain
, d
))
2680 { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d
); return; }
2682 if (SameDomainName(&domain
, &localdomain
) || SameDomainName(&domain
, &LocalReverseMapomain
))
2683 { debugf("MarkSearchListElem - ignoring local domain %##s", domain
.c
); return; }
2685 // if domain is in list, mark as pre-existent (0)
2686 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
2687 if (SameDomainName(&ptr
->domain
, &domain
))
2689 if (ptr
->flag
!= 1) ptr
->flag
= 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
2693 // if domain not in list, add to list, mark as add (1)
2696 new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem
));
2697 if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
2698 bzero(new, sizeof(SearchListElem
));
2699 AssignDomainName(&new->domain
, &domain
);
2700 new->flag
= 1; // add
2701 new->next
= SearchList
;
2706 // Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
2707 mDNSlocal mStatus
GetSearchDomains(void)
2710 mStatus err
= GetDNSConfig(&v
);
2712 #if !MDNS_NO_DNSINFO
2716 dns_config_t
*config
= v
;
2717 if (!config
->n_resolver
) return err
;
2718 dns_resolver_t
*resolv
= config
->resolver
[0]; // use the first slot for search domains
2720 for (i
= 0; i
< resolv
->n_search
; i
++) MarkSearchListElem(resolv
->search
[i
]);
2721 if (resolv
->domain
) MarkSearchListElem(resolv
->domain
);
2722 dns_configuration_free(config
);
2729 // Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
2730 mDNSlocal
void GetDSSearchDomains(CFDictionaryRef dict
)
2732 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2737 // get all the domains from "Search Domains" field of sharing prefs
2740 CFArrayRef searchdomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
2743 count
= CFArrayGetCount(searchdomains
);
2744 for (i
= 0; i
< count
; i
++)
2746 s
= CFArrayGetValueAtIndex(searchdomains
, i
);
2747 if (!s
) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
2748 if (!CFStringGetCString(s
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2750 LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2753 MarkSearchListElem(buf
);
2757 // get DHCP domain field
2758 CFStringRef dname
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
2761 if (CFStringGetCString(dname
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2762 MarkSearchListElem(buf
);
2763 else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2768 mDNSlocal mStatus
RegisterSearchDomains(mDNS
*const m
, CFDictionaryRef dict
)
2770 struct ifaddrs
*ifa
= NULL
;
2771 SearchListElem
*ptr
, *prev
, *freeSLPtr
;
2775 if (DomainDiscoveryDisabled
) return mStatus_NoError
;
2777 // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
2778 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= dict
? -1 : 0;
2780 // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
2781 if (GetSearchDomains() == mStatus_UnsupportedErr
) GetDSSearchDomains(dict
);
2783 // Construct reverse-map search domains
2784 ifa
= myGetIfAddrs(1);
2788 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
2792 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
2794 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
2795 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
2796 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
2797 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
2798 MarkSearchListElem(buffer
);
2801 ifa
= ifa
->ifa_next
;
2804 // delete elems marked for removal, do queries for elems marked add
2809 if (ptr
->flag
== -1) // remove
2811 mDNS_StopQuery(m
, &ptr
->BrowseQ
);
2812 mDNS_StopQuery(m
, &ptr
->RegisterQ
);
2813 mDNS_StopQuery(m
, &ptr
->DefBrowseQ
);
2814 mDNS_StopQuery(m
, &ptr
->DefRegisterQ
);
2815 mDNS_StopQuery(m
, &ptr
->LegacyBrowseQ
);
2817 // deregister records generated from answers to the query
2818 arList
= ptr
->AuthRecs
;
2819 ptr
->AuthRecs
= NULL
;
2822 AuthRecord
*dereg
= &arList
->ar
;
2823 arList
= arList
->next
;
2824 debugf("Deregistering PTR %##s -> %##s", dereg
->resrec
.name
->c
, dereg
->resrec
.rdata
->u
.name
.c
);
2825 err
= mDNS_Deregister(m
, dereg
);
2826 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
2829 // remove elem from list, delete
2830 if (prev
) prev
->next
= ptr
->next
;
2831 else SearchList
= ptr
->next
;
2834 freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr
);
2838 if (ptr
->flag
== 1) // add
2840 mStatus err1
, err2
, err3
, err4
, err5
;
2841 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2842 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2843 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2844 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2845 err5
= mDNS_GetDomains(m
, &ptr
->LegacyBrowseQ
, mDNS_DomainTypeBrowseLegacy
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2846 if (err1
|| err2
|| err3
|| err4
|| err5
)
2847 LogMsg("GetDomains for domain %##s returned error(s):\n"
2848 "%d (mDNS_DomainTypeBrowse)\n"
2849 "%d (mDNS_DomainTypeBrowseDefault)\n"
2850 "%d (mDNS_DomainTypeRegistration)\n"
2851 "%d (mDNS_DomainTypeRegistrationDefault)"
2852 "%d (mDNS_DomainTypeBrowseLegacy)\n",
2853 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
2857 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
2863 return mStatus_NoError
;
2866 //!!!KRS here is where we will give success/failure notification to the UI
2867 mDNSlocal
void SCPrefsDynDNSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2870 debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
2871 SetDDNSNameStatus(rr
->resrec
.name
, result
);
2874 mDNSlocal
void SetSecretForDomain(mDNS
*m
, const domainname
*domain
)
2877 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
2879 void *secret
= NULL
;
2880 domainname
*d
, canon
;
2882 mDNSu32 type
= 'ddns';
2883 mDNSu32 typelen
= sizeof(type
);
2884 char *failedfn
= "(none)";
2885 SecKeychainAttributeList
*attrList
= NULL
;
2886 SecKeychainItemRef itemRef
= NULL
;
2888 err
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
2889 if (err
) { failedfn
= "SecKeychainSetPreferenceDomain"; goto cleanup
; }
2891 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
2892 ConvertDomainNameToCString(domain
, dstring
);
2893 dlen
= strlen(dstring
);
2894 for (i
= 0; i
< dlen
; i
++) dstring
[i
] = tolower(dstring
[i
]); // canonicalize -> lower case
2895 MakeDomainNameFromDNSNameString(&canon
, dstring
);
2898 // find longest-match key, excluding last label (e.g. excluding ".com")
2899 while (d
->c
[0] && *(d
->c
+ d
->c
[0] + 1))
2901 if (!ConvertDomainNameToCString(d
, dstring
)) { LogMsg("SetSecretForDomain: bad domain %##s", d
->c
); return; }
2902 dlen
= strlen(dstring
);
2903 if (dstring
[dlen
-1] == '.') { dstring
[dlen
-1] = '\0'; dlen
--; } // chop trailing dot
2904 SecKeychainAttribute attrs
[] = { { kSecServiceItemAttr
, strlen(dstring
), dstring
},
2905 { kSecTypeItemAttr
, typelen
, (UInt32
*)&type
} };
2906 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
2907 SecKeychainSearchRef searchRef
;
2909 err
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attributes
, &searchRef
);
2910 if (err
) { failedfn
= "SecKeychainSearchCreateFromAttributes"; goto cleanup
; }
2912 err
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
2916 SecKeychainAttributeInfo attrInfo
;
2918 char keybuf
[MAX_ESCAPED_DOMAIN_NAME
+1];
2921 tags
[0] = kSecAccountItemAttr
;
2923 attrInfo
.tag
= tags
;
2924 attrInfo
.format
= NULL
;
2926 err
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrList
, &secretlen
, &secret
);
2927 if (err
|| !attrList
) { failedfn
= "SecKeychainItemCopyAttributesAndData"; goto cleanup
; }
2928 if (!secretlen
|| !secret
) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
2929 if (((char *)secret
)[secretlen
-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup
; }
2931 for (i
= 0; i
< attrList
->count
; i
++)
2933 SecKeychainAttribute attr
= attrList
->attr
[i
];
2934 if (attr
.tag
== kSecAccountItemAttr
)
2936 if (!attr
.length
|| attr
.length
> MAX_ESCAPED_DOMAIN_NAME
) { LogMsg("SetSecretForDomain - Bad key length %d", attr
.length
); goto cleanup
; }
2937 strncpy(keybuf
, attr
.data
, attr
.length
);
2938 if (!MakeDomainNameFromDNSNameString(&keyname
, keybuf
)) { LogMsg("SetSecretForDomain - bad key %s", keybuf
); goto cleanup
; }
2939 debugf("Setting shared secret for zone %s with key %##s", dstring
, keyname
.c
);
2940 mDNS_SetSecretForZone(m
, d
, &keyname
, secret
);
2944 if (i
== attrList
->count
) LogMsg("SetSecretForDomain - no key name set");
2947 else if (err
== errSecItemNotFound
) d
= (domainname
*)(d
->c
+ d
->c
[0] + 1);
2948 else { failedfn
= "SecKeychainSearchCopyNext"; goto cleanup
; }
2952 if (err
&& err
!= errSecItemNotFound
) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn
, err
);
2953 if (attrList
) SecKeychainItemFreeAttributesAndData(attrList
, secret
);
2954 if (itemRef
) CFRelease(itemRef
);
2957 mDNSlocal
void SetSCPrefsBrowseDomainsFromCFArray(mDNS
*m
, CFArrayRef browseDomains
, mDNSBool add
)
2961 CFIndex count
= CFArrayGetCount(browseDomains
);
2962 CFDictionaryRef browseDict
;
2963 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2966 for (i
= 0; i
< count
; i
++)
2968 browseDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(browseDomains
, i
);
2969 if (browseDict
&& DDNSSettingEnabled(browseDict
))
2971 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
2974 domainname BrowseDomain
;
2975 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) || !MakeDomainNameFromDNSNameString(&BrowseDomain
, buf
) || !BrowseDomain
.c
[0])
2976 LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf
[0] ? buf
: "(unknown)");
2977 else SetSCPrefsBrowseDomain(m
, &BrowseDomain
, add
);
2985 mDNSlocal
void DynDNSConfigChanged(mDNS
*const m
)
2987 static mDNSBool LegacyNATInitialized
= mDNSfalse
;
2988 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2989 CFDictionaryRef dict
;
2991 domainname RegDomain
, fqdn
;
2992 CFArrayRef NewBrowseDomains
= NULL
;
2993 int nAdditions
= 0, nDeletions
= 0;
2995 // get fqdn, zone from SCPrefs
2996 GetUserSpecifiedDDNSConfig(&fqdn
, &RegDomain
, &NewBrowseDomains
);
2997 ReadDDNSSettingsFromConfFile(m
, CONFIG_FILE
, fqdn
.c
[0] ? NULL
: &fqdn
, RegDomain
.c
[0] ? NULL
: &RegDomain
, &DomainDiscoveryDisabled
);
2999 if (!SameDomainName(&RegDomain
, &DynDNSRegDomain
))
3001 if (DynDNSRegDomain
.c
[0])
3003 RemoveDefRegDomain(&DynDNSRegDomain
);
3004 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNSfalse
); // if we were automatically browsing in our registration domain, stop
3006 AssignDomainName(&DynDNSRegDomain
, &RegDomain
);
3007 if (DynDNSRegDomain
.c
[0])
3009 SetSecretForDomain(m
, &DynDNSRegDomain
);
3010 AddDefRegDomain(&DynDNSRegDomain
);
3011 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNStrue
);
3015 // Add new browse domains to internal list
3016 if (NewBrowseDomains
) SetSCPrefsBrowseDomainsFromCFArray(m
, NewBrowseDomains
, mDNStrue
);
3018 // Remove old browse domains from internal list
3019 if (DynDNSBrowseDomains
)
3021 SetSCPrefsBrowseDomainsFromCFArray(m
, DynDNSBrowseDomains
, mDNSfalse
);
3022 CFRelease(DynDNSBrowseDomains
);
3025 // Replace the old browse domains array with the new array
3026 DynDNSBrowseDomains
= NewBrowseDomains
;
3028 if (!SameDomainName(&fqdn
, &DynDNSHostname
))
3030 if (DynDNSHostname
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &DynDNSHostname
);
3031 AssignDomainName(&DynDNSHostname
, &fqdn
);
3032 if (DynDNSHostname
.c
[0])
3034 SetSecretForDomain(m
, &fqdn
); // no-op if "zone" secret, above, is to be used for hostname
3035 SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate "in progress"
3036 mDNS_AddDynDNSHostName(m
, &DynDNSHostname
, SCPrefsDynDNSCallback
, NULL
);
3041 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL
, NULL
);
3044 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3045 if (!key
) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3046 dict
= SCDynamicStoreCopyValue(store
, key
);
3049 // handle any changes to search domains and DNS server addresses
3050 if (RegisterSplitDNS(m
, &nAdditions
, &nDeletions
) != mStatus_NoError
)
3051 if (dict
) RegisterNameServers(m
, dict
); // fall back to non-split DNS aware configuration on failure
3052 RegisterSearchDomains(m
, dict
); // note that we register name servers *before* search domains
3053 if (dict
) CFRelease(dict
);
3055 // get IPv4 settings
3056 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3057 if (!key
) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3058 dict
= SCDynamicStoreCopyValue(store
, key
);
3061 if (!dict
) // lost v4
3063 mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3064 if (DynDNSHostname
.c
[0]) SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate temporary failure
3068 // handle router changes
3071 r
.type
= mDNSAddrType_IPv4
;
3072 r
.ip
.v4
.NotAnInteger
= 0;
3073 CFStringRef router
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3076 struct sockaddr_in saddr
;
3078 if (!CFStringGetCString(router
, buf
, 256, kCFStringEncodingUTF8
))
3079 LogMsg("Could not convert router to CString");
3082 saddr
.sin_len
= sizeof(saddr
);
3083 saddr
.sin_family
= AF_INET
;
3085 inet_aton(buf
, &saddr
.sin_addr
);
3086 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) { debugf("Ignoring router %s (requires PPP connection)", buf
); }
3087 else *(in_addr_t
*)&r
.ip
.v4
= saddr
.sin_addr
.s_addr
;
3091 // handle primary interface changes
3092 // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
3093 if (nAdditions
|| nDeletions
) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3094 CFStringRef primary
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3097 mDNSAddr v4
= zeroAddr
, v6
= zeroAddr
;
3098 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3099 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3101 if (!CFStringGetCString(primary
, buf
, 256, kCFStringEncodingUTF8
))
3102 { LogMsg("Could not convert router to CString"); goto error
; }
3104 // find primary interface in list
3105 while (ifa
&& (!v4
.ip
.v4
.NotAnInteger
|| !HavePrimaryGlobalv6
))
3107 mDNSAddr tmp6
= zeroAddr
;
3108 if (!strcmp(buf
, ifa
->ifa_name
))
3110 if (ifa
->ifa_addr
->sa_family
== AF_INET
) SetupAddr(&v4
, ifa
->ifa_addr
);
3111 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3113 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3114 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3115 { HavePrimaryGlobalv6
= mDNStrue
; v6
= tmp6
; }
3120 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3121 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
.ip
.v6
.b
[0])
3123 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3124 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) v6
= tmp6
;
3127 ifa
= ifa
->ifa_next
;
3130 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3131 // V4 to communicate w/ our DNS server
3133 if (v4
.ip
.v4
.b
[0] == 169 && v4
.ip
.v4
.b
[1] == 254) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
); // primary IP is link-local
3136 if (v4
.ip
.v4
.NotAnInteger
!= u
->AdvertisedV4
.ip
.v4
.NotAnInteger
||
3137 memcmp(v6
.ip
.v6
.b
, u
->AdvertisedV6
.ip
.v6
.b
, 16) ||
3138 r
.ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
)
3140 if (LegacyNATInitialized
) { LegacyNATDestroy(); LegacyNATInitialized
= mDNSfalse
; }
3141 if (r
.ip
.v4
.NotAnInteger
&& IsPrivateV4Addr(&v4
))
3143 mStatus err
= LegacyNATInit();
3144 if (err
) LogMsg("ERROR: LegacyNATInit");
3145 else LegacyNATInitialized
= mDNStrue
;
3147 mDNS_SetPrimaryInterfaceInfo(m
, &v4
, v6
.ip
.v6
.b
[0] ? &v6
: NULL
, r
.ip
.v4
.NotAnInteger
? &r
: NULL
);
3155 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3157 LogOperation("*** Network Configuration Change ***");
3158 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3159 mDNSs32 utc
= mDNSPlatformUTC();
3160 MarkAllInterfacesInactive(m
, utc
);
3161 UpdateInterfaceList(m
, utc
);
3162 int nDeletions
= ClearInactiveInterfaces(m
, utc
);
3163 int nAdditions
= SetupActiveInterfaces(m
, utc
);
3164 DynDNSConfigChanged(m
); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
3165 if (nDeletions
|| nAdditions
) mDNS_UpdateLLQs(m
); // so that LLQs are restarted against the up to date name servers
3167 if (m
->MainCallback
)
3168 m
->MainCallback(m
, mStatus_ConfigChanged
);
3171 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3173 (void)store
; // Parameter not used
3174 (void)changedKeys
; // Parameter not used
3175 mDNS
*const m
= (mDNS
*const)context
;
3178 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
3180 int c
= CFArrayGetCount(changedKeys
); // Count changes
3181 CFRange range
= { 0, c
};
3182 CFStringRef k1
= SCDynamicStoreKeyCreateComputerName(NULL
);
3183 CFStringRef k2
= SCDynamicStoreKeyCreateHostNames(NULL
);
3186 int c1
= (CFArrayContainsValue(changedKeys
, range
, k1
) != 0); // See if ComputerName changed
3187 int c2
= (CFArrayContainsValue(changedKeys
, range
, k2
) != 0); // See if Local Hostname changed
3188 int c3
= (CFArrayContainsValue(changedKeys
, range
, CFSTR("Setup:/Network/DynamicDNS")) != 0);
3189 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
3191 if (k1
) CFRelease(k1
);
3192 if (k2
) CFRelease(k2
);
3194 LogOperation("*** NetworkChanged *** %d change%s, delay %d", c
, c
>1?"s":"", delay
);
3196 if (!m
->p
->NetworkChanged
||
3197 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3198 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3200 if (!m
->SuppressSending
||
3201 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3202 m
->SuppressSending
= m
->p
->NetworkChanged
;
3206 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3209 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3210 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3211 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3212 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
3213 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
3214 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
3215 CFStringRef key5
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3216 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3217 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3219 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3220 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3222 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3223 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3225 CFArrayAppendValue(keys
, key1
);
3226 CFArrayAppendValue(keys
, key2
);
3227 CFArrayAppendValue(keys
, key3
);
3228 CFArrayAppendValue(keys
, key4
);
3229 CFArrayAppendValue(keys
, key5
);
3230 CFArrayAppendValue(keys
, CFSTR("Setup:/Network/DynamicDNS"));
3231 CFArrayAppendValue(patterns
, pattern1
);
3232 CFArrayAppendValue(patterns
, pattern2
);
3233 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3234 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3235 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3237 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3238 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3240 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3241 m
->p
->Store
= store
;
3246 if (store
) CFRelease(store
);
3249 if (key1
) CFRelease(key1
);
3250 if (key2
) CFRelease(key2
);
3251 if (key3
) CFRelease(key3
);
3252 if (key4
) CFRelease(key4
);
3253 if (key5
) CFRelease(key5
);
3254 if (pattern1
) CFRelease(pattern1
);
3255 if (pattern2
) CFRelease(pattern2
);
3256 if (keys
) CFRelease(keys
);
3257 if (patterns
) CFRelease(patterns
);
3262 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3264 mDNS
*const m
= (mDNS
*const)refcon
;
3265 (void)service
; // Parameter not used
3268 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3269 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3270 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3271 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3272 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3273 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3274 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3275 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3276 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3277 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3278 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3279 // Just to be safe, also make sure our interface list is fully up to date, in case we
3280 // haven't yet received the System Configuration Framework "network changed" event that
3281 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3282 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3283 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3284 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3285 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3286 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3287 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3289 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3292 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
3294 IONotificationPortRef thePortRef
;
3295 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
3296 if (m
->p
->PowerConnection
)
3298 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
3299 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3300 return(mStatus_NoError
);
3305 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3306 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3307 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3308 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3310 // Major version 6 is 10.2.x (Jaguar)
3311 // Major version 7 is 10.3.x (Panther)
3312 // Major version 8 is 10.4.x (Tiger)
3313 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3315 int major
= 0, minor
= 0;
3316 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
3317 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3320 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3321 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3322 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3323 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3324 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3325 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3326 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3329 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3333 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3334 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3335 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3336 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3339 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3341 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3344 struct sockaddr_in s5353
;
3345 s5353
.sin_family
= AF_INET
;
3346 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3347 s5353
.sin_addr
.s_addr
= 0;
3348 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3352 if (err
) LogMsg("No unicast UDP responses");
3353 else debugf("Unicast UDP responses okay");
3357 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
3358 mDNSlocal
void FoundLegacyBrowseDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
3360 DNameListElem
*ptr
, *prev
, *new;
3362 (void)question
; // unused
3364 LogMsg("%s browse domain %##s", AddRecord
? "Adding" : "Removing", answer
->rdata
->u
.name
.c
);
3368 new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem
));
3369 if (!new) { LogMsg("ERROR: malloc"); return; }
3370 AssignDomainName(&new->name
, &answer
->rdata
->u
.name
);
3371 new->next
= DefBrowseList
;
3372 DefBrowseList
= new;
3373 DefaultBrowseDomainChanged(&new->name
, mDNStrue
);
3374 udsserver_default_browse_domain_changed(&new->name
, mDNStrue
);
3379 ptr
= DefBrowseList
;
3383 if (SameDomainName(&ptr
->name
, &answer
->rdata
->u
.name
))
3385 DefaultBrowseDomainChanged(&ptr
->name
, mDNSfalse
);
3386 udsserver_default_browse_domain_changed(&ptr
->name
, mDNSfalse
);
3387 if (prev
) prev
->next
= ptr
->next
;
3388 else DefBrowseList
= ptr
->next
;
3389 freeL("FoundLegacyBrowseDomain", ptr
);
3395 LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer
->rdata
->u
.name
.c
);
3399 mDNSlocal
void RegisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3401 // allocate/register legacy and non-legacy _browse PTR record
3402 ARListElem
*browse
= mallocL("ARListElem", sizeof(*browse
));
3403 mDNS_SetupResourceRecord(&browse
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, browse
);
3404 MakeDomainNameFromDNSNameString(browse
->ar
.resrec
.name
, mDNS_DomainTypeNames
[type
]);
3405 AppendDNSNameString (browse
->ar
.resrec
.name
, "local");
3406 AssignDomainName(&browse
->ar
.resrec
.rdata
->u
.name
, d
);
3407 mStatus err
= mDNS_Register(m
, &browse
->ar
);
3410 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err
);
3411 freeL("ARListElem", browse
);
3415 browse
->next
= SCPrefBrowseDomains
;
3416 SCPrefBrowseDomains
= browse
;
3420 mDNSlocal
void DeregisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3422 ARListElem
*remove
, **ptr
= &SCPrefBrowseDomains
;
3423 domainname lhs
; // left-hand side of PTR, for comparison
3425 MakeDomainNameFromDNSNameString(&lhs
, mDNS_DomainTypeNames
[type
]);
3426 AppendDNSNameString (&lhs
, "local");
3430 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, d
) && SameDomainName((*ptr
)->ar
.resrec
.name
, &lhs
))
3433 *ptr
= (*ptr
)->next
;
3434 mDNS_Deregister(m
, &remove
->ar
);
3437 else ptr
= &(*ptr
)->next
;
3441 // Add or remove a user-specified domain to the list of empty-string browse domains
3442 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
3443 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
)
3445 debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
3449 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3450 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3454 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3455 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3459 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3460 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3461 // (.local manually generated via explicit callback)
3462 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3463 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3464 // 4) result above should generate a callback from question in (1). result added to global list
3465 // 5) global list delivered to client via GetSearchDomainList()
3466 // 6) client calls to enumerate domains now go over LocalOnly interface
3467 // (!!!KRS may add outgoing interface in addition)
3469 mDNSlocal mStatus
InitDNSConfig(mDNS
*const m
)
3472 static AuthRecord LocalRegPTR
;
3474 // start query for domains to be used in default (empty string domain) browses
3475 err
= mDNS_GetDomains(m
, &LegacyBrowseDomainQ
, mDNS_DomainTypeBrowseLegacy
, NULL
, mDNSInterface_LocalOnly
, FoundLegacyBrowseDomain
, NULL
);
3477 // provide browse domain "local" automatically
3478 SetSCPrefsBrowseDomain(m
, &localdomain
, mDNStrue
);
3480 // register registration domain "local"
3481 mDNS_SetupResourceRecord(&LocalRegPTR
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, NULL
, NULL
);
3482 MakeDomainNameFromDNSNameString(LocalRegPTR
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
]);
3483 AppendDNSNameString (LocalRegPTR
.resrec
.name
, "local");
3484 AssignDomainName(&LocalRegPTR
.resrec
.rdata
->u
.name
, &localdomain
);
3485 err
= mDNS_Register(m
, &LocalRegPTR
);
3486 if (err
) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err
);
3488 return mStatus_NoError
;
3491 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3493 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3494 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
3496 for (i
=0; i
<100; i
++)
3498 domainlabel testlabel
;
3500 GetUserSpecifiedLocalHostName(&testlabel
);
3501 if (testlabel
.c
[0]) break;
3507 m
->hostlabel
.c
[0] = 0;
3509 char *HINFO_HWstring
= "Macintosh";
3510 char HINFO_HWstring_buffer
[256];
3511 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3512 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3513 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3514 HINFO_HWstring
= HINFO_HWstring_buffer
;
3516 char HINFO_SWstring
[256] = "";
3517 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3518 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3520 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3521 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3522 if (hlen
+ slen
< 254)
3524 m
->HIHardware
.c
[0] = hlen
;
3525 m
->HISoftware
.c
[0] = slen
;
3526 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
3527 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
3530 m
->p
->unicastsockets
.m
= m
;
3531 m
->p
->unicastsockets
.info
= NULL
;
3532 m
->p
->unicastsockets
.sktv4
= m
->p
->unicastsockets
.sktv6
= -1;
3533 m
->p
->unicastsockets
.cfsv4
= m
->p
->unicastsockets
.cfsv6
= NULL
;
3534 m
->p
->unicastsockets
.rlsv4
= m
->p
->unicastsockets
.rlsv6
= NULL
;
3536 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET
);
3537 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET6
);
3539 struct sockaddr_in s4
;
3540 struct sockaddr_in6 s6
;
3541 socklen_t n4
= sizeof(s4
);
3542 socklen_t n6
= sizeof(s6
);
3543 if (getsockname(m
->p
->unicastsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
3544 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
3545 if (getsockname(m
->p
->unicastsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
3546 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
3548 m
->p
->InterfaceList
= mDNSNULL
;
3549 m
->p
->userhostlabel
.c
[0] = 0;
3550 m
->p
->usernicelabel
.c
[0] = 0;
3551 m
->p
->NotifyUser
= 0;
3552 mDNSs32 utc
= mDNSPlatformUTC();
3553 UpdateInterfaceList(m
, utc
);
3554 SetupActiveInterfaces(m
, utc
);
3556 err
= WatchForNetworkChanges(m
);
3557 if (err
) return(err
);
3559 err
= WatchForPowerChanges(m
);
3560 if (err
) return err
;
3562 DynDNSRegDomain
.c
[0] = '\0';
3563 DynDNSConfigChanged(m
); // Get initial DNS configuration
3569 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
3571 mStatus result
= mDNSPlatformInit_setup(m
);
3573 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3574 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3575 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
3579 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
3581 if (m
->p
->PowerConnection
)
3583 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3584 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
3585 CFRelease(m
->p
->PowerRLS
);
3586 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
3587 m
->p
->PowerConnection
= 0;
3588 m
->p
->PowerNotifier
= 0;
3589 m
->p
->PowerRLS
= NULL
;
3594 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3595 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
3596 CFRelease(m
->p
->StoreRLS
);
3597 CFRelease(m
->p
->Store
);
3599 m
->p
->StoreRLS
= NULL
;
3602 mDNSs32 utc
= mDNSPlatformUTC();
3603 MarkAllInterfacesInactive(m
, utc
);
3604 ClearInactiveInterfaces(m
, utc
);
3605 CloseSocketSet(&m
->p
->unicastsockets
);
3608 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
3610 return(mach_absolute_time());
3613 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
3615 mDNSexport mStatus
mDNSPlatformTimeInit(void)
3617 // Notes: Typical values for mach_timebase_info:
3618 // tbi.numer = 1000 million
3619 // tbi.denom = 33 million
3620 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3621 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3622 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3623 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3624 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3626 // Arithmetic notes:
3627 // tbi.denom is at least 1, and not more than 2^32-1.
3628 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3629 // tbi.denom is at least 1, and not more than 2^32-1.
3630 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3631 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3632 // which is unlikely on any current or future Macintosh.
3633 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3634 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3635 struct mach_timebase_info tbi
;
3636 kern_return_t result
= mach_timebase_info(&tbi
);
3637 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
3641 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
3643 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3645 static uint64_t last_mach_absolute_time
= 0;
3646 uint64_t this_mach_absolute_time
= mach_absolute_time();
3647 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
3649 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
3650 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
3651 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3652 last_mach_absolute_time
= this_mach_absolute_time
;
3653 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later
3654 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
3655 NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
3657 last_mach_absolute_time
= this_mach_absolute_time
;
3659 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
3662 mDNSexport mDNSs32
mDNSPlatformUTC(void)
3667 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
3668 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
3669 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
3670 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
3671 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
3672 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
3673 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
3674 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
3675 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
3676 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }