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.323 2006/01/05 21:45:27 cheshire
28 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
30 Revision 1.322 2006/01/05 21:41:50 cheshire
31 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
33 Revision 1.321 2006/01/05 21:35:06 cheshire
34 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
36 Revision 1.320 2005/12/03 01:39:28 cheshire
37 <rdar://problem/4363411> Improve diagnostic message to indicate that message will not appear to customers
39 Revision 1.319 2005/12/02 00:02:15 cheshire
40 Include recvmsg return value in error message
42 Revision 1.318 2005/10/20 00:10:34 cheshire
43 <rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
45 Revision 1.317 2005/09/24 01:10:26 cheshire
48 Revision 1.316 2005/07/29 18:04:22 ksekar
49 <rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
51 Revision 1.315 2005/07/22 21:50:55 ksekar
52 Fix GCC 4.0/Intel compiler warnings
54 Revision 1.314 2005/07/11 02:12:09 cheshire
55 <rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
56 Fix copy-and-paste error: "CFRelease(StatusVals[0]);" should be "CFRelease(StateVals[0]);"
58 Revision 1.313 2005/07/04 23:52:25 cheshire
59 <rdar://problem/3923098> Things are showing up with a bogus interface index
61 Revision 1.312 2005/07/04 22:24:36 cheshire
62 Export NotifyOfElusiveBug() so other files can call it
64 Revision 1.311 2005/06/15 13:20:43 cheshire
65 <rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
67 Revision 1.310 2005/04/07 00:49:58 cheshire
68 <rdar://problem/4080074> PPP connection disables Bonjour ".local" lookups
70 Revision 1.309 2005/03/23 05:53:29 cheshire
71 Fix %s where it should have been %##s in debugf & LogMsg calls
73 Revision 1.308 2005/03/09 00:48:44 cheshire
74 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
75 Move "m->p->NetworkChanged = 0;" line from caller to callee
77 Revision 1.307 2005/03/03 03:12:02 cheshire
78 Add comment about mDNSMacOSXSystemBuildNumber()
80 Revision 1.306 2005/03/02 22:18:00 cheshire
81 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
83 Revision 1.305 2005/02/26 05:08:28 cheshire
84 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
85 Added dnsinfo.h to project directory
87 Revision 1.304 2005/02/25 23:51:22 cheshire
88 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
89 Return mStatus_UnknownErr instead of -1
91 Revision 1.303 2005/02/25 17:47:45 ksekar
92 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
94 Revision 1.302 2005/02/25 02:34:14 cheshire
95 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
96 Show status as 1 (in progress) while we're trying
98 Revision 1.301 2005/02/24 21:55:57 ksekar
99 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
101 Revision 1.300 2005/02/15 20:03:13 ksekar
102 <rdar://problem/4005868> Crash when SCPreferences contains empty array
104 Revision 1.299 2005/02/15 02:46:53 cheshire
105 <rdar://problem/3967876> Don't log ENETUNREACH errors for unicast destinations
107 Revision 1.298 2005/02/10 00:41:59 cheshire
110 Revision 1.297 2005/02/09 23:38:51 ksekar
111 <rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
113 Revision 1.296 2005/02/01 21:06:52 ksekar
114 Avoid spurious log message
116 Revision 1.295 2005/02/01 19:33:30 ksekar
117 <rdar://problem/3985239> Keychain format too restrictive
119 Revision 1.294 2005/01/27 21:30:23 cheshire
120 <rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
121 Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
123 Revision 1.293 2005/01/27 19:15:41 cheshire
124 Remove extraneous LogMsg() call
126 Revision 1.292 2005/01/27 17:48:38 cheshire
127 Added comment about CFSocketInvalidate closing the underlying socket
129 Revision 1.291 2005/01/27 00:10:58 cheshire
130 <rdar://problem/3967867> Name change log messages every time machine boots
132 Revision 1.290 2005/01/25 23:18:30 ksekar
133 fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
135 Revision 1.289 2005/01/25 18:08:31 ksekar
136 Removed redundant debug output
138 Revision 1.288 2005/01/25 17:42:26 ksekar
139 Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
140 cleaned up duplicate log messages when adding/removing browse domains
142 Revision 1.287 2005/01/25 16:59:23 ksekar
143 <rdar://problem/3971138> sa_len not set checking reachability for TCP connections
145 Revision 1.286 2005/01/25 02:02:37 cheshire
146 <rdar://problem/3970673> mDNSResponder leaks
147 GetSearchDomains() was not calling dns_configuration_free().
149 Revision 1.285 2005/01/22 00:07:54 ksekar
150 <rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
152 Revision 1.284 2005/01/21 23:07:17 ksekar
153 <rdar://problem/3960795> mDNSResponder causes Dial on Demand
155 Revision 1.283 2005/01/19 21:16:16 cheshire
156 Make sure when we set NetworkChanged that we don't set it to zero
158 Revision 1.282 2005/01/19 19:19:21 ksekar
159 <rdar://problem/3960191> Need a way to turn off domain discovery
161 Revision 1.281 2005/01/18 18:10:55 ksekar
162 <rdar://problem/3954575> Use 10.4 resolver API to get search domains
164 Revision 1.280 2005/01/17 22:48:52 ksekar
165 No longer need to call MarkSearchListElem for registration domain
167 Revision 1.279 2005/01/17 20:40:34 ksekar
168 SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
170 Revision 1.278 2005/01/17 19:53:34 ksekar
171 Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
173 Revision 1.277 2005/01/12 00:17:50 ksekar
174 <rdar://problem/3933573> Update LLQs *after* setting DNS
176 Revision 1.276 2005/01/10 17:39:10 ksekar
177 Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
179 Revision 1.275 2005/01/10 04:02:22 ksekar
180 Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
182 Revision 1.274 2005/01/10 03:41:36 ksekar
183 Correction to checkin 1.272 - check that registration domain is set
184 before trying to remove it as an implicit browse domain
186 Revision 1.273 2005/01/08 00:42:18 ksekar
187 <rdar://problem/3922758> Clean up syslog messages
189 Revision 1.272 2005/01/07 23:21:42 ksekar
190 <rdar://problem/3891628> Clean up SCPreferences format
192 Revision 1.271 2004/12/20 23:18:12 cheshire
193 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
194 One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
196 Revision 1.270 2004/12/20 21:28:14 cheshire
197 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
198 Additional refinements to handle sleep/wake better
200 Revision 1.269 2004/12/20 20:48:11 cheshire
201 Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
203 Revision 1.268 2004/12/18 03:19:04 cheshire
204 Show netmask in error log
206 Revision 1.267 2004/12/18 00:51:52 cheshire
207 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
209 Revision 1.266 2004/12/17 23:49:38 cheshire
210 <rdar://problem/3922754> Computer Name change is slow
211 Also treat changes to "Setup:/Network/DynamicDNS" the same way
213 Revision 1.265 2004/12/17 23:37:47 cheshire
214 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
215 (and other repetitive configuration changes)
217 Revision 1.264 2004/12/17 19:03:05 cheshire
218 Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
220 Revision 1.263 2004/12/17 05:25:46 cheshire
221 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
223 Revision 1.262 2004/12/17 04:48:32 cheshire
224 <rdar://problem/3922754> Computer Name change is slow
226 Revision 1.261 2004/12/17 02:40:08 cheshire
227 Undo last change -- it was too strict
229 Revision 1.260 2004/12/16 22:17:16 cheshire
230 Only accept multicast packets on interfaces that have McastTxRx set
232 Revision 1.259 2004/12/16 20:13:01 cheshire
233 <rdar://problem/3324626> Cache memory management improvements
235 Revision 1.258 2004/12/14 00:18:05 cheshire
236 Don't log dns_configuration_copy() failures in the first three minutes after boot
238 Revision 1.257 2004/12/10 19:45:46 cheshire
239 <rdar://problem/3915074> Reduce egregious stack space usage
240 Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
242 Revision 1.256 2004/12/10 04:35:43 cheshire
243 <rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
245 Revision 1.255 2004/12/10 04:12:54 ksekar
246 <rdar://problem/3890764> Need new DefaultBrowseDomain key
248 Revision 1.254 2004/12/10 01:55:31 ksekar
249 <rdar://problem/3899067> Keychain lookups should be in lower case.
251 Revision 1.253 2004/12/09 03:15:41 ksekar
252 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
254 Revision 1.252 2004/12/07 01:32:42 cheshire
255 Don't log dns_configuration_copy() failure when running on 10.3
257 Revision 1.251 2004/12/06 22:30:31 cheshire
258 Added debugging log message
260 Revision 1.250 2004/12/06 06:59:08 ksekar
261 RegisterSplitDNS should return Unsupported error when compiled on Panther
263 Revision 1.249 2004/12/04 00:29:46 cheshire
264 Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
265 (When compiled on 10.3, code will not include split-DNS support.)
267 Revision 1.248 2004/12/01 20:57:20 ksekar
268 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
270 Revision 1.247 2004/12/01 03:26:58 cheshire
271 Remove unused variables
273 Revision 1.246 2004/12/01 01:51:34 cheshire
274 Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
276 Revision 1.245 2004/11/30 03:24:04 cheshire
277 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
279 Revision 1.244 2004/11/30 02:59:35 cheshire
280 For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
282 Revision 1.243 2004/11/29 19:17:29 ksekar
283 <rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
285 Revision 1.242 2004/11/29 18:37:38 ksekar
286 <rdar://problem/3889341> Buffer overflow in GetConfigOption
288 Revision 1.241 2004/11/25 01:37:04 ksekar
289 <rdar://problem/3894854> Config file and SCPreferences don't play well together
291 Revision 1.240 2004/11/25 01:29:42 ksekar
292 Remove unnecessary log messages
294 Revision 1.239 2004/11/25 01:27:19 ksekar
295 <rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
297 Revision 1.238 2004/11/24 22:00:59 cheshire
298 Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
300 Revision 1.237 2004/11/24 21:54:44 cheshire
301 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
303 Revision 1.236 2004/11/23 03:39:46 cheshire
304 Let interface name/index mapping capability live directly in JNISupport.c,
305 instead of having to call through to the daemon via IPC to get this information.
307 Revision 1.235 2004/11/17 01:45:35 cheshire
308 <rdar://problem/3847435> mDNS buddy list frequently becomes empty if you let the machine sleep
309 Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
310 in case we get no System Configuration Framework "network changed" event.
312 Revision 1.234 2004/11/17 00:32:56 ksekar
313 <rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
315 Revision 1.233 2004/11/12 03:16:45 rpantos
316 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
318 Revision 1.232 2004/11/10 20:40:54 ksekar
319 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
321 Revision 1.231 2004/11/06 00:59:33 ksekar
322 Don't log ENETDOWN errors for unicast destinations (pollutes log on
325 Revision 1.230 2004/11/05 01:04:10 ksekar
326 <rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
328 Revision 1.229 2004/11/03 03:45:16 cheshire
329 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
331 Revision 1.228 2004/11/02 23:47:32 cheshire
332 <rdar://problem/3863214> Default hostname and Computer Name should be unique
334 Revision 1.227 2004/11/02 04:23:03 cheshire
335 Change to more informative name "GetUserSpecifiedLocalHostName()"
337 Revision 1.226 2004/11/01 20:36:19 ksekar
338 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
340 Revision 1.225 2004/10/28 19:03:04 cheshire
341 Remove \n from LogMsg() calls
343 Revision 1.224 2004/10/28 17:47:34 cheshire
344 Oops. Forgot the %d in the log message.
346 Revision 1.223 2004/10/28 17:24:28 cheshire
347 Updated "bad ifa_netmask" log message to give more information
349 Revision 1.222 2004/10/28 03:36:34 cheshire
350 <rdar://problem/3856535> Share the same port for both multicast and unicast receiving
352 Revision 1.221 2004/10/28 03:24:41 cheshire
353 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
355 Revision 1.220 2004/10/28 00:53:57 cheshire
356 Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
357 Add LogOperation() call to record when we get network change events
359 Revision 1.219 2004/10/27 20:42:20 cheshire
360 Clean up debugging messages
362 Revision 1.218 2004/10/27 02:03:59 cheshire
363 Update debugging messages
365 Revision 1.217 2004/10/26 20:48:21 cheshire
366 Improve logging messages
368 Revision 1.216 2004/10/26 01:02:37 cheshire
371 Revision 1.215 2004/10/25 20:09:00 ksekar
372 Cleaned up config file parsing.
374 Revision 1.214 2004/10/25 19:30:53 ksekar
375 <rdar://problem/3827956> Simplify dynamic host name structures
377 Revision 1.213 2004/10/23 01:16:01 cheshire
378 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
380 Revision 1.212 2004/10/22 20:52:08 ksekar
381 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
383 Revision 1.211 2004/10/22 01:07:11 cheshire
384 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
385 Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
386 These are all supposed to be remapped to /dev/null
388 Revision 1.210 2004/10/20 02:19:54 cheshire
389 Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
391 Revision 1.209 2004/10/16 00:17:00 cheshire
392 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
394 Revision 1.208 2004/10/15 23:00:18 ksekar
395 <rdar://problem/3799242> Need to update LLQs on location changes
397 Revision 1.207 2004/10/13 22:45:23 cheshire
398 <rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
400 Revision 1.206 2004/10/13 22:11:46 cheshire
401 Update debugging messages
403 Revision 1.205 2004/10/12 21:10:11 cheshire
404 <rdar://problem/3438376> mach_absolute_time() not monotonically increasing
405 Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
407 Revision 1.204 2004/10/12 03:20:52 ksekar
408 <rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
410 Revision 1.203 2004/10/08 04:29:25 ksekar
411 <rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
413 Revision 1.202 2004/10/04 05:56:04 cheshire
414 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
416 Revision 1.201 2004/09/30 00:24:59 ksekar
417 <rdar://problem/3695802> Dynamically update default registration domains on config change
419 Revision 1.200 2004/09/26 23:20:35 ksekar
420 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
422 Revision 1.199 2004/09/24 23:54:55 cheshire
423 <rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
425 Revision 1.198 2004/09/24 23:47:49 cheshire
426 Correct comment and error message
428 Revision 1.197 2004/09/24 23:39:27 cheshire
429 <rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
431 Revision 1.196 2004/09/24 20:53:04 cheshire
432 Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
434 Revision 1.195 2004/09/24 19:21:45 cheshire
435 <rdar://problem/3671626> Report "Address already in use" errors
437 Revision 1.194 2004/09/24 19:16:54 cheshire
438 Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
439 Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
441 Revision 1.193 2004/09/22 00:41:59 cheshire
442 Move tcp connection status codes into the legal range allocated for mDNS use
444 Revision 1.192 2004/09/21 21:02:55 cheshire
445 Set up ifname before calling mDNS_RegisterInterface()
447 Revision 1.191 2004/09/21 19:19:36 cheshire
448 <rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
450 Revision 1.190 2004/09/21 19:04:45 cheshire
451 Strip trailing white space from the ends of lines
453 Revision 1.189 2004/09/21 00:13:28 cheshire
454 Fix build failure (io_connect_t and io_object_t are integers, not pointers)
456 Revision 1.188 2004/09/20 23:52:02 cheshire
457 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
459 Revision 1.187 2004/09/18 01:37:01 cheshire
462 Revision 1.186 2004/09/18 01:11:57 ksekar
463 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
465 Revision 1.185 2004/09/17 01:08:52 cheshire
466 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
467 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
468 declared in that file are ONLY appropriate to single-address-space embedded applications.
469 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
471 Revision 1.184 2004/09/17 00:19:10 cheshire
472 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
474 Revision 1.183 2004/09/17 00:15:56 cheshire
475 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
477 Revision 1.182 2004/09/16 21:36:36 cheshire
478 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
479 Changes to add necessary locking calls around unicast DNS operations
481 Revision 1.181 2004/09/16 02:03:42 cheshire
482 <rdar://problem/3802944> Change address to notify user of kernel flaw
484 Revision 1.180 2004/09/16 01:58:22 cheshire
485 Fix compiler warnings
487 Revision 1.179 2004/09/16 00:24:49 cheshire
488 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
490 Revision 1.178 2004/09/15 21:51:34 cheshire
491 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
492 Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
493 the machine, so make sure we don't do this until at least three minutes after boot.
495 Revision 1.177 2004/09/15 01:16:29 cheshire
496 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
498 Revision 1.176 2004/09/14 23:42:36 cheshire
499 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
501 Revision 1.175 2004/09/14 21:35:46 cheshire
502 Minor code tidying, and added comments about CFRetainCounts
504 Revision 1.174 2004/09/14 19:14:57 ksekar
505 <rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
507 Revision 1.173 2004/08/25 23:35:22 ksekar
508 <rdar://problem/3770615>: Error converting shared secret from base-64 to binary
510 Revision 1.172 2004/08/25 02:01:45 cheshire
511 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
513 Revision 1.171 2004/08/25 01:04:42 cheshire
514 Don't need to CFRelease name and array
516 Revision 1.170 2004/08/25 00:37:28 ksekar
517 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
519 Revision 1.169 2004/08/18 17:35:41 ksekar
520 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
522 Revision 1.168 2004/08/17 03:16:24 ksekar
523 Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
525 Revision 1.167 2004/08/17 00:52:43 ksekar
526 Fix config file parse error, make semantics match SCPreferences
529 Revision 1.166 2004/08/16 19:55:07 ksekar
530 Change enumeration type to BrowseDefault to construct empty-string
531 browse list as result of checking 1.161.
533 Revision 1.165 2004/08/16 19:52:40 ksekar
534 Pass computer name + zone for FQDN after keychain notification,
535 setting global default service registration domain to the zone.
537 Revision 1.164 2004/08/16 16:52:37 ksekar
538 Pass in zone read from keychain to mDNS_SetFQDNs.
540 Revision 1.163 2004/08/14 03:22:42 cheshire
541 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
542 Add GetUserSpecifiedDDNSName() routine
543 Convert ServiceRegDomain to domainname instead of C string
544 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
546 Revision 1.162 2004/08/12 22:34:00 cheshire
547 All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
549 Revision 1.161 2004/08/11 00:17:46 ksekar
550 <rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
551 set default bit for their domains
553 Revision 1.160 2004/07/29 19:27:16 ksekar
554 NATPMP Support - minor fixes and cleanup
556 Revision 1.159 2004/07/26 22:49:31 ksekar
557 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
559 Revision 1.158 2004/07/13 21:24:24 rpantos
560 Fix for <rdar://problem/3701120>.
562 Revision 1.157 2004/06/08 18:54:48 ksekar
563 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
565 Revision 1.156 2004/06/05 00:04:26 cheshire
566 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
568 Revision 1.155 2004/06/04 08:58:30 ksekar
569 <rdar://problem/3668624>: Keychain integration for secure dynamic update
571 Revision 1.154 2004/05/31 22:22:28 ksekar
572 <rdar://problem/3668639>: wide-area domains should be returned in
573 reg. domain enumeration
575 Revision 1.153 2004/05/26 17:06:33 cheshire
576 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
578 Revision 1.152 2004/05/18 23:51:26 cheshire
579 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
581 Revision 1.151 2004/05/17 21:46:34 cheshire
582 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
583 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
585 Revision 1.150 2004/05/13 04:54:20 ksekar
586 Unified list copy/free code. Added symetric list for
588 Revision 1.149 2004/05/13 03:55:14 ksekar
589 Fixed list traversal bug in FoundDefSearchDomain.
591 Revision 1.148 2004/05/12 22:03:08 ksekar
592 Made GetSearchDomainList a true platform-layer call (declaration moved
593 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
594 only on non-OSX platforms. Changed call to return a copy of the list
595 to avoid shared memory issues. Added a routine to free the list.
597 Revision 1.147 2004/05/12 02:03:25 ksekar
598 Non-local domains will only be browsed by default, and show up in
599 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
601 Revision 1.146 2004/04/27 02:49:15 cheshire
602 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
604 Revision 1.145 2004/04/21 03:08:03 cheshire
605 Rename 'alias' to more descriptive name 'primary'
607 Revision 1.144 2004/04/21 03:04:35 cheshire
608 Minor cleanup for clarity
610 Revision 1.143 2004/04/21 03:03:30 cheshire
611 Preparation work: AddInterfaceToList() should return pointer to structure it creates
613 Revision 1.142 2004/04/21 02:49:11 cheshire
614 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
616 Revision 1.141 2004/04/21 02:20:47 cheshire
617 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
619 Revision 1.140 2004/04/14 23:09:29 ksekar
620 Support for TSIG signed dynamic updates.
622 Revision 1.139 2004/04/09 17:40:26 cheshire
623 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
625 Revision 1.138 2004/04/09 16:37:16 cheshire
626 Suggestion from Bob Bradley:
627 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
629 Revision 1.137 2004/04/08 00:59:55 cheshire
630 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
631 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
633 Revision 1.136 2004/04/07 01:08:57 cheshire
634 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
636 Revision 1.135 2004/03/19 01:01:03 ksekar
637 Fixed config file parsing to chop newline
639 Revision 1.134 2004/03/13 01:57:34 ksekar
640 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
642 Revision 1.133 2004/02/02 22:46:56 cheshire
643 Move "CFRelease(dict);" inside the "if (dict)" check
645 Revision 1.132 2004/01/28 02:30:08 ksekar
646 Added default Search Domains to unicast browsing, controlled via
647 Networking sharing prefs pane. Stopped sending unicast messages on
648 every interface. Fixed unicast resolving via mach-port API.
650 Revision 1.131 2004/01/27 22:57:48 cheshire
651 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
653 Revision 1.130 2004/01/27 22:28:40 cheshire
654 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
655 Additional lingering port 53 code deleted
657 Revision 1.129 2004/01/27 20:15:23 cheshire
658 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
660 Revision 1.128 2004/01/24 23:58:17 cheshire
661 Change to use mDNSVal16() instead of shifting and ORing
663 Revision 1.127 2004/01/24 04:59:16 cheshire
664 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
666 Revision 1.126 2004/01/23 23:23:15 ksekar
667 Added TCP support for truncated unicast messages.
669 Revision 1.125 2004/01/22 03:43:09 cheshire
670 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
672 Revision 1.124 2004/01/21 21:53:19 cheshire
673 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
675 Revision 1.123 2004/01/20 03:18:25 cheshire
676 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
678 Revision 1.122 2003/12/17 20:43:59 cheshire
679 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
681 Revision 1.121 2003/12/13 03:05:28 ksekar
682 <rdar://problem/3192548>: DynDNS: Unicast query of service records
684 Revision 1.120 2003/12/08 21:00:46 rpantos
685 Changes to support mDNSResponder on Linux.
687 Revision 1.119 2003/12/03 02:35:15 cheshire
688 Also report value of m->timenow when logging sendto() failure
690 Revision 1.118 2003/11/14 20:59:09 cheshire
691 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
692 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
694 Revision 1.117 2003/11/08 22:18:29 cheshire
695 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
697 Revision 1.116 2003/09/23 16:39:49 cheshire
698 When LogAllOperations is set, also report registration and deregistration of interfaces
700 Revision 1.115 2003/09/10 00:45:55 cheshire
701 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
703 Revision 1.114 2003/08/27 02:55:13 cheshire
704 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
706 Revision 1.113 2003/08/19 22:20:00 cheshire
707 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
708 More minor refinements
710 Revision 1.112 2003/08/19 03:04:43 cheshire
711 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
713 Revision 1.111 2003/08/18 22:53:37 cheshire
714 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
716 Revision 1.110 2003/08/16 03:39:00 cheshire
717 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
719 Revision 1.109 2003/08/15 02:19:49 cheshire
720 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
721 Also limit number of messages to at most 100
723 Revision 1.108 2003/08/12 22:24:52 cheshire
724 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
725 This message indicates a kernel bug, but still we don't want to flood syslog.
726 Do a sleep(1) after writing this log message, to limit the rate.
728 Revision 1.107 2003/08/12 19:56:25 cheshire
731 Revision 1.106 2003/08/12 13:48:32 cheshire
732 Add comment explaining clockdivisor calculation
734 Revision 1.105 2003/08/12 13:44:14 cheshire
735 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
736 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
737 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
739 Revision 1.104 2003/08/12 13:12:07 cheshire
740 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
742 Revision 1.103 2003/08/08 18:36:04 cheshire
743 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
745 Revision 1.102 2003/08/06 00:14:52 cheshire
746 <rdar://problem/3330324> Need to check IP TTL on responses
747 Also add corresponding checks in the IPv6 code path
749 Revision 1.101 2003/08/05 22:20:16 cheshire
750 <rdar://problem/3330324> Need to check IP TTL on responses
752 Revision 1.100 2003/08/05 21:18:50 cheshire
753 <rdar://problem/3363185> mDNSResponder should ignore 6to4
754 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
756 Revision 1.99 2003/08/05 20:13:52 cheshire
757 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
758 Ignore interfaces with the IN6_IFF_NOTREADY flag set
760 Revision 1.98 2003/07/20 03:38:51 ksekar
761 <rdar://problem/3320722>
762 Completed support for Unix-domain socket based API.
764 Revision 1.97 2003/07/19 03:15:16 cheshire
765 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
766 and add the obvious trivial implementations to each platform support layer
768 Revision 1.96 2003/07/18 00:30:00 cheshire
769 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
771 Revision 1.95 2003/07/12 03:15:20 cheshire
772 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
773 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
775 Revision 1.94 2003/07/03 00:51:54 cheshire
776 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
778 Revision 1.93 2003/07/03 00:09:14 cheshire
779 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
780 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
782 Revision 1.92 2003/07/02 21:19:51 cheshire
783 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
785 Revision 1.91 2003/06/24 01:53:51 cheshire
786 Minor update to comments
788 Revision 1.90 2003/06/24 01:51:47 cheshire
789 <rdar://problem/3303118> Oops: Double-dispose of sockets
790 Don't need to close sockets: CFSocketInvalidate() does that for us
792 Revision 1.89 2003/06/21 18:12:47 cheshire
793 <rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
794 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
796 Revision 1.88 2003/06/12 23:38:37 cheshire
797 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
798 Also check that scope_id matches before concluding that two interfaces are the same
800 Revision 1.87 2003/06/10 01:14:11 cheshire
801 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
803 Revision 1.86 2003/05/28 02:41:52 cheshire
804 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
806 Revision 1.85 2003/05/28 02:39:47 cheshire
807 Minor change to debugging messages
809 Revision 1.84 2003/05/27 22:29:40 cheshire
810 Remove out-dated comment
812 Revision 1.83 2003/05/26 03:21:29 cheshire
813 Tidy up address structure naming:
814 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
815 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
816 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
818 Revision 1.82 2003/05/26 03:01:27 cheshire
819 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
821 Revision 1.81 2003/05/24 02:06:42 cheshire
822 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
823 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
824 However, it is probably wise to have the code explicitly set this socket
825 option anyway, in case the default changes in later versions of Unix.
827 Revision 1.80 2003/05/24 02:02:24 cheshire
828 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
829 Fix error in myIfIndexToName; was returning prematurely
831 Revision 1.79 2003/05/23 23:07:44 cheshire
832 <rdar://problem/3268199> Must not write to stderr when running as daemon
834 Revision 1.78 2003/05/23 01:19:04 cheshire
835 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
836 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
838 Revision 1.77 2003/05/23 01:12:05 cheshire
841 Revision 1.76 2003/05/22 01:26:01 cheshire
844 Revision 1.75 2003/05/22 00:07:09 cheshire
845 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
846 Extra logging to determine whether there is a bug in CFSocket
848 Revision 1.74 2003/05/21 20:20:12 cheshire
849 Fix warnings (mainly printf format string warnings, like using "%d" where
850 it should say "%lu", etc.) and improve error logging (use strerror()
851 to include textual error message as well as numeric error in log messages).
853 Revision 1.73 2003/05/21 17:56:29 ksekar
854 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
856 Revision 1.72 2003/05/14 18:48:41 cheshire
857 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
858 More minor refinements:
859 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
860 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
862 Revision 1.71 2003/05/14 07:08:37 cheshire
863 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
864 Previously, when there was any network configuration change, mDNSResponder
865 would tear down the entire list of active interfaces and start again.
866 That was very disruptive, and caused the entire cache to be flushed,
867 and caused lots of extra network traffic. Now it only removes interfaces
868 that have really gone, and only adds new ones that weren't there before.
870 Revision 1.70 2003/05/07 18:30:24 cheshire
871 Fix signed/unsigned comparison warning
873 Revision 1.69 2003/05/06 20:14:44 cheshire
876 Revision 1.68 2003/05/06 00:00:49 cheshire
877 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
879 Revision 1.67 2003/04/29 00:43:44 cheshire
880 Fix compiler warnings
882 Revision 1.66 2003/04/26 02:41:58 cheshire
883 <rdar://problem/3241281> Change timenow from a local variable to a structure member
885 Revision 1.65 2003/04/26 02:34:01 cheshire
886 Add missing mDNSexport
888 Revision 1.64 2003/04/15 16:48:06 jgraessl
889 <rdar://problem/3228833>
890 Modified code in CFSocket notifier function to read all packets on the socket
891 instead of reading only one packet every time the notifier was called.
893 Revision 1.63 2003/04/15 16:33:50 jgraessl
894 <rdar://problem/3221880>
895 Switched to our own copy of if_indextoname to improve performance.
897 Revision 1.62 2003/03/28 01:55:44 cheshire
898 Minor improvements to debugging messages
900 Revision 1.61 2003/03/27 03:30:56 cheshire
901 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
902 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
904 1. Make mDNS_DeregisterInterface() safe to call from a callback
905 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
906 (it never really needed to deregister the interface at all)
908 Revision 1.60 2003/03/15 04:40:38 cheshire
909 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
911 Revision 1.59 2003/03/11 01:23:26 cheshire
912 <rdar://problem/3194246> mDNSResponder socket problems
914 Revision 1.58 2003/03/06 01:43:04 cheshire
915 <rdar://problem/3189097> Additional debugging code in mDNSResponder
916 Improve "LIST_ALL_INTERFACES" output
918 Revision 1.57 2003/03/05 22:36:27 cheshire
919 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
920 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
922 Revision 1.56 2003/03/05 01:50:38 cheshire
923 <rdar://problem/3189097> Additional debugging code in mDNSResponder
925 Revision 1.55 2003/02/21 01:54:09 cheshire
926 <rdar://problem/3099194> mDNSResponder needs performance improvements
927 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
929 Revision 1.54 2003/02/20 06:48:35 cheshire
930 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
931 Reviewed by: Josh Graessley, Bob Bradley
933 Revision 1.53 2003/01/29 02:21:23 cheshire
934 Return mStatus_Invalid if can't send packet because socket not available
936 Revision 1.52 2003/01/28 19:39:43 jgraessl
937 Enabling AAAA over IPv4 support.
939 Revision 1.51 2003/01/28 05:11:23 cheshire
940 Fixed backwards comparison in SearchForInterfaceByName
942 Revision 1.50 2003/01/13 23:49:44 jgraessl
943 Merged changes for the following fixes in to top of tree:
944 <rdar://problem/3086540> computer name changes not handled properly
945 <rdar://problem/3124348> service name changes are not properly handled
946 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
948 Revision 1.49 2002/12/23 22:13:30 jgraessl
949 Reviewed by: Stuart Cheshire
950 Initial IPv6 support for mDNSResponder.
952 Revision 1.48 2002/11/22 01:37:52 cheshire
953 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
955 Revision 1.47 2002/09/21 20:44:51 zarzycki
958 Revision 1.46 2002/09/19 21:25:35 cheshire
959 mDNS_snprintf() doesn't need to be in a separate file
961 Revision 1.45 2002/09/17 01:45:13 cheshire
962 Add LIST_ALL_INTERFACES symbol for debugging
964 Revision 1.44 2002/09/17 01:36:23 cheshire
965 Move Puma support to mDNSMacOSXPuma.c
967 Revision 1.43 2002/09/17 01:05:28 cheshire
968 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
970 Revision 1.42 2002/09/16 23:13:50 cheshire
975 // ***************************************************************************
977 // Supporting routines to run mDNS on a CFRunLoop platform
978 // ***************************************************************************
980 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
981 // including ones that mDNSResponder chooses not to use.
982 #define LIST_ALL_INTERFACES 0
984 // For enabling AAAA records over IPv4. Setting this to 0 sends only
985 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
986 // AAAA and A records over both IPv4 and IPv6.
987 #define AAAA_OVER_V4 1
989 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
990 #include "DNSCommon.h"
991 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
992 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
993 #include "PlatformCommon.h"
996 #include <stdarg.h> // For va_list support
998 #include <net/if_types.h> // For IFT_ETHER
999 #include <net/if_dl.h>
1000 #include <sys/uio.h>
1001 #include <sys/param.h>
1002 #include <sys/socket.h>
1003 #include <sys/sysctl.h>
1005 #include <sys/ioctl.h>
1006 #include <time.h> // platform support for UTC time
1007 #include <arpa/inet.h> // for inet_aton
1009 #include <netinet/in.h> // For IP_RECVTTL
1011 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
1014 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
1015 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
1016 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
1018 #include <Security/Security.h>
1020 #include "dnsinfo.h"
1022 // Code contributed by Dave Heller:
1023 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
1024 // work on Mac OS X 10.1, which does not have the getifaddrs call.
1025 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
1026 #if RUN_ON_PUMA_WITHOUT_IFADDRS
1027 #include "mDNSMacOSXPuma.c"
1029 #include <ifaddrs.h>
1032 #include <IOKit/IOKitLib.h>
1033 #include <IOKit/IOMessage.h>
1034 #include <mach/mach_time.h>
1036 typedef struct SearchListElem
1038 struct SearchListElem
*next
;
1041 DNSQuestion BrowseQ
;
1042 DNSQuestion DefBrowseQ
;
1043 DNSQuestion LegacyBrowseQ
;
1044 DNSQuestion RegisterQ
;
1045 DNSQuestion DefRegisterQ
;
1046 ARListElem
*AuthRecs
;
1050 // ***************************************************************************
1053 static mDNSu32 clockdivisor
= 0;
1055 // for domain enumeration and default browsing/registration
1056 static SearchListElem
*SearchList
= NULL
; // where we search for _browse domains
1057 static DNSQuestion LegacyBrowseDomainQ
; // our local enumeration query for _legacy._browse domains
1058 static DNameListElem
*DefBrowseList
= NULL
; // cache of answers to above query (where we search for empty string browses)
1059 static DNameListElem
*DefRegList
= NULL
; // manually generated list of domains where we register for empty string registrations
1060 static ARListElem
*SCPrefBrowseDomains
= NULL
; // manually generated local-only PTR records for browse domains we get from SCPreferences
1062 static domainname DynDNSRegDomain
; // Default wide-area zone for service registration
1063 static CFArrayRef DynDNSBrowseDomains
= NULL
; // Default wide-area zones for legacy ("empty string") browses
1064 static domainname DynDNSHostname
;
1066 static mDNSBool DomainDiscoveryDisabled
= mDNSfalse
;
1068 #define CONFIG_FILE "/etc/mDNSResponder.conf"
1069 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
1070 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
1072 // Function Prototypes
1073 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
);
1075 // ***************************************************************************
1078 // routines to allow access to default domain lists from daemon layer
1080 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
1082 return mDNS_CopyDNameList(DefBrowseList
);
1085 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
1087 return mDNS_CopyDNameList(DefRegList
);
1090 // utility routines to manage registration domain lists
1092 mDNSlocal
void AddDefRegDomain(domainname
*d
)
1094 DNameListElem
*newelem
= NULL
, *ptr
;
1096 // make sure name not already in list
1097 for (ptr
= DefRegList
; ptr
; ptr
= ptr
->next
)
1099 if (SameDomainName(&ptr
->name
, d
))
1100 { debugf("duplicate addition of default reg domain %##s", d
->c
); return; }
1103 newelem
= mallocL("DNameListElem", sizeof(*newelem
));
1104 if (!newelem
) { LogMsg("Error - malloc"); return; }
1105 AssignDomainName(&newelem
->name
, d
);
1106 newelem
->next
= DefRegList
;
1107 DefRegList
= newelem
;
1109 DefaultRegDomainChanged(d
, mDNStrue
);
1110 udsserver_default_reg_domain_changed(d
, mDNStrue
);
1113 mDNSlocal
void RemoveDefRegDomain(domainname
*d
)
1115 DNameListElem
*ptr
= DefRegList
, *prev
= NULL
;
1119 if (SameDomainName(&ptr
->name
, d
))
1121 if (prev
) prev
->next
= ptr
->next
;
1122 else DefRegList
= ptr
->next
;
1123 freeL("DNameListElem", ptr
);
1124 DefaultRegDomainChanged(d
, mDNSfalse
);
1125 udsserver_default_reg_domain_changed(d
, mDNSfalse
);
1131 debugf("Requested removal of default registration domain %##s not in contained in list", d
->c
);
1134 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
1136 static int notifyCount
= 0;
1137 if (notifyCount
) return;
1139 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1140 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1141 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
1143 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
1146 // Determine if we're at Apple (17.*.*.*)
1147 extern mDNS mDNSStorage
;
1148 NetworkInterfaceInfoOSX
*i
;
1149 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
1150 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
1152 if (!i
) return; // If not at Apple, don't show the alert
1156 LogMsg("%s", title
);
1158 // Display a notification to the user
1160 static const char footer
[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
1161 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
1162 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
1163 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
1164 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
1165 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
1168 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
1170 static struct ifaddrs
*ifa
= NULL
;
1178 if (ifa
== NULL
) getifaddrs(&ifa
);
1183 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
1185 NetworkInterfaceInfoOSX
*i
;
1186 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1187 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
1189 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1190 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1194 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
1196 struct ifaddrs
*ifa
;
1197 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
1198 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1199 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
1200 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
1204 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
1206 NetworkInterfaceInfoOSX
*i
;
1207 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
1209 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1210 // Don't get tricked by inactive interfaces with no InterfaceID set
1211 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
1215 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
1217 NetworkInterfaceInfoOSX
*i
;
1218 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
1220 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1221 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1222 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
1226 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
1228 mDNSBool result
= mDNSfalse
;
1229 SCNetworkConnectionFlags flags
;
1230 SCNetworkReachabilityRef ReachRef
= NULL
;
1232 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
1233 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
1234 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
1235 result
= flags
& kSCNetworkFlagsConnectionRequired
;
1238 if (ReachRef
) CFRelease(ReachRef
);
1242 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1243 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1244 // OR send via our primary v4 unicast socket
1245 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1246 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
1250 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1251 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1252 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1253 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
1254 char *ifa_name
= info
? info
->ifa_name
: "unicast";
1255 struct sockaddr_storage to
;
1258 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
1259 // anonymous socket created for this purpose, so that we'll receive the response.
1260 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
1261 if (info
&& !mDNSAddrIsDNSMulticast(dst
))
1263 const DNSMessage
*const m
= (DNSMessage
*)msg
;
1264 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
1265 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
1268 if (dst
->type
== mDNSAddrType_IPv4
)
1270 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1271 sin_to
->sin_len
= sizeof(*sin_to
);
1272 sin_to
->sin_family
= AF_INET
;
1273 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1274 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1275 s
= info
? info
->ss
.sktv4
: m
->p
->unicastsockets
.sktv4
;
1277 else if (dst
->type
== mDNSAddrType_IPv6
)
1279 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1280 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1281 sin6_to
->sin6_family
= AF_INET6
;
1282 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1283 sin6_to
->sin6_flowinfo
= 0;
1284 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1285 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1286 s
= info
? info
->ss
.sktv6
: m
->p
->unicastsockets
.sktv6
;
1290 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1291 return mStatus_BadParamErr
;
1294 // Don't send if it would cause dial on demand connection initiation. As an optimization,
1295 // don't bother consulting reachability API / routing table when sending Multicast DNS
1296 // since we ignore PPP interfaces for mDNS traffic
1297 if (!mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
1299 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1300 return mStatus_NoError
;
1304 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1305 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1307 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1308 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1310 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1311 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1312 if (s
< 0) return(mStatus_Invalid
);
1314 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1317 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1318 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1319 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1320 // Don't report EHOSTUNREACH in the first three minutes after boot
1321 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1322 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1323 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1324 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1325 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1326 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1327 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1328 return(mStatus_UnknownErr
);
1331 return(mStatus_NoError
);
1334 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1335 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1337 static unsigned int numLogMessages
= 0;
1338 struct iovec databuffers
= { (char *)buffer
, max
};
1341 struct cmsghdr
*cmPtr
;
1342 char ancillary
[1024];
1344 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1346 // Set up the message
1347 msg
.msg_name
= (caddr_t
)from
;
1348 msg
.msg_namelen
= *fromlen
;
1349 msg
.msg_iov
= &databuffers
;
1351 msg
.msg_control
= (caddr_t
)&ancillary
;
1352 msg
.msg_controllen
= sizeof(ancillary
);
1356 n
= recvmsg(s
, &msg
, 0);
1359 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1362 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1364 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1365 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1368 if (msg
.msg_flags
& MSG_CTRUNC
)
1370 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1374 *fromlen
= msg
.msg_namelen
;
1376 // Parse each option out of the ancillary data.
1377 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1379 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1380 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1382 dstaddr
->type
= mDNSAddrType_IPv4
;
1383 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
1385 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1387 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1388 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1390 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
1391 ifname
[sdl
->sdl_nlen
] = 0;
1392 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1395 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1397 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1399 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1401 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1402 dstaddr
->type
= mDNSAddrType_IPv6
;
1403 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1404 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1406 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1408 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1415 // On entry, context points to our CFSocketSet
1416 // If ss->info is NULL, we received this packet on our anonymous unicast socket
1417 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
1418 mDNSlocal
void myCFSocketCallBack(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
1420 const CFSocketSet
*const ss
= (const CFSocketSet
*)context
;
1421 mDNS
*const m
= ss
->m
;
1422 const int skt
= CFSocketGetNative(cfs
);
1423 const int s1
= (cfs
== ss
->cfsv4
) ? ss
->sktv4
: (cfs
== ss
->cfsv6
) ? ss
->sktv6
: -1;
1426 (void)address
; // Parameter not used
1427 (void)data
; // Parameter not used
1429 if (CallBackType
!= kCFSocketReadCallBack
)
1430 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
1432 if (s1
< 0 || s1
!= skt
)
1434 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
1435 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss
->cfsv4
, ss
->sktv4
);
1436 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss
->cfsv6
, ss
->sktv6
);
1441 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1442 mDNSInterfaceID InterfaceID
= ss
->info
? ss
->info
->ifinfo
.InterfaceID
: mDNSNULL
;
1443 mDNSAddr senderAddr
, destAddr
;
1444 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1445 struct sockaddr_storage from
;
1446 size_t fromlen
= sizeof(from
);
1447 char packetifname
[IF_NAMESIZE
] = "";
1449 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1453 if (from
.ss_family
== AF_INET
)
1455 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1456 senderAddr
.type
= mDNSAddrType_IPv4
;
1457 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1458 senderPort
.NotAnInteger
= sin
->sin_port
;
1460 else if (from
.ss_family
== AF_INET6
)
1462 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1463 senderAddr
.type
= mDNSAddrType_IPv6
;
1464 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1465 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1469 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
1473 if (mDNSAddrIsDNSMulticast(&destAddr
))
1475 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
1476 // sockets API means that even though this socket has only officially joined the multicast group
1477 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1478 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1479 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
1480 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1481 if (!ss
->info
|| !ss
->info
->Exists
)
1483 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr
, &destAddr
);
1486 else if (strcmp(ss
->info
->ifa_name
, packetifname
))
1488 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
1489 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
, packetifname
);
1493 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
1494 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
);
1498 // Note: Unicast packets are delivered to *one* of our listening sockets,
1499 // not necessarily the one bound to the physical interface where the packet arrived.
1500 // To sort this out we search our interface list and update InterfaceID to reference
1501 // the mDNSCore interface object for the interface where the packet was actually received.
1502 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1503 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1504 if (intf
) InterfaceID
= intf
->InterfaceID
;
1507 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1510 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1512 // Something is busted here.
1513 // CFSocket says there is a packet, but myrecvfrom says there is not.
1514 // Try calling select() to get another opinion.
1515 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1516 // All of this is racy, as data may have arrived after the call to select()
1517 int save_errno
= errno
;
1521 socklen_t solen
= sizeof(int);
1524 FD_SET(s1
, &readfds
);
1525 struct timeval timeout
;
1527 timeout
.tv_usec
= 0;
1528 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1529 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1530 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1531 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1532 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1533 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1534 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
1535 static unsigned int numLogMessages
= 0;
1536 if (numLogMessages
++ < 100)
1537 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1538 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1539 if (numLogMessages
> 5)
1540 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1541 "Congratulations, you've reproduced an elusive bug.\r"
1542 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1543 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1544 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1546 sleep(1); // After logging this error, rate limit so we don't flood syslog
1550 // TCP socket support for unicast DNS and Dynamic DNS Update
1554 TCPConnectionCallback callback
;
1559 mDNSlocal
void tcpCFSocketCallback(CFSocketRef cfs
, CFSocketCallBackType CallbackType
, CFDataRef address
,
1560 const void *data
, void *context
)
1562 #pragma unused(CallbackType, address, data)
1563 mDNSBool connect
= mDNSfalse
;
1565 tcpInfo_t
*info
= context
;
1566 if (!info
->connected
)
1569 info
->connected
= mDNStrue
; // prevent connected flag from being set in future callbacks
1571 info
->callback(CFSocketGetNative(cfs
), info
->context
, connect
);
1572 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1575 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1576 TCPConnectionCallback callback
, void *context
, int *descriptor
)
1578 int sd
, on
= 1; // "on" for setsockopt
1579 struct sockaddr_in saddr
;
1580 CFSocketContext cfContext
= { 0, NULL
, 0, 0, 0 };
1583 CFRunLoopSourceRef rls
;
1585 (void)InterfaceID
; //!!!KRS use this if non-zero!!!
1588 if (dst
->type
!= mDNSAddrType_IPv4
)
1590 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1591 return mStatus_UnknownErr
;
1594 bzero(&saddr
, sizeof(saddr
));
1595 saddr
.sin_family
= AF_INET
;
1596 saddr
.sin_port
= dstport
.NotAnInteger
;
1597 saddr
.sin_len
= sizeof(saddr
);
1598 memcpy(&saddr
.sin_addr
, &dst
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1600 // Don't send if it would cause dial on demand connection initiation.
1601 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1603 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1604 return mStatus_UnknownErr
;
1607 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1608 if (sd
< 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd
, errno
, strerror(errno
)); return mStatus_UnknownErr
; }
1611 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
1613 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1614 return mStatus_UnknownErr
;
1617 // receive interface identifiers
1618 if (setsockopt(sd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1620 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
));
1621 return mStatus_UnknownErr
;
1623 // set up CF wrapper, add to Run Loop
1624 info
= mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t
));
1625 info
->callback
= callback
;
1626 info
->context
= context
;
1627 cfContext
.info
= info
;
1628 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
| kCFSocketConnectCallBack
,
1629 tcpCFSocketCallback
, &cfContext
);
1632 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
1633 freeL("mDNSPlatformTCPConnect", info
);
1634 return mStatus_UnknownErr
;
1637 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
1640 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
1641 freeL("mDNSPlatformTCPConnect", info
);
1642 return mStatus_UnknownErr
;
1645 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1648 // initiate connection wth peer
1649 if (connect(sd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1651 if (errno
== EINPROGRESS
)
1653 info
->connected
= 0;
1655 return mStatus_ConnPending
;
1657 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno
));
1658 freeL("mDNSPlatformTCPConnect", info
);
1659 CFSocketInvalidate(sr
); // Note: Also closes the underlying socket
1660 return mStatus_ConnFailed
;
1662 info
->connected
= 1;
1664 return mStatus_ConnEstablished
;
1667 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
1669 CFSocketContext cfContext
;
1673 if (sd
< 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd
);
1675 // Get the CFSocket for the descriptor
1676 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketNoCallBack
, NULL
, NULL
);
1677 if (!sr
) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
1679 CFSocketGetContext(sr
, &cfContext
);
1680 if (!cfContext
.info
)
1682 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
1686 CFRelease(sr
); // this only releases the copy we allocated with CreateWithNative above
1688 info
= cfContext
.info
;
1690 // Note: MUST NOT close the underlying native BSD socket.
1691 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1692 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1693 CFSocketInvalidate(sr
);
1695 freeL("mDNSPlatformTCPCloseConnection", info
);
1698 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
1700 int nread
= recv(sd
, buf
, buflen
, 0);
1703 if (errno
== EAGAIN
) return 0; // no data available (call would block)
1704 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno
));
1710 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
1712 int nsent
= send(sd
, msg
, len
, 0);
1716 if (errno
== EAGAIN
) return 0; // blocked
1717 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno
));
1723 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1724 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1726 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1727 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1730 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1735 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1736 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1738 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1741 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1746 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1749 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1750 if (!state
) return mDNSfalse
;
1751 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1752 return val
? mDNStrue
: mDNSfalse
;
1755 mDNSlocal
void GetUserSpecifiedDDNSConfig(domainname
*const fqdn
, domainname
*const regDomain
, CFArrayRef
*const browseDomains
)
1757 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1760 regDomain
->c
[0] = 0;
1762 *browseDomains
= NULL
;
1764 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL
, NULL
);
1767 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, CFSTR("Setup:/Network/DynamicDNS"));
1770 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("HostNames"));
1771 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
1773 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
1774 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
1776 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
1779 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1780 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
1781 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
1782 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
1787 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("RegistrationDomains"));
1788 if (regArray
&& CFArrayGetCount(regArray
) > 0)
1790 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
1791 if (regDict
&& DDNSSettingEnabled(regDict
))
1793 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
1796 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1797 !MakeDomainNameFromDNSNameString(regDomain
, buf
) || !regDomain
->c
[0])
1798 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
1799 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf
);
1803 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("BrowseDomains"));
1804 if (browseArray
&& CFArrayGetCount(browseArray
) > 0)
1806 CFRetain(browseArray
);
1807 *browseDomains
= browseArray
;
1815 mDNSlocal
void SetDDNSNameStatus(domainname
*const dname
, mStatus status
)
1817 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL
, NULL
);
1820 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1821 ConvertDomainNameToCString(dname
, uname
);
1827 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1831 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
1832 // That single entity is a CFDictionary with name "HostNames".
1833 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
1834 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
1835 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
1836 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
1837 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
1839 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
1840 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
1841 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
1842 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
1845 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
1846 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
1849 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
1852 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
1855 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
1858 SCDynamicStoreSetValue(store
, CFSTR("State:/Network/DynamicDNS"), StateDict
);
1859 CFRelease(StateDict
);
1861 CFRelease(StateVals
[0]);
1863 CFRelease(HostVals
[0]);
1865 CFRelease(StatusVals
[0]);
1867 CFRelease(HostKeys
[0]);
1873 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1874 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1875 mDNSlocal mStatus
SetupSocket(mDNS
*const m
, CFSocketSet
*cp
, mDNSBool mcast
, const mDNSAddr
*ifaddr
, u_short sa_family
)
1877 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1878 CFSocketRef
*c
= (sa_family
== AF_INET
) ? &cp
->cfsv4
: &cp
->cfsv6
;
1879 CFRunLoopSourceRef
*r
= (sa_family
== AF_INET
) ? &cp
->rlsv4
: &cp
->rlsv6
;
1881 const int twofivefive
= 255;
1882 mStatus err
= mStatus_NoError
;
1883 char *errstr
= mDNSNULL
;
1885 mDNSIPPort port
= (mcast
| m
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1887 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
1888 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
1890 // Open the socket...
1891 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1892 if (skt
< 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1894 // ... with a shared UDP port, if it's for multicast receiving
1895 if (port
.NotAnInteger
) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1896 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1898 if (sa_family
== AF_INET
)
1900 // We want to receive destination addresses
1901 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1902 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1904 // We want to receive interface identifiers
1905 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1906 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1908 // We want to receive packet TTL value so we can check it
1909 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1910 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1912 // Add multicast group membership on this interface, if it's for multicast receiving
1915 struct in_addr addr
= { ifaddr
->ip
.v4
.NotAnInteger
};
1917 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1918 imr
.imr_interface
= addr
;
1919 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
1920 if (err
< 0) { errstr
= "setsockopt - IP_ADD_MEMBERSHIP"; goto fail
; }
1922 // Specify outgoing interface too
1923 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
1924 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_IF"; goto fail
; }
1927 // Send unicast packets with TTL 255
1928 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1929 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1931 // And multicast packets with TTL 255 too
1932 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1933 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1935 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1936 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1937 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1938 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1940 // And start listening for packets
1941 struct sockaddr_in listening_sockaddr
;
1942 listening_sockaddr
.sin_family
= AF_INET
;
1943 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1944 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1945 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1946 if (err
) { errstr
= "bind"; goto fail
; }
1948 else if (sa_family
== AF_INET6
)
1950 // We want to receive destination addresses and receive interface identifiers
1951 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1952 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1954 // We want to receive packet hop count value so we can check it
1955 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1956 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1958 // We want to receive only IPv6 packets, without this option, we may
1959 // get IPv4 addresses as mapped addresses.
1960 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1961 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1965 // Add multicast group membership on this interface, if it's for multicast receiving
1966 int interface_id
= if_nametoindex(cp
->info
->ifa_name
);
1967 struct ipv6_mreq i6mr
;
1968 i6mr
.ipv6mr_interface
= interface_id
;
1969 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
1970 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
1971 if (err
< 0) { errstr
= "setsockopt - IPV6_JOIN_GROUP"; goto fail
; }
1973 // Specify outgoing interface too
1974 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
1975 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_IF"; goto fail
; }
1978 // Send unicast packets with TTL 255
1979 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1980 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1982 // And multicast packets with TTL 255 too
1983 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1984 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1986 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1988 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1989 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1990 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1991 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1994 // Want to receive our own packets
1995 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1996 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1998 // And start listening for packets
1999 struct sockaddr_in6 listening_sockaddr6
;
2000 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
2001 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
2002 listening_sockaddr6
.sin6_family
= AF_INET6
;
2003 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
2004 listening_sockaddr6
.sin6_flowinfo
= 0;
2005 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
2006 listening_sockaddr6
.sin6_scope_id
= 0;
2007 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
2008 if (err
) { errstr
= "bind"; goto fail
; }
2011 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
2013 CFSocketContext myCFSocketContext
= { 0, cp
, NULL
, NULL
, NULL
};
2014 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
2015 *r
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
2016 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r
, kCFRunLoopDefaultMode
);
2021 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
2022 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
2023 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
2024 "Congratulations, you've reproduced an elusive bug.\r"
2025 "Please contact the current assignee of <rdar://problem/3814904>.\r"
2026 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
2027 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
2032 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2034 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2036 if (sa
->sa_family
== AF_INET
)
2038 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2039 ip
->type
= mDNSAddrType_IPv4
;
2040 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2041 return(mStatus_NoError
);
2044 if (sa
->sa_family
== AF_INET6
)
2046 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2047 ip
->type
= mDNSAddrType_IPv6
;
2048 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2049 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2050 return(mStatus_NoError
);
2053 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2054 return(mStatus_Invalid
);
2057 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2059 mDNSEthAddr eth
= zeroEthAddr
;
2060 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2063 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2066 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2069 CFRange range
= { 0, 6 }; // Offset, length
2070 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2071 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2074 CFRelease(entityname
);
2081 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2083 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2084 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2087 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2088 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2090 NetworkInterfaceInfoOSX
**p
;
2091 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2092 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2094 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2095 (*p
)->Exists
= mDNStrue
;
2099 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2100 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2101 if (!i
) return(mDNSNULL
);
2102 bzero(i
, sizeof(NetworkInterfaceInfoOSX
));
2103 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2104 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2105 strcpy(i
->ifa_name
, ifa
->ifa_name
);
2107 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2109 i
->ifinfo
.mask
= mask
;
2110 strncpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2111 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2112 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2113 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2116 i
->Exists
= mDNStrue
;
2118 i
->scope_id
= scope_id
;
2120 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2121 i
->Multicast
= (ifa
->ifa_flags
& IFF_MULTICAST
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
);
2125 i
->ss
.sktv4
= i
->ss
.sktv6
= -1;
2126 i
->ss
.cfsv4
= i
->ss
.cfsv6
= NULL
;
2127 i
->ss
.rlsv4
= i
->ss
.rlsv6
= NULL
;
2133 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2135 NetworkInterfaceInfoOSX
*i
;
2136 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2137 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2138 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
2143 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2145 mDNSBool foundav4
= mDNSfalse
;
2146 mDNSBool foundav6
= mDNSfalse
;
2147 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2148 struct ifaddrs
*v4Loopback
= NULL
;
2149 struct ifaddrs
*v6Loopback
= NULL
;
2150 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2151 char defaultname
[32];
2152 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2153 if (InfoSocket
< 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2154 if (m
->SleepState
) ifa
= NULL
;
2158 #if LIST_ALL_INTERFACES
2159 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2160 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2161 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2162 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2163 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2164 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2165 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2166 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2167 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2168 if (!(ifa
->ifa_flags
& IFF_UP
))
2169 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2170 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2171 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2172 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2173 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2174 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2175 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2176 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2177 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2178 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2179 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2182 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2184 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2185 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2186 mDNSPlatformMemCopy(sdl
->sdl_data
+ sdl
->sdl_nlen
, PrimaryMAC
.b
, 6);
2189 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2190 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2192 if (!ifa
->ifa_netmask
)
2195 SetupAddr(&ip
, ifa
->ifa_addr
);
2196 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2197 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2199 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2202 SetupAddr(&ip
, ifa
->ifa_addr
);
2203 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2204 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2208 int ifru_flags6
= 0;
2209 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2211 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2212 struct in6_ifreq ifr6
;
2213 bzero((char *)&ifr6
, sizeof(ifr6
));
2214 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2215 ifr6
.ifr_addr
= *sin6
;
2216 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2217 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2218 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2220 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2222 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2223 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2224 else v6Loopback
= ifa
;
2227 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2228 if (i
&& i
->Multicast
)
2230 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2231 else foundav6
= mDNStrue
;
2237 ifa
= ifa
->ifa_next
;
2240 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2241 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2242 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2244 // Now the list is complete, set the McastTxRx setting for each interface.
2245 // We always send and receive using IPv4.
2246 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
2247 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
2248 // which means there's a good chance that most or all the other devices on that network should also have v4.
2249 // 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.
2250 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
2251 // so we are willing to make that sacrifice.
2252 NetworkInterfaceInfoOSX
*i
;
2253 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2256 mDNSBool txrx
= i
->Multicast
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2257 if (i
->ifinfo
.McastTxRx
!= txrx
)
2259 i
->ifinfo
.McastTxRx
= txrx
;
2260 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2263 if (InfoSocket
>= 0) close(InfoSocket
);
2265 mDNS_snprintf(defaultname
, sizeof(defaultname
), "Macintosh-%02X%02X%02X%02X%02X%02X",
2266 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2268 // Set up the nice label
2269 domainlabel nicelabel
;
2271 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2272 if (nicelabel
.c
[0] == 0)
2274 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2275 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2278 // Set up the RFC 1034-compliant label
2279 domainlabel hostlabel
;
2281 GetUserSpecifiedLocalHostName(&hostlabel
);
2282 if (hostlabel
.c
[0] == 0)
2284 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2285 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2288 if (SameDomainLabel(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2289 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2292 debugf("Updating m->nicelabel to %#s", nicelabel
.c
);
2293 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2296 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2297 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2300 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
2301 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2305 return(mStatus_NoError
);
2308 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2310 int i
= 0, bits
= 0;
2311 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2314 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2315 while (b
& 0x80) { bits
++; b
<<= 1; }
2318 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2322 // returns count of non-link local V4 addresses registered
2323 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2325 NetworkInterfaceInfoOSX
*i
;
2327 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2330 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
2331 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2332 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2334 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2336 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2337 n
->InterfaceID
= mDNSNULL
;
2340 if (!n
->InterfaceID
)
2342 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2343 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2344 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2345 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2346 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2347 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2348 // 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.
2349 mDNSBool flapping
= (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2350 mDNS_RegisterInterface(m
, n
, flapping
? mDNSPlatformOneSecond
* 5 : 0);
2351 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2352 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
2353 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2354 flapping
? " (Flapping)" : "", n
->InterfaceActive
? " (Primary)" : "");
2358 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2361 if (i
->sa_family
== AF_INET
&& primary
->ss
.sktv4
== -1)
2363 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET
);
2364 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
));
2365 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
));
2368 if (i
->sa_family
== AF_INET6
&& primary
->ss
.sktv6
== -1)
2370 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET6
);
2371 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
));
2372 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
));
2379 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2381 NetworkInterfaceInfoOSX
*i
;
2382 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2384 if (i
->Exists
) i
->LastSeen
= utc
;
2385 i
->Exists
= mDNSfalse
;
2389 mDNSlocal
void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls
, CFSocketRef cfs
)
2391 // Note: CFSocketInvalidate also closes the underlying socket for us
2392 // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
2393 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); // rls 2 cfs 3
2394 CFRelease(rls
); // rls ? cfs 3
2395 CFSocketInvalidate(cfs
); // rls ? cfs 1
2396 CFRelease(cfs
); // rls ? cfs ?
2399 mDNSlocal
void CloseSocketSet(CFSocketSet
*ss
)
2401 // Note: MUST NOT close the underlying native BSD sockets.
2402 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
2403 // because it first has to unhook the sockets from its select() call, before it can safely close them.
2404 if (ss
->cfsv4
) CloseRunLoopSourceSocket(ss
->rlsv4
, ss
->cfsv4
);
2405 if (ss
->cfsv6
) CloseRunLoopSourceSocket(ss
->rlsv6
, ss
->cfsv6
);
2406 ss
->sktv4
= ss
->sktv6
= -1;
2407 ss
->cfsv4
= ss
->cfsv6
= NULL
;
2408 ss
->rlsv4
= ss
->rlsv6
= NULL
;
2411 // returns count of non-link local V4 addresses deregistered
2412 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2415 // If an interface is going away, then deregister this from the mDNSCore.
2416 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2417 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2418 // it refers to has gone away we'll crash.
2419 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2420 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2421 NetworkInterfaceInfoOSX
*i
;
2423 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2425 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
2426 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2427 if (i
->ifinfo
.InterfaceID
)
2428 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2430 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
2431 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2432 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2433 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
2434 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2435 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2436 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2437 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2438 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2443 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2444 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2448 // 2. Close all our CFSockets. We'll recreate them later as necessary.
2449 // (We may have previously had both v4 and v6, and we may not need both any more.)
2450 CloseSocketSet(&i
->ss
);
2451 // 3. If no longer active, delete interface from list and free memory
2454 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2455 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2456 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2457 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2458 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2459 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2463 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2464 freeL("NetworkInterfaceInfoOSX", i
);
2465 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2473 mDNSlocal mStatus
GetDNSConfig(void **result
)
2476 static int MessageShown
= 0;
2477 if (!MessageShown
) { MessageShown
= 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
2479 return mStatus_UnsupportedErr
;
2482 *result
= dns_configuration_copy();
2486 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2487 if (mDNSMacOSXSystemBuildNumber(NULL
) < 8) return mStatus_UnsupportedErr
;
2489 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2490 // Apparently this is expected behaviour -- "not a bug".
2491 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2492 // If we are still getting failures after three minutes, then we log them.
2493 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return mStatus_NoError
;
2495 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2496 return mStatus_UnknownErr
;
2498 return mStatus_NoError
;
2499 #endif // MDNS_NO_DNSINFO
2502 mDNSlocal mStatus
RegisterSplitDNS(mDNS
*m
, int *nAdditions
, int *nDeletions
)
2504 (void)m
; // unused on 10.3 systems
2506 *nAdditions
= *nDeletions
= 0;
2507 mStatus err
= GetDNSConfig(&v
);
2509 #if !MDNS_NO_DNSINFO
2514 dns_config_t
*config
= v
; // use void * to allow compilation on 10.3 systems
2516 p
= m
->uDNS_info
.Servers
;
2517 while (p
) { p
->del
= mDNStrue
; p
= p
->next
; } // mark all for deletion
2519 LogOperation("RegisterSplitDNS: Registering %d resolvers", config
->n_resolver
);
2520 for (i
= 0; i
< config
->n_resolver
; i
++)
2524 dns_resolver_t
*r
= config
->resolver
[i
];
2525 if (r
->port
== MulticastDNSPort
.NotAnInteger
) continue; // ignore configurations for .local
2526 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2527 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2529 // check if this is the lowest-weighted server for the domain
2530 for (j
= 0; j
< config
->n_resolver
; j
++)
2532 dns_resolver_t
*p
= config
->resolver
[j
];
2533 if (p
->port
== MulticastDNSPort
.NotAnInteger
) continue;
2534 if (p
->search_order
<= r
->search_order
)
2537 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2538 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2539 if (SameDomainName(&d
, &tmp
))
2540 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2543 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2544 { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
); continue; }
2545 // we're using this resolver - find the first IPv4 address
2546 for (n
= 0; n
< r
->n_nameserver
; n
++)
2548 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& !AddrRequiresPPPConnection(r
->nameserver
[n
]))
2550 // %%% This should use mDNS_AddDNSServer() instead of duplicating functionality here
2552 if (SetupAddr(&saddr
, r
->nameserver
[n
])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
2553 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
2554 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
);
2555 p
= m
->uDNS_info
.Servers
;
2558 if (mDNSSameAddress(&p
->addr
, &saddr
) && SameDomainName(&p
->domain
, &d
)) { p
->del
= mDNSfalse
; break; }
2563 p
= mallocL("DNSServer", sizeof(*p
));
2564 if (!p
) { LogMsg("Error: malloc"); mDNS_Unlock(m
); return mStatus_UnknownErr
; }
2567 p
->teststate
= DNSServer_Untested
;
2568 AssignDomainName(&p
->domain
, &d
);
2569 p
->next
= m
->uDNS_info
.Servers
;
2570 m
->uDNS_info
.Servers
= p
;
2573 break; // !!!KRS if we ever support round-robin servers, don't break here
2578 // remove all servers marked for deletion
2579 DNSServer
**s
= &m
->uDNS_info
.Servers
;
2586 freeL("DNSServer", p
);
2589 else s
= &(*s
)->next
;
2592 dns_configuration_free(config
);
2599 mDNSlocal mStatus
RegisterNameServers(mDNS
*const m
, CFDictionaryRef dict
)
2604 mDNSAddr saddr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
2607 mDNS_DeleteDNSServers(m
); // deregister orig list
2608 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
2609 if (!values
) return mStatus_NoError
;
2611 count
= CFArrayGetCount(values
);
2612 for (i
= 0; i
< count
; i
++)
2614 s
= CFArrayGetValueAtIndex(values
, i
);
2615 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
2616 if (!CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
))
2618 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
2621 if (!inet_aton(buf
, (struct in_addr
*)saddr
.ip
.v4
.b
))
2623 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf
);
2626 LogOperation("RegisterNameServers: Adding %#a", &saddr
);
2627 mDNS_AddDNSServer(m
, &saddr
, NULL
);
2629 return mStatus_NoError
;
2632 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2635 ARListElem
*elem
= rr
->RecordContext
;
2636 if (result
== mStatus_MemFree
) freeL("FreeARElemCallback", elem
);
2639 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2641 SearchListElem
*slElem
= question
->QuestionContext
;
2642 ARListElem
*arElem
, *ptr
, *prev
;
2649 arElem
= mallocL("FoundDomain - arElem", sizeof(ARListElem
));
2650 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
2651 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
2652 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
2653 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
2654 else if (question
== &slElem
->LegacyBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseLegacy
];
2655 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
2656 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
2657 else { LogMsg("FoundDomain - unknown question"); return; }
2659 MakeDomainNameFromDNSNameString(arElem
->ar
.resrec
.name
, name
);
2660 AppendDNSNameString (arElem
->ar
.resrec
.name
, "local");
2661 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
2662 err
= mDNS_Register(m
, &arElem
->ar
);
2665 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
);
2666 freeL("FoundDomain - arElem", arElem
);
2669 arElem
->next
= slElem
->AuthRecs
;
2670 slElem
->AuthRecs
= arElem
;
2674 ptr
= slElem
->AuthRecs
;
2678 if (SameDomainName(&ptr
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
2680 debugf("Deregistering PTR %##s -> %##s", ptr
->ar
.resrec
.name
->c
, ptr
->ar
.resrec
.rdata
->u
.name
.c
);
2682 if (prev
) prev
->next
= ptr
->next
;
2683 else slElem
->AuthRecs
= ptr
->next
;
2685 err
= mDNS_Deregister(m
, dereg
);
2686 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
2697 mDNSlocal
void MarkSearchListElem(const char *d
)
2699 SearchListElem
*new, *ptr
;
2702 if (!MakeDomainNameFromDNSNameString(&domain
, d
))
2703 { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d
); return; }
2705 if (SameDomainName(&domain
, &localdomain
) || SameDomainName(&domain
, &LocalReverseMapomain
))
2706 { debugf("MarkSearchListElem - ignoring local domain %##s", domain
.c
); return; }
2708 // if domain is in list, mark as pre-existent (0)
2709 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
2710 if (SameDomainName(&ptr
->domain
, &domain
))
2712 if (ptr
->flag
!= 1) ptr
->flag
= 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
2716 // if domain not in list, add to list, mark as add (1)
2719 new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem
));
2720 if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
2721 bzero(new, sizeof(SearchListElem
));
2722 AssignDomainName(&new->domain
, &domain
);
2723 new->flag
= 1; // add
2724 new->next
= SearchList
;
2729 // Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
2730 mDNSlocal mStatus
GetSearchDomains(void)
2733 mStatus err
= GetDNSConfig(&v
);
2735 #if !MDNS_NO_DNSINFO
2739 dns_config_t
*config
= v
;
2740 if (!config
->n_resolver
) return err
;
2741 dns_resolver_t
*resolv
= config
->resolver
[0]; // use the first slot for search domains
2743 for (i
= 0; i
< resolv
->n_search
; i
++) MarkSearchListElem(resolv
->search
[i
]);
2744 if (resolv
->domain
) MarkSearchListElem(resolv
->domain
);
2745 dns_configuration_free(config
);
2752 // Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
2753 mDNSlocal
void GetDSSearchDomains(CFDictionaryRef dict
)
2755 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2760 // get all the domains from "Search Domains" field of sharing prefs
2763 CFArrayRef searchdomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
2766 count
= CFArrayGetCount(searchdomains
);
2767 for (i
= 0; i
< count
; i
++)
2769 s
= CFArrayGetValueAtIndex(searchdomains
, i
);
2770 if (!s
) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
2771 if (!CFStringGetCString(s
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2773 LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2776 MarkSearchListElem(buf
);
2780 // get DHCP domain field
2781 CFStringRef dname
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
2784 if (CFStringGetCString(dname
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2785 MarkSearchListElem(buf
);
2786 else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2791 mDNSlocal mStatus
RegisterSearchDomains(mDNS
*const m
, CFDictionaryRef dict
)
2793 struct ifaddrs
*ifa
= NULL
;
2794 SearchListElem
*ptr
, *prev
, *freeSLPtr
;
2798 if (DomainDiscoveryDisabled
) return mStatus_NoError
;
2800 // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
2801 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= dict
? -1 : 0;
2803 // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
2804 if (GetSearchDomains() == mStatus_UnsupportedErr
) GetDSSearchDomains(dict
);
2806 // Construct reverse-map search domains
2807 ifa
= myGetIfAddrs(1);
2811 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
2815 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
2817 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
2818 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
2819 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
2820 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
2821 MarkSearchListElem(buffer
);
2824 ifa
= ifa
->ifa_next
;
2827 // delete elems marked for removal, do queries for elems marked add
2832 if (ptr
->flag
== -1) // remove
2834 mDNS_StopQuery(m
, &ptr
->BrowseQ
);
2835 mDNS_StopQuery(m
, &ptr
->RegisterQ
);
2836 mDNS_StopQuery(m
, &ptr
->DefBrowseQ
);
2837 mDNS_StopQuery(m
, &ptr
->DefRegisterQ
);
2838 mDNS_StopQuery(m
, &ptr
->LegacyBrowseQ
);
2840 // deregister records generated from answers to the query
2841 arList
= ptr
->AuthRecs
;
2842 ptr
->AuthRecs
= NULL
;
2845 AuthRecord
*dereg
= &arList
->ar
;
2846 arList
= arList
->next
;
2847 debugf("Deregistering PTR %##s -> %##s", dereg
->resrec
.name
->c
, dereg
->resrec
.rdata
->u
.name
.c
);
2848 err
= mDNS_Deregister(m
, dereg
);
2849 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
2852 // remove elem from list, delete
2853 if (prev
) prev
->next
= ptr
->next
;
2854 else SearchList
= ptr
->next
;
2857 freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr
);
2861 if (ptr
->flag
== 1) // add
2863 mStatus err1
, err2
, err3
, err4
, err5
;
2864 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2865 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2866 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2867 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2868 err5
= mDNS_GetDomains(m
, &ptr
->LegacyBrowseQ
, mDNS_DomainTypeBrowseLegacy
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2869 if (err1
|| err2
|| err3
|| err4
|| err5
)
2870 LogMsg("GetDomains for domain %##s returned error(s):\n"
2871 "%d (mDNS_DomainTypeBrowse)\n"
2872 "%d (mDNS_DomainTypeBrowseDefault)\n"
2873 "%d (mDNS_DomainTypeRegistration)\n"
2874 "%d (mDNS_DomainTypeRegistrationDefault)"
2875 "%d (mDNS_DomainTypeBrowseLegacy)\n",
2876 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
2880 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
2886 return mStatus_NoError
;
2889 //!!!KRS here is where we will give success/failure notification to the UI
2890 mDNSlocal
void SCPrefsDynDNSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2893 debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
2894 SetDDNSNameStatus(rr
->resrec
.name
, result
);
2897 mDNSlocal
void SetSecretForDomain(mDNS
*m
, const domainname
*domain
)
2900 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
2902 void *secret
= NULL
;
2903 domainname
*d
, canon
;
2905 mDNSu32 type
= 'ddns';
2906 mDNSu32 typelen
= sizeof(type
);
2907 char *failedfn
= "(none)";
2908 SecKeychainAttributeList
*attrList
= NULL
;
2909 SecKeychainItemRef itemRef
= NULL
;
2911 err
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
2912 if (err
) { failedfn
= "SecKeychainSetPreferenceDomain"; goto cleanup
; }
2914 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
2915 ConvertDomainNameToCString(domain
, dstring
);
2916 dlen
= strlen(dstring
);
2917 for (i
= 0; i
< dlen
; i
++) dstring
[i
] = tolower(dstring
[i
]); // canonicalize -> lower case
2918 MakeDomainNameFromDNSNameString(&canon
, dstring
);
2921 // find longest-match key, excluding last label (e.g. excluding ".com")
2922 while (d
->c
[0] && *(d
->c
+ d
->c
[0] + 1))
2924 if (!ConvertDomainNameToCString(d
, dstring
)) { LogMsg("SetSecretForDomain: bad domain %##s", d
->c
); return; }
2925 dlen
= strlen(dstring
);
2926 if (dstring
[dlen
-1] == '.') { dstring
[dlen
-1] = '\0'; dlen
--; } // chop trailing dot
2927 SecKeychainAttribute attrs
[] = { { kSecServiceItemAttr
, strlen(dstring
), dstring
},
2928 { kSecTypeItemAttr
, typelen
, (UInt32
*)&type
} };
2929 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
2930 SecKeychainSearchRef searchRef
;
2932 err
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attributes
, &searchRef
);
2933 if (err
) { failedfn
= "SecKeychainSearchCreateFromAttributes"; goto cleanup
; }
2935 err
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
2939 SecKeychainAttributeInfo attrInfo
;
2941 char keybuf
[MAX_ESCAPED_DOMAIN_NAME
+1];
2944 tags
[0] = kSecAccountItemAttr
;
2946 attrInfo
.tag
= tags
;
2947 attrInfo
.format
= NULL
;
2949 err
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrList
, &secretlen
, &secret
);
2950 if (err
|| !attrList
) { failedfn
= "SecKeychainItemCopyAttributesAndData"; goto cleanup
; }
2951 if (!secretlen
|| !secret
) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
2952 if (((char *)secret
)[secretlen
-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup
; }
2954 for (i
= 0; i
< attrList
->count
; i
++)
2956 SecKeychainAttribute attr
= attrList
->attr
[i
];
2957 if (attr
.tag
== kSecAccountItemAttr
)
2959 if (!attr
.length
|| attr
.length
> MAX_ESCAPED_DOMAIN_NAME
) { LogMsg("SetSecretForDomain - Bad key length %d", attr
.length
); goto cleanup
; }
2960 strncpy(keybuf
, attr
.data
, attr
.length
);
2961 if (!MakeDomainNameFromDNSNameString(&keyname
, keybuf
)) { LogMsg("SetSecretForDomain - bad key %s", keybuf
); goto cleanup
; }
2962 debugf("Setting shared secret for zone %s with key %##s", dstring
, keyname
.c
);
2963 mDNS_SetSecretForZone(m
, d
, &keyname
, secret
);
2967 if (i
== attrList
->count
) LogMsg("SetSecretForDomain - no key name set");
2970 else if (err
== errSecItemNotFound
) d
= (domainname
*)(d
->c
+ d
->c
[0] + 1);
2971 else { failedfn
= "SecKeychainSearchCopyNext"; goto cleanup
; }
2975 if (err
&& err
!= errSecItemNotFound
) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn
, err
);
2976 if (attrList
) SecKeychainItemFreeAttributesAndData(attrList
, secret
);
2977 if (itemRef
) CFRelease(itemRef
);
2980 mDNSlocal
void SetSCPrefsBrowseDomainsFromCFArray(mDNS
*m
, CFArrayRef browseDomains
, mDNSBool add
)
2984 CFIndex count
= CFArrayGetCount(browseDomains
);
2985 CFDictionaryRef browseDict
;
2986 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2989 for (i
= 0; i
< count
; i
++)
2991 browseDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(browseDomains
, i
);
2992 if (browseDict
&& DDNSSettingEnabled(browseDict
))
2994 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
2997 domainname BrowseDomain
;
2998 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) || !MakeDomainNameFromDNSNameString(&BrowseDomain
, buf
) || !BrowseDomain
.c
[0])
2999 LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf
[0] ? buf
: "(unknown)");
3000 else SetSCPrefsBrowseDomain(m
, &BrowseDomain
, add
);
3008 mDNSlocal
void DynDNSConfigChanged(mDNS
*const m
)
3010 static mDNSBool LegacyNATInitialized
= mDNSfalse
;
3011 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
3012 CFDictionaryRef dict
;
3014 domainname RegDomain
, fqdn
;
3015 CFArrayRef NewBrowseDomains
= NULL
;
3016 int nAdditions
= 0, nDeletions
= 0;
3018 // get fqdn, zone from SCPrefs
3019 GetUserSpecifiedDDNSConfig(&fqdn
, &RegDomain
, &NewBrowseDomains
);
3020 ReadDDNSSettingsFromConfFile(m
, CONFIG_FILE
, fqdn
.c
[0] ? NULL
: &fqdn
, RegDomain
.c
[0] ? NULL
: &RegDomain
, &DomainDiscoveryDisabled
);
3022 if (!SameDomainName(&RegDomain
, &DynDNSRegDomain
))
3024 if (DynDNSRegDomain
.c
[0])
3026 RemoveDefRegDomain(&DynDNSRegDomain
);
3027 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNSfalse
); // if we were automatically browsing in our registration domain, stop
3029 AssignDomainName(&DynDNSRegDomain
, &RegDomain
);
3030 if (DynDNSRegDomain
.c
[0])
3032 SetSecretForDomain(m
, &DynDNSRegDomain
);
3033 AddDefRegDomain(&DynDNSRegDomain
);
3034 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNStrue
);
3038 // Add new browse domains to internal list
3039 if (NewBrowseDomains
) SetSCPrefsBrowseDomainsFromCFArray(m
, NewBrowseDomains
, mDNStrue
);
3041 // Remove old browse domains from internal list
3042 if (DynDNSBrowseDomains
)
3044 SetSCPrefsBrowseDomainsFromCFArray(m
, DynDNSBrowseDomains
, mDNSfalse
);
3045 CFRelease(DynDNSBrowseDomains
);
3048 // Replace the old browse domains array with the new array
3049 DynDNSBrowseDomains
= NewBrowseDomains
;
3051 if (!SameDomainName(&fqdn
, &DynDNSHostname
))
3053 if (DynDNSHostname
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &DynDNSHostname
);
3054 AssignDomainName(&DynDNSHostname
, &fqdn
);
3055 if (DynDNSHostname
.c
[0])
3057 SetSecretForDomain(m
, &fqdn
); // no-op if "zone" secret, above, is to be used for hostname
3058 SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate "in progress"
3059 mDNS_AddDynDNSHostName(m
, &DynDNSHostname
, SCPrefsDynDNSCallback
, NULL
);
3064 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL
, NULL
);
3067 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3068 if (!key
) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3069 dict
= SCDynamicStoreCopyValue(store
, key
);
3072 // handle any changes to search domains and DNS server addresses
3073 if (RegisterSplitDNS(m
, &nAdditions
, &nDeletions
) != mStatus_NoError
)
3074 if (dict
) RegisterNameServers(m
, dict
); // fall back to non-split DNS aware configuration on failure
3075 RegisterSearchDomains(m
, dict
); // note that we register name servers *before* search domains
3076 if (dict
) CFRelease(dict
);
3078 // get IPv4 settings
3079 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3080 if (!key
) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3081 dict
= SCDynamicStoreCopyValue(store
, key
);
3084 if (!dict
) // lost v4
3086 mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3087 if (DynDNSHostname
.c
[0]) SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate temporary failure
3091 // handle router changes
3094 r
.type
= mDNSAddrType_IPv4
;
3095 r
.ip
.v4
.NotAnInteger
= 0;
3096 CFStringRef router
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3099 struct sockaddr_in saddr
;
3101 if (!CFStringGetCString(router
, buf
, 256, kCFStringEncodingUTF8
))
3102 LogMsg("Could not convert router to CString");
3105 saddr
.sin_len
= sizeof(saddr
);
3106 saddr
.sin_family
= AF_INET
;
3108 inet_aton(buf
, &saddr
.sin_addr
);
3109 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) { debugf("Ignoring router %s (requires PPP connection)", buf
); }
3110 else *(in_addr_t
*)&r
.ip
.v4
= saddr
.sin_addr
.s_addr
;
3114 // handle primary interface changes
3115 // 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
3116 if (nAdditions
|| nDeletions
) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3117 CFStringRef primary
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3120 mDNSAddr v4
= zeroAddr
, v6
= zeroAddr
;
3121 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3122 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3124 if (!CFStringGetCString(primary
, buf
, 256, kCFStringEncodingUTF8
))
3125 { LogMsg("Could not convert router to CString"); goto error
; }
3127 // find primary interface in list
3128 while (ifa
&& (!v4
.ip
.v4
.NotAnInteger
|| !HavePrimaryGlobalv6
))
3130 mDNSAddr tmp6
= zeroAddr
;
3131 if (!strcmp(buf
, ifa
->ifa_name
))
3133 if (ifa
->ifa_addr
->sa_family
== AF_INET
) SetupAddr(&v4
, ifa
->ifa_addr
);
3134 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3136 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3137 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3138 { HavePrimaryGlobalv6
= mDNStrue
; v6
= tmp6
; }
3143 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3144 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
.ip
.v6
.b
[0])
3146 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3147 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) v6
= tmp6
;
3150 ifa
= ifa
->ifa_next
;
3153 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3154 // V4 to communicate w/ our DNS server
3156 if (v4
.ip
.v4
.b
[0] == 169 && v4
.ip
.v4
.b
[1] == 254) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
); // primary IP is link-local
3159 if (v4
.ip
.v4
.NotAnInteger
!= u
->AdvertisedV4
.ip
.v4
.NotAnInteger
||
3160 memcmp(v6
.ip
.v6
.b
, u
->AdvertisedV6
.ip
.v6
.b
, 16) ||
3161 r
.ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
)
3163 if (LegacyNATInitialized
) { LegacyNATDestroy(); LegacyNATInitialized
= mDNSfalse
; }
3164 if (r
.ip
.v4
.NotAnInteger
&& IsPrivateV4Addr(&v4
))
3166 mStatus err
= LegacyNATInit();
3167 if (err
) LogMsg("ERROR: LegacyNATInit");
3168 else LegacyNATInitialized
= mDNStrue
;
3170 mDNS_SetPrimaryInterfaceInfo(m
, &v4
, v6
.ip
.v6
.b
[0] ? &v6
: NULL
, r
.ip
.v4
.NotAnInteger
? &r
: NULL
);
3178 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3180 LogOperation("*** Network Configuration Change ***");
3181 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3182 mDNSs32 utc
= mDNSPlatformUTC();
3183 MarkAllInterfacesInactive(m
, utc
);
3184 UpdateInterfaceList(m
, utc
);
3185 int nDeletions
= ClearInactiveInterfaces(m
, utc
);
3186 int nAdditions
= SetupActiveInterfaces(m
, utc
);
3187 DynDNSConfigChanged(m
); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
3188 if (nDeletions
|| nAdditions
) mDNS_UpdateLLQs(m
); // so that LLQs are restarted against the up to date name servers
3190 if (m
->MainCallback
)
3191 m
->MainCallback(m
, mStatus_ConfigChanged
);
3194 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3196 (void)store
; // Parameter not used
3197 (void)changedKeys
; // Parameter not used
3198 mDNS
*const m
= (mDNS
*const)context
;
3201 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
3203 int c
= CFArrayGetCount(changedKeys
); // Count changes
3204 CFRange range
= { 0, c
};
3205 CFStringRef k1
= SCDynamicStoreKeyCreateComputerName(NULL
);
3206 CFStringRef k2
= SCDynamicStoreKeyCreateHostNames(NULL
);
3209 int c1
= (CFArrayContainsValue(changedKeys
, range
, k1
) != 0); // See if ComputerName changed
3210 int c2
= (CFArrayContainsValue(changedKeys
, range
, k2
) != 0); // See if Local Hostname changed
3211 int c3
= (CFArrayContainsValue(changedKeys
, range
, CFSTR("Setup:/Network/DynamicDNS")) != 0);
3212 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
3214 if (k1
) CFRelease(k1
);
3215 if (k2
) CFRelease(k2
);
3217 LogOperation("*** NetworkChanged *** %d change%s, delay %d", c
, c
>1?"s":"", delay
);
3219 if (!m
->p
->NetworkChanged
||
3220 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3221 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3223 if (!m
->SuppressSending
||
3224 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3225 m
->SuppressSending
= m
->p
->NetworkChanged
;
3229 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3232 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3233 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3234 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3235 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
3236 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
3237 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
3238 CFStringRef key5
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3239 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3240 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3242 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3243 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3245 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3246 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3248 CFArrayAppendValue(keys
, key1
);
3249 CFArrayAppendValue(keys
, key2
);
3250 CFArrayAppendValue(keys
, key3
);
3251 CFArrayAppendValue(keys
, key4
);
3252 CFArrayAppendValue(keys
, key5
);
3253 CFArrayAppendValue(keys
, CFSTR("Setup:/Network/DynamicDNS"));
3254 CFArrayAppendValue(patterns
, pattern1
);
3255 CFArrayAppendValue(patterns
, pattern2
);
3256 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3257 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3258 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3260 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3261 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3263 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3264 m
->p
->Store
= store
;
3269 if (store
) CFRelease(store
);
3272 if (key1
) CFRelease(key1
);
3273 if (key2
) CFRelease(key2
);
3274 if (key3
) CFRelease(key3
);
3275 if (key4
) CFRelease(key4
);
3276 if (key5
) CFRelease(key5
);
3277 if (pattern1
) CFRelease(pattern1
);
3278 if (pattern2
) CFRelease(pattern2
);
3279 if (keys
) CFRelease(keys
);
3280 if (patterns
) CFRelease(patterns
);
3285 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3287 mDNS
*const m
= (mDNS
*const)refcon
;
3288 (void)service
; // Parameter not used
3291 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3292 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3293 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3294 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3295 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3296 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3297 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3298 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3299 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3300 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3301 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3302 // Just to be safe, also make sure our interface list is fully up to date, in case we
3303 // haven't yet received the System Configuration Framework "network changed" event that
3304 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3305 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3306 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3307 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3308 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3309 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3310 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3312 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3315 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
3317 IONotificationPortRef thePortRef
;
3318 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
3319 if (m
->p
->PowerConnection
)
3321 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
3322 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3323 return(mStatus_NoError
);
3328 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3329 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3330 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3331 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3333 // Major version 6 is 10.2.x (Jaguar)
3334 // Major version 7 is 10.3.x (Panther)
3335 // Major version 8 is 10.4.x (Tiger)
3336 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3338 int major
= 0, minor
= 0;
3339 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
3340 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3343 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3344 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3345 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3346 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3347 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3348 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3349 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3352 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3356 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3357 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3358 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3359 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3362 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3364 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3367 struct sockaddr_in s5353
;
3368 s5353
.sin_family
= AF_INET
;
3369 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3370 s5353
.sin_addr
.s_addr
= 0;
3371 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3375 if (err
) LogMsg("No unicast UDP responses");
3376 else debugf("Unicast UDP responses okay");
3380 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
3381 mDNSlocal
void FoundLegacyBrowseDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
3383 DNameListElem
*ptr
, *prev
, *new;
3385 (void)question
; // unused
3387 LogMsg("%s browse domain %##s", AddRecord
? "Adding" : "Removing", answer
->rdata
->u
.name
.c
);
3391 new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem
));
3392 if (!new) { LogMsg("ERROR: malloc"); return; }
3393 AssignDomainName(&new->name
, &answer
->rdata
->u
.name
);
3394 new->next
= DefBrowseList
;
3395 DefBrowseList
= new;
3396 DefaultBrowseDomainChanged(&new->name
, mDNStrue
);
3397 udsserver_default_browse_domain_changed(&new->name
, mDNStrue
);
3402 ptr
= DefBrowseList
;
3406 if (SameDomainName(&ptr
->name
, &answer
->rdata
->u
.name
))
3408 DefaultBrowseDomainChanged(&ptr
->name
, mDNSfalse
);
3409 udsserver_default_browse_domain_changed(&ptr
->name
, mDNSfalse
);
3410 if (prev
) prev
->next
= ptr
->next
;
3411 else DefBrowseList
= ptr
->next
;
3412 freeL("FoundLegacyBrowseDomain", ptr
);
3418 LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer
->rdata
->u
.name
.c
);
3422 mDNSlocal
void RegisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3424 // allocate/register legacy and non-legacy _browse PTR record
3425 ARListElem
*browse
= mallocL("ARListElem", sizeof(*browse
));
3426 mDNS_SetupResourceRecord(&browse
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, browse
);
3427 MakeDomainNameFromDNSNameString(browse
->ar
.resrec
.name
, mDNS_DomainTypeNames
[type
]);
3428 AppendDNSNameString (browse
->ar
.resrec
.name
, "local");
3429 AssignDomainName(&browse
->ar
.resrec
.rdata
->u
.name
, d
);
3430 mStatus err
= mDNS_Register(m
, &browse
->ar
);
3433 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err
);
3434 freeL("ARListElem", browse
);
3438 browse
->next
= SCPrefBrowseDomains
;
3439 SCPrefBrowseDomains
= browse
;
3443 mDNSlocal
void DeregisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3445 ARListElem
*remove
, **ptr
= &SCPrefBrowseDomains
;
3446 domainname lhs
; // left-hand side of PTR, for comparison
3448 MakeDomainNameFromDNSNameString(&lhs
, mDNS_DomainTypeNames
[type
]);
3449 AppendDNSNameString (&lhs
, "local");
3453 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, d
) && SameDomainName((*ptr
)->ar
.resrec
.name
, &lhs
))
3456 *ptr
= (*ptr
)->next
;
3457 mDNS_Deregister(m
, &remove
->ar
);
3460 else ptr
= &(*ptr
)->next
;
3464 // Add or remove a user-specified domain to the list of empty-string browse domains
3465 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
3466 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
)
3468 debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
3472 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3473 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3477 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3478 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3482 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3483 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3484 // (.local manually generated via explicit callback)
3485 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3486 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3487 // 4) result above should generate a callback from question in (1). result added to global list
3488 // 5) global list delivered to client via GetSearchDomainList()
3489 // 6) client calls to enumerate domains now go over LocalOnly interface
3490 // (!!!KRS may add outgoing interface in addition)
3492 mDNSlocal mStatus
InitDNSConfig(mDNS
*const m
)
3495 static AuthRecord LocalRegPTR
;
3497 // start query for domains to be used in default (empty string domain) browses
3498 err
= mDNS_GetDomains(m
, &LegacyBrowseDomainQ
, mDNS_DomainTypeBrowseLegacy
, NULL
, mDNSInterface_LocalOnly
, FoundLegacyBrowseDomain
, NULL
);
3500 // provide browse domain "local" automatically
3501 SetSCPrefsBrowseDomain(m
, &localdomain
, mDNStrue
);
3503 // register registration domain "local"
3504 mDNS_SetupResourceRecord(&LocalRegPTR
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, NULL
, NULL
);
3505 MakeDomainNameFromDNSNameString(LocalRegPTR
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
]);
3506 AppendDNSNameString (LocalRegPTR
.resrec
.name
, "local");
3507 AssignDomainName(&LocalRegPTR
.resrec
.rdata
->u
.name
, &localdomain
);
3508 err
= mDNS_Register(m
, &LocalRegPTR
);
3509 if (err
) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err
);
3511 return mStatus_NoError
;
3514 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3516 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3517 // 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.
3519 for (i
=0; i
<100; i
++)
3521 domainlabel testlabel
;
3523 GetUserSpecifiedLocalHostName(&testlabel
);
3524 if (testlabel
.c
[0]) break;
3530 m
->hostlabel
.c
[0] = 0;
3532 char *HINFO_HWstring
= "Macintosh";
3533 char HINFO_HWstring_buffer
[256];
3534 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3535 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3536 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3537 HINFO_HWstring
= HINFO_HWstring_buffer
;
3539 char HINFO_SWstring
[256] = "";
3540 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3541 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3543 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3544 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3545 if (hlen
+ slen
< 254)
3547 m
->HIHardware
.c
[0] = hlen
;
3548 m
->HISoftware
.c
[0] = slen
;
3549 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
3550 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
3553 m
->p
->unicastsockets
.m
= m
;
3554 m
->p
->unicastsockets
.info
= NULL
;
3555 m
->p
->unicastsockets
.sktv4
= m
->p
->unicastsockets
.sktv6
= -1;
3556 m
->p
->unicastsockets
.cfsv4
= m
->p
->unicastsockets
.cfsv6
= NULL
;
3557 m
->p
->unicastsockets
.rlsv4
= m
->p
->unicastsockets
.rlsv6
= NULL
;
3559 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET
);
3560 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET6
);
3562 struct sockaddr_in s4
;
3563 struct sockaddr_in6 s6
;
3564 socklen_t n4
= sizeof(s4
);
3565 socklen_t n6
= sizeof(s6
);
3566 if (getsockname(m
->p
->unicastsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
3567 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
3568 if (getsockname(m
->p
->unicastsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
3569 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
3571 m
->p
->InterfaceList
= mDNSNULL
;
3572 m
->p
->userhostlabel
.c
[0] = 0;
3573 m
->p
->usernicelabel
.c
[0] = 0;
3574 m
->p
->NotifyUser
= 0;
3575 mDNSs32 utc
= mDNSPlatformUTC();
3576 UpdateInterfaceList(m
, utc
);
3577 SetupActiveInterfaces(m
, utc
);
3579 err
= WatchForNetworkChanges(m
);
3580 if (err
) return(err
);
3582 err
= WatchForPowerChanges(m
);
3583 if (err
) return err
;
3585 DynDNSRegDomain
.c
[0] = '\0';
3586 DynDNSConfigChanged(m
); // Get initial DNS configuration
3592 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
3594 mStatus result
= mDNSPlatformInit_setup(m
);
3596 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3597 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3598 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
3602 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
3604 if (m
->p
->PowerConnection
)
3606 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3607 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
3608 CFRelease(m
->p
->PowerRLS
);
3609 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
3610 m
->p
->PowerConnection
= 0;
3611 m
->p
->PowerNotifier
= 0;
3612 m
->p
->PowerRLS
= NULL
;
3617 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3618 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
3619 CFRelease(m
->p
->StoreRLS
);
3620 CFRelease(m
->p
->Store
);
3622 m
->p
->StoreRLS
= NULL
;
3625 mDNSs32 utc
= mDNSPlatformUTC();
3626 MarkAllInterfacesInactive(m
, utc
);
3627 ClearInactiveInterfaces(m
, utc
);
3628 CloseSocketSet(&m
->p
->unicastsockets
);
3631 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
3633 return(mach_absolute_time());
3636 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
3638 mDNSexport mStatus
mDNSPlatformTimeInit(void)
3640 // Notes: Typical values for mach_timebase_info:
3641 // tbi.numer = 1000 million
3642 // tbi.denom = 33 million
3643 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3644 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3645 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3646 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3647 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3649 // Arithmetic notes:
3650 // tbi.denom is at least 1, and not more than 2^32-1.
3651 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3652 // tbi.denom is at least 1, and not more than 2^32-1.
3653 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3654 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3655 // which is unlikely on any current or future Macintosh.
3656 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3657 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3658 struct mach_timebase_info tbi
;
3659 kern_return_t result
= mach_timebase_info(&tbi
);
3660 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
3664 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
3666 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3668 static uint64_t last_mach_absolute_time
= 0;
3669 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
3670 uint64_t this_mach_absolute_time
= mach_absolute_time();
3671 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
3673 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
3674 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
3675 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3676 last_mach_absolute_time
= this_mach_absolute_time
;
3677 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
3678 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
3679 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
3680 NotifyOfElusiveBug("mach_absolute_time went backwards!",
3681 "This error occurs from time to time, often on newly released hardware, "
3682 "and usually the exact cause is different in each instance.\r\r"
3683 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
3684 "and assign it to Radar Component “Kernel” Version “X”.");
3686 last_mach_absolute_time
= this_mach_absolute_time
;
3688 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
3691 mDNSexport mDNSs32
mDNSPlatformUTC(void)
3696 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
3697 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
3698 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
3699 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
3700 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
3701 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
3702 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
3703 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
3704 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
3705 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }