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.308.2.2 2005/08/05 01:12:24 ksekar
28 <rdar://problem/4137930> SUTiger: Hostname registration should register IPv6 AAAA record with DNS Update
29 <rdar://problem/4147774> SUTiger: Be defensive against invalid UTF-8 in dynamic host names
30 <rdar://problem/3923098> SUTiger: Things are showing up with a bogus interface index
31 <rdar://problem/4080074> SUTiger: PPP connection disables same-host Bonjour ".local" lookups
34 Revision 1.308.2.1 2005/07/22 21:42:59 ksekar
35 Fix GCC 4.0/Intel compiler warnings
37 Revision 1.308 2005/03/09 00:48:44 cheshire
38 <rdar://problem/4015157> QU packets getting sent too early on wake from sleep
39 Move "m->p->NetworkChanged = 0;" line from caller to callee
41 Revision 1.307 2005/03/03 03:12:02 cheshire
42 Add comment about mDNSMacOSXSystemBuildNumber()
44 Revision 1.306 2005/03/02 22:18:00 cheshire
45 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
47 Revision 1.305 2005/02/26 05:08:28 cheshire
48 <rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
49 Added dnsinfo.h to project directory
51 Revision 1.304 2005/02/25 23:51:22 cheshire
52 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
53 Return mStatus_UnknownErr instead of -1
55 Revision 1.303 2005/02/25 17:47:45 ksekar
56 <rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
58 Revision 1.302 2005/02/25 02:34:14 cheshire
59 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
60 Show status as 1 (in progress) while we're trying
62 Revision 1.301 2005/02/24 21:55:57 ksekar
63 <rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
65 Revision 1.300 2005/02/15 20:03:13 ksekar
66 <rdar://problem/4005868> Crash when SCPreferences contains empty array
68 Revision 1.299 2005/02/15 02:46:53 cheshire
69 <rdar://problem/3967876> Don't log ENETUNREACH errors for unicast destinations
71 Revision 1.298 2005/02/10 00:41:59 cheshire
74 Revision 1.297 2005/02/09 23:38:51 ksekar
75 <rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
77 Revision 1.296 2005/02/01 21:06:52 ksekar
78 Avoid spurious log message
80 Revision 1.295 2005/02/01 19:33:30 ksekar
81 <rdar://problem/3985239> Keychain format too restrictive
83 Revision 1.294 2005/01/27 21:30:23 cheshire
84 <rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
85 Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
87 Revision 1.293 2005/01/27 19:15:41 cheshire
88 Remove extraneous LogMsg() call
90 Revision 1.292 2005/01/27 17:48:38 cheshire
91 Added comment about CFSocketInvalidate closing the underlying socket
93 Revision 1.291 2005/01/27 00:10:58 cheshire
94 <rdar://problem/3967867> Name change log messages every time machine boots
96 Revision 1.290 2005/01/25 23:18:30 ksekar
97 fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
99 Revision 1.289 2005/01/25 18:08:31 ksekar
100 Removed redundant debug output
102 Revision 1.288 2005/01/25 17:42:26 ksekar
103 Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
104 cleaned up duplicate log messages when adding/removing browse domains
106 Revision 1.287 2005/01/25 16:59:23 ksekar
107 <rdar://problem/3971138> sa_len not set checking reachability for TCP connections
109 Revision 1.286 2005/01/25 02:02:37 cheshire
110 <rdar://problem/3970673> mDNSResponder leaks
111 GetSearchDomains() was not calling dns_configuration_free().
113 Revision 1.285 2005/01/22 00:07:54 ksekar
114 <rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
116 Revision 1.284 2005/01/21 23:07:17 ksekar
117 <rdar://problem/3960795> mDNSResponder causes Dial on Demand
119 Revision 1.283 2005/01/19 21:16:16 cheshire
120 Make sure when we set NetworkChanged that we don't set it to zero
122 Revision 1.282 2005/01/19 19:19:21 ksekar
123 <rdar://problem/3960191> Need a way to turn off domain discovery
125 Revision 1.281 2005/01/18 18:10:55 ksekar
126 <rdar://problem/3954575> Use 10.4 resolver API to get search domains
128 Revision 1.280 2005/01/17 22:48:52 ksekar
129 No longer need to call MarkSearchListElem for registration domain
131 Revision 1.279 2005/01/17 20:40:34 ksekar
132 SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
134 Revision 1.278 2005/01/17 19:53:34 ksekar
135 Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
137 Revision 1.277 2005/01/12 00:17:50 ksekar
138 <rdar://problem/3933573> Update LLQs *after* setting DNS
140 Revision 1.276 2005/01/10 17:39:10 ksekar
141 Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
143 Revision 1.275 2005/01/10 04:02:22 ksekar
144 Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
146 Revision 1.274 2005/01/10 03:41:36 ksekar
147 Correction to checkin 1.272 - check that registration domain is set
148 before trying to remove it as an implicit browse domain
150 Revision 1.273 2005/01/08 00:42:18 ksekar
151 <rdar://problem/3922758> Clean up syslog messages
153 Revision 1.272 2005/01/07 23:21:42 ksekar
154 <rdar://problem/3891628> Clean up SCPreferences format
156 Revision 1.271 2004/12/20 23:18:12 cheshire
157 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
158 One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
160 Revision 1.270 2004/12/20 21:28:14 cheshire
161 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
162 Additional refinements to handle sleep/wake better
164 Revision 1.269 2004/12/20 20:48:11 cheshire
165 Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
167 Revision 1.268 2004/12/18 03:19:04 cheshire
168 Show netmask in error log
170 Revision 1.267 2004/12/18 00:51:52 cheshire
171 Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
173 Revision 1.266 2004/12/17 23:49:38 cheshire
174 <rdar://problem/3922754> Computer Name change is slow
175 Also treat changes to "Setup:/Network/DynamicDNS" the same way
177 Revision 1.265 2004/12/17 23:37:47 cheshire
178 <rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
179 (and other repetitive configuration changes)
181 Revision 1.264 2004/12/17 19:03:05 cheshire
182 Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
184 Revision 1.263 2004/12/17 05:25:46 cheshire
185 <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
187 Revision 1.262 2004/12/17 04:48:32 cheshire
188 <rdar://problem/3922754> Computer Name change is slow
190 Revision 1.261 2004/12/17 02:40:08 cheshire
191 Undo last change -- it was too strict
193 Revision 1.260 2004/12/16 22:17:16 cheshire
194 Only accept multicast packets on interfaces that have McastTxRx set
196 Revision 1.259 2004/12/16 20:13:01 cheshire
197 <rdar://problem/3324626> Cache memory management improvements
199 Revision 1.258 2004/12/14 00:18:05 cheshire
200 Don't log dns_configuration_copy() failures in the first three minutes after boot
202 Revision 1.257 2004/12/10 19:45:46 cheshire
203 <rdar://problem/3915074> Reduce egregious stack space usage
204 Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
206 Revision 1.256 2004/12/10 04:35:43 cheshire
207 <rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
209 Revision 1.255 2004/12/10 04:12:54 ksekar
210 <rdar://problem/3890764> Need new DefaultBrowseDomain key
212 Revision 1.254 2004/12/10 01:55:31 ksekar
213 <rdar://problem/3899067> Keychain lookups should be in lower case.
215 Revision 1.253 2004/12/09 03:15:41 ksekar
216 <rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
218 Revision 1.252 2004/12/07 01:32:42 cheshire
219 Don't log dns_configuration_copy() failure when running on 10.3
221 Revision 1.251 2004/12/06 22:30:31 cheshire
222 Added debugging log message
224 Revision 1.250 2004/12/06 06:59:08 ksekar
225 RegisterSplitDNS should return Unsupported error when compiled on Panther
227 Revision 1.249 2004/12/04 00:29:46 cheshire
228 Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
229 (When compiled on 10.3, code will not include split-DNS support.)
231 Revision 1.248 2004/12/01 20:57:20 ksekar
232 <rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
234 Revision 1.247 2004/12/01 03:26:58 cheshire
235 Remove unused variables
237 Revision 1.246 2004/12/01 01:51:34 cheshire
238 Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
240 Revision 1.245 2004/11/30 03:24:04 cheshire
241 <rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
243 Revision 1.244 2004/11/30 02:59:35 cheshire
244 For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
246 Revision 1.243 2004/11/29 19:17:29 ksekar
247 <rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
249 Revision 1.242 2004/11/29 18:37:38 ksekar
250 <rdar://problem/3889341> Buffer overflow in GetConfigOption
252 Revision 1.241 2004/11/25 01:37:04 ksekar
253 <rdar://problem/3894854> Config file and SCPreferences don't play well together
255 Revision 1.240 2004/11/25 01:29:42 ksekar
256 Remove unnecessary log messages
258 Revision 1.239 2004/11/25 01:27:19 ksekar
259 <rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
261 Revision 1.238 2004/11/24 22:00:59 cheshire
262 Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
264 Revision 1.237 2004/11/24 21:54:44 cheshire
265 <rdar://problem/3894475> mDNSCore not receiving unicast responses properly
267 Revision 1.236 2004/11/23 03:39:46 cheshire
268 Let interface name/index mapping capability live directly in JNISupport.c,
269 instead of having to call through to the daemon via IPC to get this information.
271 Revision 1.235 2004/11/17 01:45:35 cheshire
272 <rdar://problem/3847435> mDNS buddy list frequently becomes empty if you let the machine sleep
273 Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
274 in case we get no System Configuration Framework "network changed" event.
276 Revision 1.234 2004/11/17 00:32:56 ksekar
277 <rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
279 Revision 1.233 2004/11/12 03:16:45 rpantos
280 rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
282 Revision 1.232 2004/11/10 20:40:54 ksekar
283 <rdar://problem/3868216> LLQ mobility fragile on non-primary interface
285 Revision 1.231 2004/11/06 00:59:33 ksekar
286 Don't log ENETDOWN errors for unicast destinations (pollutes log on
289 Revision 1.230 2004/11/05 01:04:10 ksekar
290 <rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
292 Revision 1.229 2004/11/03 03:45:16 cheshire
293 <rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
295 Revision 1.228 2004/11/02 23:47:32 cheshire
296 <rdar://problem/3863214> Default hostname and Computer Name should be unique
298 Revision 1.227 2004/11/02 04:23:03 cheshire
299 Change to more informative name "GetUserSpecifiedLocalHostName()"
301 Revision 1.226 2004/11/01 20:36:19 ksekar
302 <rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
304 Revision 1.225 2004/10/28 19:03:04 cheshire
305 Remove \n from LogMsg() calls
307 Revision 1.224 2004/10/28 17:47:34 cheshire
308 Oops. Forgot the %d in the log message.
310 Revision 1.223 2004/10/28 17:24:28 cheshire
311 Updated "bad ifa_netmask" log message to give more information
313 Revision 1.222 2004/10/28 03:36:34 cheshire
314 <rdar://problem/3856535> Share the same port for both multicast and unicast receiving
316 Revision 1.221 2004/10/28 03:24:41 cheshire
317 Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
319 Revision 1.220 2004/10/28 00:53:57 cheshire
320 Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
321 Add LogOperation() call to record when we get network change events
323 Revision 1.219 2004/10/27 20:42:20 cheshire
324 Clean up debugging messages
326 Revision 1.218 2004/10/27 02:03:59 cheshire
327 Update debugging messages
329 Revision 1.217 2004/10/26 20:48:21 cheshire
330 Improve logging messages
332 Revision 1.216 2004/10/26 01:02:37 cheshire
335 Revision 1.215 2004/10/25 20:09:00 ksekar
336 Cleaned up config file parsing.
338 Revision 1.214 2004/10/25 19:30:53 ksekar
339 <rdar://problem/3827956> Simplify dynamic host name structures
341 Revision 1.213 2004/10/23 01:16:01 cheshire
342 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
344 Revision 1.212 2004/10/22 20:52:08 ksekar
345 <rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
347 Revision 1.211 2004/10/22 01:07:11 cheshire
348 <rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
349 Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
350 These are all supposed to be remapped to /dev/null
352 Revision 1.210 2004/10/20 02:19:54 cheshire
353 Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
355 Revision 1.209 2004/10/16 00:17:00 cheshire
356 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
358 Revision 1.208 2004/10/15 23:00:18 ksekar
359 <rdar://problem/3799242> Need to update LLQs on location changes
361 Revision 1.207 2004/10/13 22:45:23 cheshire
362 <rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
364 Revision 1.206 2004/10/13 22:11:46 cheshire
365 Update debugging messages
367 Revision 1.205 2004/10/12 21:10:11 cheshire
368 <rdar://problem/3438376> mach_absolute_time() not monotonically increasing
369 Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
371 Revision 1.204 2004/10/12 03:20:52 ksekar
372 <rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
374 Revision 1.203 2004/10/08 04:29:25 ksekar
375 <rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
377 Revision 1.202 2004/10/04 05:56:04 cheshire
378 <rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
380 Revision 1.201 2004/09/30 00:24:59 ksekar
381 <rdar://problem/3695802> Dynamically update default registration domains on config change
383 Revision 1.200 2004/09/26 23:20:35 ksekar
384 <rdar://problem/3813108> Allow default registrations in multiple wide-area domains
386 Revision 1.199 2004/09/24 23:54:55 cheshire
387 <rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
389 Revision 1.198 2004/09/24 23:47:49 cheshire
390 Correct comment and error message
392 Revision 1.197 2004/09/24 23:39:27 cheshire
393 <rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
395 Revision 1.196 2004/09/24 20:53:04 cheshire
396 Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
398 Revision 1.195 2004/09/24 19:21:45 cheshire
399 <rdar://problem/3671626> Report "Address already in use" errors
401 Revision 1.194 2004/09/24 19:16:54 cheshire
402 Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
403 Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
405 Revision 1.193 2004/09/22 00:41:59 cheshire
406 Move tcp connection status codes into the legal range allocated for mDNS use
408 Revision 1.192 2004/09/21 21:02:55 cheshire
409 Set up ifname before calling mDNS_RegisterInterface()
411 Revision 1.191 2004/09/21 19:19:36 cheshire
412 <rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
414 Revision 1.190 2004/09/21 19:04:45 cheshire
415 Strip trailing white space from the ends of lines
417 Revision 1.189 2004/09/21 00:13:28 cheshire
418 Fix build failure (io_connect_t and io_object_t are integers, not pointers)
420 Revision 1.188 2004/09/20 23:52:02 cheshire
421 CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
423 Revision 1.187 2004/09/18 01:37:01 cheshire
426 Revision 1.186 2004/09/18 01:11:57 ksekar
427 <rdar://problem/3806734> Add a user's default domain to empty-string browse list
429 Revision 1.185 2004/09/17 01:08:52 cheshire
430 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
431 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
432 declared in that file are ONLY appropriate to single-address-space embedded applications.
433 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
435 Revision 1.184 2004/09/17 00:19:10 cheshire
436 For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
438 Revision 1.183 2004/09/17 00:15:56 cheshire
439 Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
441 Revision 1.182 2004/09/16 21:36:36 cheshire
442 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
443 Changes to add necessary locking calls around unicast DNS operations
445 Revision 1.181 2004/09/16 02:03:42 cheshire
446 <rdar://problem/3802944> Change address to notify user of kernel flaw
448 Revision 1.180 2004/09/16 01:58:22 cheshire
449 Fix compiler warnings
451 Revision 1.179 2004/09/16 00:24:49 cheshire
452 <rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
454 Revision 1.178 2004/09/15 21:51:34 cheshire
455 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
456 Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
457 the machine, so make sure we don't do this until at least three minutes after boot.
459 Revision 1.177 2004/09/15 01:16:29 cheshire
460 <rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
462 Revision 1.176 2004/09/14 23:42:36 cheshire
463 <rdar://problem/3801296> Need to seed random number generator from platform-layer data
465 Revision 1.175 2004/09/14 21:35:46 cheshire
466 Minor code tidying, and added comments about CFRetainCounts
468 Revision 1.174 2004/09/14 19:14:57 ksekar
469 <rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
471 Revision 1.173 2004/08/25 23:35:22 ksekar
472 <rdar://problem/3770615>: Error converting shared secret from base-64 to binary
474 Revision 1.172 2004/08/25 02:01:45 cheshire
475 <rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
477 Revision 1.171 2004/08/25 01:04:42 cheshire
478 Don't need to CFRelease name and array
480 Revision 1.170 2004/08/25 00:37:28 ksekar
481 <rdar://problem/3774635>: Cleanup DynDNS hostname registration code
483 Revision 1.169 2004/08/18 17:35:41 ksekar
484 <rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
486 Revision 1.168 2004/08/17 03:16:24 ksekar
487 Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
489 Revision 1.167 2004/08/17 00:52:43 ksekar
490 Fix config file parse error, make semantics match SCPreferences
493 Revision 1.166 2004/08/16 19:55:07 ksekar
494 Change enumeration type to BrowseDefault to construct empty-string
495 browse list as result of checking 1.161.
497 Revision 1.165 2004/08/16 19:52:40 ksekar
498 Pass computer name + zone for FQDN after keychain notification,
499 setting global default service registration domain to the zone.
501 Revision 1.164 2004/08/16 16:52:37 ksekar
502 Pass in zone read from keychain to mDNS_SetFQDNs.
504 Revision 1.163 2004/08/14 03:22:42 cheshire
505 <rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
506 Add GetUserSpecifiedDDNSName() routine
507 Convert ServiceRegDomain to domainname instead of C string
508 Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
510 Revision 1.162 2004/08/12 22:34:00 cheshire
511 All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
513 Revision 1.161 2004/08/11 00:17:46 ksekar
514 <rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
515 set default bit for their domains
517 Revision 1.160 2004/07/29 19:27:16 ksekar
518 NATPMP Support - minor fixes and cleanup
520 Revision 1.159 2004/07/26 22:49:31 ksekar
521 <rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
523 Revision 1.158 2004/07/13 21:24:24 rpantos
524 Fix for <rdar://problem/3701120>.
526 Revision 1.157 2004/06/08 18:54:48 ksekar
527 <rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
529 Revision 1.156 2004/06/05 00:04:26 cheshire
530 <rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
532 Revision 1.155 2004/06/04 08:58:30 ksekar
533 <rdar://problem/3668624>: Keychain integration for secure dynamic update
535 Revision 1.154 2004/05/31 22:22:28 ksekar
536 <rdar://problem/3668639>: wide-area domains should be returned in
537 reg. domain enumeration
539 Revision 1.153 2004/05/26 17:06:33 cheshire
540 <rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
542 Revision 1.152 2004/05/18 23:51:26 cheshire
543 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
545 Revision 1.151 2004/05/17 21:46:34 cheshire
546 <rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
547 Take care to correctly update InterfaceIDs when a dormant interface comes back to life
549 Revision 1.150 2004/05/13 04:54:20 ksekar
550 Unified list copy/free code. Added symetric list for
552 Revision 1.149 2004/05/13 03:55:14 ksekar
553 Fixed list traversal bug in FoundDefSearchDomain.
555 Revision 1.148 2004/05/12 22:03:08 ksekar
556 Made GetSearchDomainList a true platform-layer call (declaration moved
557 from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
558 only on non-OSX platforms. Changed call to return a copy of the list
559 to avoid shared memory issues. Added a routine to free the list.
561 Revision 1.147 2004/05/12 02:03:25 ksekar
562 Non-local domains will only be browsed by default, and show up in
563 _browse domain enumeration, if they contain an _browse._dns-sd ptr record.
565 Revision 1.146 2004/04/27 02:49:15 cheshire
566 <rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
568 Revision 1.145 2004/04/21 03:08:03 cheshire
569 Rename 'alias' to more descriptive name 'primary'
571 Revision 1.144 2004/04/21 03:04:35 cheshire
572 Minor cleanup for clarity
574 Revision 1.143 2004/04/21 03:03:30 cheshire
575 Preparation work: AddInterfaceToList() should return pointer to structure it creates
577 Revision 1.142 2004/04/21 02:49:11 cheshire
578 To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
580 Revision 1.141 2004/04/21 02:20:47 cheshire
581 Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
583 Revision 1.140 2004/04/14 23:09:29 ksekar
584 Support for TSIG signed dynamic updates.
586 Revision 1.139 2004/04/09 17:40:26 cheshire
587 Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
589 Revision 1.138 2004/04/09 16:37:16 cheshire
590 Suggestion from Bob Bradley:
591 Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
593 Revision 1.137 2004/04/08 00:59:55 cheshire
594 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
595 Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
597 Revision 1.136 2004/04/07 01:08:57 cheshire
598 <rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
600 Revision 1.135 2004/03/19 01:01:03 ksekar
601 Fixed config file parsing to chop newline
603 Revision 1.134 2004/03/13 01:57:34 ksekar
604 <rdar://problem/3192546>: DynDNS: Dynamic update of service records
606 Revision 1.133 2004/02/02 22:46:56 cheshire
607 Move "CFRelease(dict);" inside the "if (dict)" check
609 Revision 1.132 2004/01/28 02:30:08 ksekar
610 Added default Search Domains to unicast browsing, controlled via
611 Networking sharing prefs pane. Stopped sending unicast messages on
612 every interface. Fixed unicast resolving via mach-port API.
614 Revision 1.131 2004/01/27 22:57:48 cheshire
615 <rdar://problem/3534352>: Need separate socket for issuing unicast queries
617 Revision 1.130 2004/01/27 22:28:40 cheshire
618 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
619 Additional lingering port 53 code deleted
621 Revision 1.129 2004/01/27 20:15:23 cheshire
622 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
624 Revision 1.128 2004/01/24 23:58:17 cheshire
625 Change to use mDNSVal16() instead of shifting and ORing
627 Revision 1.127 2004/01/24 04:59:16 cheshire
628 Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
630 Revision 1.126 2004/01/23 23:23:15 ksekar
631 Added TCP support for truncated unicast messages.
633 Revision 1.125 2004/01/22 03:43:09 cheshire
634 Export constants like mDNSInterface_LocalOnly so that the client layers can use them
636 Revision 1.124 2004/01/21 21:53:19 cheshire
637 <rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
639 Revision 1.123 2004/01/20 03:18:25 cheshire
640 Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
642 Revision 1.122 2003/12/17 20:43:59 cheshire
643 <rdar://problem/3496728>: Syslog messages saying "sendto failed"
645 Revision 1.121 2003/12/13 03:05:28 ksekar
646 <rdar://problem/3192548>: DynDNS: Unicast query of service records
648 Revision 1.120 2003/12/08 21:00:46 rpantos
649 Changes to support mDNSResponder on Linux.
651 Revision 1.119 2003/12/03 02:35:15 cheshire
652 Also report value of m->timenow when logging sendto() failure
654 Revision 1.118 2003/11/14 20:59:09 cheshire
655 Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
656 Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
658 Revision 1.117 2003/11/08 22:18:29 cheshire
659 <rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
661 Revision 1.116 2003/09/23 16:39:49 cheshire
662 When LogAllOperations is set, also report registration and deregistration of interfaces
664 Revision 1.115 2003/09/10 00:45:55 cheshire
665 <rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
667 Revision 1.114 2003/08/27 02:55:13 cheshire
668 <rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
670 Revision 1.113 2003/08/19 22:20:00 cheshire
671 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
672 More minor refinements
674 Revision 1.112 2003/08/19 03:04:43 cheshire
675 <rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
677 Revision 1.111 2003/08/18 22:53:37 cheshire
678 <rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
680 Revision 1.110 2003/08/16 03:39:00 cheshire
681 <rdar://problem/3338440> InterfaceID -1 indicates "local only"
683 Revision 1.109 2003/08/15 02:19:49 cheshire
684 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
685 Also limit number of messages to at most 100
687 Revision 1.108 2003/08/12 22:24:52 cheshire
688 <rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
689 This message indicates a kernel bug, but still we don't want to flood syslog.
690 Do a sleep(1) after writing this log message, to limit the rate.
692 Revision 1.107 2003/08/12 19:56:25 cheshire
695 Revision 1.106 2003/08/12 13:48:32 cheshire
696 Add comment explaining clockdivisor calculation
698 Revision 1.105 2003/08/12 13:44:14 cheshire
699 <rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
700 Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
701 instead of gettimeofday() (which can jump back if the user manually changes their time/date)
703 Revision 1.104 2003/08/12 13:12:07 cheshire
704 Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
706 Revision 1.103 2003/08/08 18:36:04 cheshire
707 <rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
709 Revision 1.102 2003/08/06 00:14:52 cheshire
710 <rdar://problem/3330324> Need to check IP TTL on responses
711 Also add corresponding checks in the IPv6 code path
713 Revision 1.101 2003/08/05 22:20:16 cheshire
714 <rdar://problem/3330324> Need to check IP TTL on responses
716 Revision 1.100 2003/08/05 21:18:50 cheshire
717 <rdar://problem/3363185> mDNSResponder should ignore 6to4
718 Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
720 Revision 1.99 2003/08/05 20:13:52 cheshire
721 <rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
722 Ignore interfaces with the IN6_IFF_NOTREADY flag set
724 Revision 1.98 2003/07/20 03:38:51 ksekar
725 <rdar://problem/3320722>
726 Completed support for Unix-domain socket based API.
728 Revision 1.97 2003/07/19 03:15:16 cheshire
729 Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
730 and add the obvious trivial implementations to each platform support layer
732 Revision 1.96 2003/07/18 00:30:00 cheshire
733 <rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
735 Revision 1.95 2003/07/12 03:15:20 cheshire
736 <rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
737 m->hostlabel even if user hasn't actually actually changed their dot-local hostname
739 Revision 1.94 2003/07/03 00:51:54 cheshire
740 <rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
742 Revision 1.93 2003/07/03 00:09:14 cheshire
743 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
744 Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
746 Revision 1.92 2003/07/02 21:19:51 cheshire
747 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
749 Revision 1.91 2003/06/24 01:53:51 cheshire
750 Minor update to comments
752 Revision 1.90 2003/06/24 01:51:47 cheshire
753 <rdar://problem/3303118> Oops: Double-dispose of sockets
754 Don't need to close sockets: CFSocketInvalidate() does that for us
756 Revision 1.89 2003/06/21 18:12:47 cheshire
757 <rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
758 One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
760 Revision 1.88 2003/06/12 23:38:37 cheshire
761 <rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
762 Also check that scope_id matches before concluding that two interfaces are the same
764 Revision 1.87 2003/06/10 01:14:11 cheshire
765 <rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
767 Revision 1.86 2003/05/28 02:41:52 cheshire
768 <rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
770 Revision 1.85 2003/05/28 02:39:47 cheshire
771 Minor change to debugging messages
773 Revision 1.84 2003/05/27 22:29:40 cheshire
774 Remove out-dated comment
776 Revision 1.83 2003/05/26 03:21:29 cheshire
777 Tidy up address structure naming:
778 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
779 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
780 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
782 Revision 1.82 2003/05/26 03:01:27 cheshire
783 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
785 Revision 1.81 2003/05/24 02:06:42 cheshire
786 <rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
787 Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
788 However, it is probably wise to have the code explicitly set this socket
789 option anyway, in case the default changes in later versions of Unix.
791 Revision 1.80 2003/05/24 02:02:24 cheshire
792 <rdar://problem/3221880> if_indextoname consumes a lot of CPU
793 Fix error in myIfIndexToName; was returning prematurely
795 Revision 1.79 2003/05/23 23:07:44 cheshire
796 <rdar://problem/3268199> Must not write to stderr when running as daemon
798 Revision 1.78 2003/05/23 01:19:04 cheshire
799 <rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
800 Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
802 Revision 1.77 2003/05/23 01:12:05 cheshire
805 Revision 1.76 2003/05/22 01:26:01 cheshire
808 Revision 1.75 2003/05/22 00:07:09 cheshire
809 <rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
810 Extra logging to determine whether there is a bug in CFSocket
812 Revision 1.74 2003/05/21 20:20:12 cheshire
813 Fix warnings (mainly printf format string warnings, like using "%d" where
814 it should say "%lu", etc.) and improve error logging (use strerror()
815 to include textual error message as well as numeric error in log messages).
817 Revision 1.73 2003/05/21 17:56:29 ksekar
818 <rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
820 Revision 1.72 2003/05/14 18:48:41 cheshire
821 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
822 More minor refinements:
823 mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
824 mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
826 Revision 1.71 2003/05/14 07:08:37 cheshire
827 <rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
828 Previously, when there was any network configuration change, mDNSResponder
829 would tear down the entire list of active interfaces and start again.
830 That was very disruptive, and caused the entire cache to be flushed,
831 and caused lots of extra network traffic. Now it only removes interfaces
832 that have really gone, and only adds new ones that weren't there before.
834 Revision 1.70 2003/05/07 18:30:24 cheshire
835 Fix signed/unsigned comparison warning
837 Revision 1.69 2003/05/06 20:14:44 cheshire
840 Revision 1.68 2003/05/06 00:00:49 cheshire
841 <rdar://problem/3248914> Rationalize naming of domainname manipulation functions
843 Revision 1.67 2003/04/29 00:43:44 cheshire
844 Fix compiler warnings
846 Revision 1.66 2003/04/26 02:41:58 cheshire
847 <rdar://problem/3241281> Change timenow from a local variable to a structure member
849 Revision 1.65 2003/04/26 02:34:01 cheshire
850 Add missing mDNSexport
852 Revision 1.64 2003/04/15 16:48:06 jgraessl
853 <rdar://problem/3228833>
854 Modified code in CFSocket notifier function to read all packets on the socket
855 instead of reading only one packet every time the notifier was called.
857 Revision 1.63 2003/04/15 16:33:50 jgraessl
858 <rdar://problem/3221880>
859 Switched to our own copy of if_indextoname to improve performance.
861 Revision 1.62 2003/03/28 01:55:44 cheshire
862 Minor improvements to debugging messages
864 Revision 1.61 2003/03/27 03:30:56 cheshire
865 <rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
866 Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
868 1. Make mDNS_DeregisterInterface() safe to call from a callback
869 2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
870 (it never really needed to deregister the interface at all)
872 Revision 1.60 2003/03/15 04:40:38 cheshire
873 Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
875 Revision 1.59 2003/03/11 01:23:26 cheshire
876 <rdar://problem/3194246> mDNSResponder socket problems
878 Revision 1.58 2003/03/06 01:43:04 cheshire
879 <rdar://problem/3189097> Additional debugging code in mDNSResponder
880 Improve "LIST_ALL_INTERFACES" output
882 Revision 1.57 2003/03/05 22:36:27 cheshire
883 <rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
884 Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
886 Revision 1.56 2003/03/05 01:50:38 cheshire
887 <rdar://problem/3189097> Additional debugging code in mDNSResponder
889 Revision 1.55 2003/02/21 01:54:09 cheshire
890 <rdar://problem/3099194> mDNSResponder needs performance improvements
891 Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
893 Revision 1.54 2003/02/20 06:48:35 cheshire
894 <rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
895 Reviewed by: Josh Graessley, Bob Bradley
897 Revision 1.53 2003/01/29 02:21:23 cheshire
898 Return mStatus_Invalid if can't send packet because socket not available
900 Revision 1.52 2003/01/28 19:39:43 jgraessl
901 Enabling AAAA over IPv4 support.
903 Revision 1.51 2003/01/28 05:11:23 cheshire
904 Fixed backwards comparison in SearchForInterfaceByName
906 Revision 1.50 2003/01/13 23:49:44 jgraessl
907 Merged changes for the following fixes in to top of tree:
908 <rdar://problem/3086540> computer name changes not handled properly
909 <rdar://problem/3124348> service name changes are not properly handled
910 <rdar://problem/3124352> announcements sent in pairs, failing chattiness test
912 Revision 1.49 2002/12/23 22:13:30 jgraessl
913 Reviewed by: Stuart Cheshire
914 Initial IPv6 support for mDNSResponder.
916 Revision 1.48 2002/11/22 01:37:52 cheshire
917 <rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
919 Revision 1.47 2002/09/21 20:44:51 zarzycki
922 Revision 1.46 2002/09/19 21:25:35 cheshire
923 mDNS_snprintf() doesn't need to be in a separate file
925 Revision 1.45 2002/09/17 01:45:13 cheshire
926 Add LIST_ALL_INTERFACES symbol for debugging
928 Revision 1.44 2002/09/17 01:36:23 cheshire
929 Move Puma support to mDNSMacOSXPuma.c
931 Revision 1.43 2002/09/17 01:05:28 cheshire
932 Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
934 Revision 1.42 2002/09/16 23:13:50 cheshire
939 // ***************************************************************************
941 // Supporting routines to run mDNS on a CFRunLoop platform
942 // ***************************************************************************
944 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
945 // including ones that mDNSResponder chooses not to use.
946 #define LIST_ALL_INTERFACES 0
948 // For enabling AAAA records over IPv4. Setting this to 0 sends only
949 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
950 // AAAA and A records over both IPv4 and IPv6.
951 #define AAAA_OVER_V4 1
953 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
954 #include "DNSCommon.h"
955 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
956 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
957 #include "PlatformCommon.h"
960 #include <stdarg.h> // For va_list support
962 #include <net/if_types.h> // For IFT_ETHER
963 #include <net/if_dl.h>
965 #include <sys/param.h>
966 #include <sys/socket.h>
967 #include <sys/sysctl.h>
969 #include <sys/ioctl.h>
970 #include <time.h> // platform support for UTC time
971 #include <arpa/inet.h> // for inet_aton
973 #include <netinet/in.h> // For IP_RECVTTL
975 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
978 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
979 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
980 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
982 #include <Security/Security.h>
986 // Code contributed by Dave Heller:
987 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
988 // work on Mac OS X 10.1, which does not have the getifaddrs call.
989 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
990 #if RUN_ON_PUMA_WITHOUT_IFADDRS
991 #include "mDNSMacOSXPuma.c"
996 #include <IOKit/IOKitLib.h>
997 #include <IOKit/IOMessage.h>
998 #include <mach/mach_time.h>
1000 typedef struct SearchListElem
1002 struct SearchListElem
*next
;
1005 DNSQuestion BrowseQ
;
1006 DNSQuestion DefBrowseQ
;
1007 DNSQuestion LegacyBrowseQ
;
1008 DNSQuestion RegisterQ
;
1009 DNSQuestion DefRegisterQ
;
1010 ARListElem
*AuthRecs
;
1014 // ***************************************************************************
1017 static mDNSu32 clockdivisor
= 0;
1019 // for domain enumeration and default browsing/registration
1020 static SearchListElem
*SearchList
= NULL
; // where we search for _browse domains
1021 static DNSQuestion LegacyBrowseDomainQ
; // our local enumeration query for _legacy._browse domains
1022 static DNameListElem
*DefBrowseList
= NULL
; // cache of answers to above query (where we search for empty string browses)
1023 static DNameListElem
*DefRegList
= NULL
; // manually generated list of domains where we register for empty string registrations
1024 static ARListElem
*SCPrefBrowseDomains
= NULL
; // manually generated local-only PTR records for browse domains we get from SCPreferences
1026 static domainname DynDNSRegDomain
; // Default wide-area zone for service registration
1027 static CFArrayRef DynDNSBrowseDomains
= NULL
; // Default wide-area zones for legacy ("empty string") browses
1028 static domainname DynDNSHostname
;
1030 static mDNSBool DomainDiscoveryDisabled
= mDNSfalse
;
1032 #define CONFIG_FILE "/etc/mDNSResponder.conf"
1033 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
1034 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
1036 // Function Prototypes
1037 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
);
1039 // ***************************************************************************
1042 // routines to allow access to default domain lists from daemon layer
1044 mDNSexport DNameListElem
*mDNSPlatformGetSearchDomainList(void)
1046 return mDNS_CopyDNameList(DefBrowseList
);
1049 mDNSexport DNameListElem
*mDNSPlatformGetRegDomainList(void)
1051 return mDNS_CopyDNameList(DefRegList
);
1054 // utility routines to manage registration domain lists
1056 mDNSlocal
void AddDefRegDomain(domainname
*d
)
1058 DNameListElem
*newelem
= NULL
, *ptr
;
1060 // make sure name not already in list
1061 for (ptr
= DefRegList
; ptr
; ptr
= ptr
->next
)
1063 if (SameDomainName(&ptr
->name
, d
))
1064 { debugf("duplicate addition of default reg domain %##s", d
->c
); return; }
1067 newelem
= mallocL("DNameListElem", sizeof(*newelem
));
1068 if (!newelem
) { LogMsg("Error - malloc"); return; }
1069 AssignDomainName(&newelem
->name
, d
);
1070 newelem
->next
= DefRegList
;
1071 DefRegList
= newelem
;
1073 DefaultRegDomainChanged(d
, mDNStrue
);
1074 udsserver_default_reg_domain_changed(d
, mDNStrue
);
1077 mDNSlocal
void RemoveDefRegDomain(domainname
*d
)
1079 DNameListElem
*ptr
= DefRegList
, *prev
= NULL
;
1083 if (SameDomainName(&ptr
->name
, d
))
1085 if (prev
) prev
->next
= ptr
->next
;
1086 else DefRegList
= ptr
->next
;
1087 freeL("DNameListElem", ptr
);
1088 DefaultRegDomainChanged(d
, mDNSfalse
);
1089 udsserver_default_reg_domain_changed(d
, mDNSfalse
);
1095 debugf("Requested removal of default registration domain %##s not in contained in list", d
->c
);
1098 mDNSlocal
void NotifyOfElusiveBug(const char *title
, mDNSu32 radarid
, const char *msg
)
1100 extern mDNS mDNSStorage
;
1101 NetworkInterfaceInfoOSX
*i
;
1102 static int notifyCount
= 0;
1103 if (notifyCount
) return;
1105 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
1106 // To avoid this, we don't try to display alerts in the first three minutes after boot.
1107 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
1109 // Determine if we're at Apple (17.*.*.*)
1110 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
1111 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
1113 if (!i
) return; // If not at Apple, don't show the alert
1115 // Send a notification to the user to contact coreos-networking
1117 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
1118 CFStringRef alertFormat
= CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
1119 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, alertFormat
, radarid
, msg
);
1120 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
1123 mDNSlocal
struct ifaddrs
* myGetIfAddrs(int refresh
)
1125 static struct ifaddrs
*ifa
= NULL
;
1133 if (ifa
== NULL
) getifaddrs(&ifa
);
1138 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
1140 NetworkInterfaceInfoOSX
*i
;
1141 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1142 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
1144 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
1145 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) )) return(i
);
1149 mDNSlocal
int myIfIndexToName(u_short index
, char* name
)
1151 struct ifaddrs
*ifa
;
1152 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
1153 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
1154 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
1155 { strncpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
1159 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
*const m
, mDNSu32 index
)
1161 NetworkInterfaceInfoOSX
*i
;
1162 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
1164 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1165 // Don't get tricked by inactive interfaces with no InterfaceID set
1166 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
1170 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS
*const m
, mDNSInterfaceID id
)
1172 NetworkInterfaceInfoOSX
*i
;
1173 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
1175 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
1176 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
1177 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
1181 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
1183 mDNSBool result
= mDNSfalse
;
1184 SCNetworkConnectionFlags flags
;
1185 SCNetworkReachabilityRef ReachRef
= NULL
;
1187 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
1188 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
1189 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
1190 result
= flags
& kSCNetworkFlagsConnectionRequired
;
1193 if (ReachRef
) CFRelease(ReachRef
);
1197 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1198 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1199 // OR send via our primary v4 unicast socket
1200 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1201 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
1205 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1206 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1207 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1208 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
1209 char *ifa_name
= info
? info
->ifa_name
: "unicast";
1210 struct sockaddr_storage to
;
1213 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
1214 // anonymous socket created for this purpose, so that we'll receive the response.
1215 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
1216 if (info
&& !mDNSAddrIsDNSMulticast(dst
))
1218 const DNSMessage
*const m
= (DNSMessage
*)msg
;
1219 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
1220 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
1223 if (dst
->type
== mDNSAddrType_IPv4
)
1225 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1226 sin_to
->sin_len
= sizeof(*sin_to
);
1227 sin_to
->sin_family
= AF_INET
;
1228 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1229 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1230 s
= info
? info
->ss
.sktv4
: m
->p
->unicastsockets
.sktv4
;
1232 else if (dst
->type
== mDNSAddrType_IPv6
)
1234 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1235 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1236 sin6_to
->sin6_family
= AF_INET6
;
1237 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1238 sin6_to
->sin6_flowinfo
= 0;
1239 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1240 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1241 s
= info
? info
->ss
.sktv6
: m
->p
->unicastsockets
.sktv6
;
1245 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1246 return mStatus_BadParamErr
;
1249 // Don't send if it would cause dial on demand connection initiation. As an optimization,
1250 // don't bother consulting reachability API / routing table when sending Multicast DNS
1251 // since we ignore PPP interfaces for mDNS traffic
1252 if (!mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
1254 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1255 return mStatus_NoError
;
1259 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1260 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1262 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1263 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1265 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1266 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1267 if (s
< 0) return(mStatus_Invalid
);
1269 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1272 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1273 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1274 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1275 // Don't report EHOSTUNREACH in the first three minutes after boot
1276 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1277 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1278 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1279 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1280 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1281 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1282 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1283 return(mStatus_UnknownErr
);
1286 return(mStatus_NoError
);
1289 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1290 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1292 static unsigned int numLogMessages
= 0;
1293 struct iovec databuffers
= { (char *)buffer
, max
};
1296 struct cmsghdr
*cmPtr
;
1297 char ancillary
[1024];
1299 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1301 // Set up the message
1302 msg
.msg_name
= (caddr_t
)from
;
1303 msg
.msg_namelen
= *fromlen
;
1304 msg
.msg_iov
= &databuffers
;
1306 msg
.msg_control
= (caddr_t
)&ancillary
;
1307 msg
.msg_controllen
= sizeof(ancillary
);
1311 n
= recvmsg(s
, &msg
, 0);
1314 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1317 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1319 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1320 s
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1323 if (msg
.msg_flags
& MSG_CTRUNC
)
1325 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1329 *fromlen
= msg
.msg_namelen
;
1331 // Parse each option out of the ancillary data.
1332 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1334 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1335 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1337 dstaddr
->type
= mDNSAddrType_IPv4
;
1338 dstaddr
->ip
.v4
.NotAnInteger
= *(u_int32_t
*)CMSG_DATA(cmPtr
);
1340 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1342 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1343 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1345 mDNSPlatformMemCopy(sdl
->sdl_data
, ifname
, sdl
->sdl_nlen
);
1346 ifname
[sdl
->sdl_nlen
] = 0;
1347 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1350 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1352 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1354 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1356 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1357 dstaddr
->type
= mDNSAddrType_IPv6
;
1358 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1359 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1361 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1363 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1370 // On entry, context points to our CFSocketSet
1371 // If ss->info is NULL, we received this packet on our anonymous unicast socket
1372 // If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
1373 mDNSlocal
void myCFSocketCallBack(const CFSocketRef cfs
, const CFSocketCallBackType CallBackType
, const CFDataRef address
, const void *const data
, void *const context
)
1375 const CFSocketSet
*const ss
= (const CFSocketSet
*)context
;
1376 mDNS
*const m
= ss
->m
;
1377 const int skt
= CFSocketGetNative(cfs
);
1378 const int s1
= (cfs
== ss
->cfsv4
) ? ss
->sktv4
: (cfs
== ss
->cfsv6
) ? ss
->sktv6
: -1;
1381 (void)address
; // Parameter not used
1382 (void)data
; // Parameter not used
1384 if (CallBackType
!= kCFSocketReadCallBack
)
1385 LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType
);
1387 if (s1
< 0 || s1
!= skt
)
1389 LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1
, skt
, cfs
);
1390 LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss
->cfsv4
, ss
->sktv4
);
1391 LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss
->cfsv6
, ss
->sktv6
);
1396 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1397 mDNSInterfaceID InterfaceID
= ss
->info
? ss
->info
->ifinfo
.InterfaceID
: mDNSNULL
;
1398 mDNSAddr senderAddr
, destAddr
;
1399 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1400 struct sockaddr_storage from
;
1401 size_t fromlen
= sizeof(from
);
1402 char packetifname
[IF_NAMESIZE
] = "";
1404 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1408 if (from
.ss_family
== AF_INET
)
1410 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1411 senderAddr
.type
= mDNSAddrType_IPv4
;
1412 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1413 senderPort
.NotAnInteger
= sin
->sin_port
;
1415 else if (from
.ss_family
== AF_INET6
)
1417 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1418 senderAddr
.type
= mDNSAddrType_IPv6
;
1419 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1420 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1424 LogMsg("myCFSocketCallBack from is unknown address family %d", from
.ss_family
);
1428 if (mDNSAddrIsDNSMulticast(&destAddr
))
1430 // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
1431 // sockets API means that even though this socket has only officially joined the multicast group
1432 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1433 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1434 // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
1435 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1436 if (!ss
->info
|| !ss
->info
->Exists
)
1438 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr
, &destAddr
);
1441 else if (strcmp(ss
->info
->ifa_name
, packetifname
))
1443 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
1444 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
, packetifname
);
1448 verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
1449 &senderAddr
, &destAddr
, &ss
->info
->ifinfo
.ip
, ss
->info
->ifa_name
);
1453 // Note: Unicast packets are delivered to *one* of our listening sockets,
1454 // not necessarily the one bound to the physical interface where the packet arrived.
1455 // To sort this out we search our interface list and update InterfaceID to reference
1456 // the mDNSCore interface object for the interface where the packet was actually received.
1457 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1458 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1459 if (intf
) InterfaceID
= intf
->InterfaceID
;
1462 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1465 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1467 // Something is busted here.
1468 // CFSocket says there is a packet, but myrecvfrom says there is not.
1469 // Try calling select() to get another opinion.
1470 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1471 // All of this is racy, as data may have arrived after the call to select()
1472 int save_errno
= errno
;
1476 socklen_t solen
= sizeof(int);
1479 FD_SET(s1
, &readfds
);
1480 struct timeval timeout
;
1482 timeout
.tv_usec
= 0;
1483 int selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1484 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1485 LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1486 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1487 LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1488 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1489 LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno
);
1490 static unsigned int numLogMessages
= 0;
1491 if (numLogMessages
++ < 100)
1492 LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1493 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1494 if (numLogMessages
> 5)
1495 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
1496 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1497 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1499 sleep(1); // After logging this error, rate limit so we don't flood syslog
1503 // TCP socket support for unicast DNS and Dynamic DNS Update
1507 TCPConnectionCallback callback
;
1512 mDNSlocal
void tcpCFSocketCallback(CFSocketRef cfs
, CFSocketCallBackType CallbackType
, CFDataRef address
,
1513 const void *data
, void *context
)
1515 #pragma unused(CallbackType, address, data)
1516 mDNSBool connect
= mDNSfalse
;
1518 tcpInfo_t
*info
= context
;
1519 if (!info
->connected
)
1522 info
->connected
= mDNStrue
; // prevent connected flag from being set in future callbacks
1524 info
->callback(CFSocketGetNative(cfs
), info
->context
, connect
);
1525 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1528 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1529 TCPConnectionCallback callback
, void *context
, int *descriptor
)
1531 int sd
, on
= 1; // "on" for setsockopt
1532 struct sockaddr_in saddr
;
1533 CFSocketContext cfContext
= { 0, NULL
, 0, 0, 0 };
1536 CFRunLoopSourceRef rls
;
1538 (void)InterfaceID
; //!!!KRS use this if non-zero!!!
1541 if (dst
->type
!= mDNSAddrType_IPv4
)
1543 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1544 return mStatus_UnknownErr
;
1547 bzero(&saddr
, sizeof(saddr
));
1548 saddr
.sin_family
= AF_INET
;
1549 saddr
.sin_port
= dstport
.NotAnInteger
;
1550 saddr
.sin_len
= sizeof(saddr
);
1551 memcpy(&saddr
.sin_addr
, &dst
->ip
.v4
.NotAnInteger
, sizeof(saddr
.sin_addr
));
1553 // Don't send if it would cause dial on demand connection initiation.
1554 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1556 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1557 return mStatus_UnknownErr
;
1560 sd
= socket(AF_INET
, SOCK_STREAM
, 0);
1561 if (sd
< 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd
, errno
, strerror(errno
)); return mStatus_UnknownErr
; }
1564 if (fcntl(sd
, F_SETFL
, O_NONBLOCK
) < 0)
1566 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1567 return mStatus_UnknownErr
;
1570 // receive interface identifiers
1571 if (setsockopt(sd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1573 LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
));
1574 return mStatus_UnknownErr
;
1576 // set up CF wrapper, add to Run Loop
1577 info
= mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t
));
1578 info
->callback
= callback
;
1579 info
->context
= context
;
1580 cfContext
.info
= info
;
1581 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketReadCallBack
| kCFSocketConnectCallBack
,
1582 tcpCFSocketCallback
, &cfContext
);
1585 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
1586 freeL("mDNSPlatformTCPConnect", info
);
1587 return mStatus_UnknownErr
;
1590 rls
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, sr
, 0);
1593 LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
1594 freeL("mDNSPlatformTCPConnect", info
);
1595 return mStatus_UnknownErr
;
1598 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1601 // initiate connection wth peer
1602 if (connect(sd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1604 if (errno
== EINPROGRESS
)
1606 info
->connected
= 0;
1608 return mStatus_ConnPending
;
1610 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno
));
1611 freeL("mDNSPlatformTCPConnect", info
);
1612 CFSocketInvalidate(sr
); // Note: Also closes the underlying socket
1613 return mStatus_ConnFailed
;
1615 info
->connected
= 1;
1617 return mStatus_ConnEstablished
;
1620 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
1622 CFSocketContext cfContext
;
1626 if (sd
< 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd
);
1628 // Get the CFSocket for the descriptor
1629 sr
= CFSocketCreateWithNative(kCFAllocatorDefault
, sd
, kCFSocketNoCallBack
, NULL
, NULL
);
1630 if (!sr
) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
1632 CFSocketGetContext(sr
, &cfContext
);
1633 if (!cfContext
.info
)
1635 LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
1639 CFRelease(sr
); // this only releases the copy we allocated with CreateWithNative above
1641 info
= cfContext
.info
;
1643 // Note: MUST NOT close the underlying native BSD socket.
1644 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
1645 // because it first has to unhook the sockets from its select() call, before it can safely close them.
1646 CFSocketInvalidate(sr
);
1648 freeL("mDNSPlatformTCPCloseConnection", info
);
1651 mDNSexport
int mDNSPlatformReadTCP(int sd
, void *buf
, int buflen
)
1653 int nread
= recv(sd
, buf
, buflen
, 0);
1656 if (errno
== EAGAIN
) return 0; // no data available (call would block)
1657 LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno
));
1663 mDNSexport
int mDNSPlatformWriteTCP(int sd
, const char *msg
, int len
)
1665 int nsent
= send(sd
, msg
, len
, 0);
1669 if (errno
== EAGAIN
) return 0; // blocked
1670 LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno
));
1676 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1677 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1679 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1680 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1683 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1688 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1689 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1691 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1694 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1699 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1702 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1703 if (!state
) return mDNSfalse
;
1704 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1705 return val
? mDNStrue
: mDNSfalse
;
1708 mDNSlocal
void GetUserSpecifiedDDNSConfig(domainname
*const fqdn
, domainname
*const regDomain
, CFArrayRef
*const browseDomains
)
1710 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
1713 regDomain
->c
[0] = 0;
1715 *browseDomains
= NULL
;
1717 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL
, NULL
);
1720 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, CFSTR("Setup:/Network/DynamicDNS"));
1723 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("HostNames"));
1724 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
1726 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
1727 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
1729 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
1732 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1733 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
1734 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
1735 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
1740 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("RegistrationDomains"));
1741 if (regArray
&& CFArrayGetCount(regArray
) > 0)
1743 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
1744 if (regDict
&& DDNSSettingEnabled(regDict
))
1746 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
1749 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
1750 !MakeDomainNameFromDNSNameString(regDomain
, buf
) || !regDomain
->c
[0])
1751 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
1752 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf
);
1756 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("BrowseDomains"));
1757 if (browseArray
&& CFArrayGetCount(browseArray
) > 0)
1759 CFRetain(browseArray
);
1760 *browseDomains
= browseArray
;
1768 mDNSlocal
void SetDDNSNameStatus(domainname
*const dname
, mStatus status
)
1770 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL
, NULL
);
1773 char uname
[MAX_ESCAPED_DOMAIN_NAME
];
1774 ConvertDomainNameToCString(dname
, uname
);
1780 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
1784 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
1785 // That single entity is a CFDictionary with name "HostNames".
1786 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
1787 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
1788 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
1789 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
1790 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
1792 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
1793 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
1794 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
1795 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
1798 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
1799 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
1802 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
1805 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
1808 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
1811 SCDynamicStoreSetValue(store
, CFSTR("State:/Network/DynamicDNS"), StateDict
);
1812 CFRelease(StateDict
);
1814 CFRelease(StateVals
[0]);
1816 CFRelease(HostVals
[0]);
1818 CFRelease(StatusVals
[0]);
1820 CFRelease(HostKeys
[0]);
1826 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1827 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1828 mDNSlocal mStatus
SetupSocket(mDNS
*const m
, CFSocketSet
*cp
, mDNSBool mcast
, const mDNSAddr
*ifaddr
, u_short sa_family
)
1830 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1831 CFSocketRef
*c
= (sa_family
== AF_INET
) ? &cp
->cfsv4
: &cp
->cfsv6
;
1832 CFRunLoopSourceRef
*r
= (sa_family
== AF_INET
) ? &cp
->rlsv4
: &cp
->rlsv6
;
1834 const int twofivefive
= 255;
1835 mStatus err
= mStatus_NoError
;
1836 char *errstr
= mDNSNULL
;
1838 mDNSIPPort port
= (mcast
| m
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1840 if (*s
>= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s
); return(-1); }
1841 if (*c
) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c
); return(-1); }
1843 // Open the socket...
1844 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1845 if (skt
< 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1847 // ... with a shared UDP port, if it's for multicast receiving
1848 if (port
.NotAnInteger
) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1849 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1851 if (sa_family
== AF_INET
)
1853 // We want to receive destination addresses
1854 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1855 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1857 // We want to receive interface identifiers
1858 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1859 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1861 // We want to receive packet TTL value so we can check it
1862 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1863 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1865 // Add multicast group membership on this interface, if it's for multicast receiving
1868 struct in_addr addr
= { ifaddr
->ip
.v4
.NotAnInteger
};
1870 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroupv4
.NotAnInteger
;
1871 imr
.imr_interface
= addr
;
1872 err
= setsockopt(skt
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
1873 if (err
< 0) { errstr
= "setsockopt - IP_ADD_MEMBERSHIP"; goto fail
; }
1875 // Specify outgoing interface too
1876 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_IF
, &addr
, sizeof(addr
));
1877 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_IF"; goto fail
; }
1880 // Send unicast packets with TTL 255
1881 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1882 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1884 // And multicast packets with TTL 255 too
1885 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1886 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1888 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1889 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1890 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1891 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1893 // And start listening for packets
1894 struct sockaddr_in listening_sockaddr
;
1895 listening_sockaddr
.sin_family
= AF_INET
;
1896 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1897 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1898 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1899 if (err
) { errstr
= "bind"; goto fail
; }
1901 else if (sa_family
== AF_INET6
)
1903 // We want to receive destination addresses and receive interface identifiers
1904 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1905 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1907 // We want to receive packet hop count value so we can check it
1908 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1909 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1911 // We want to receive only IPv6 packets, without this option, we may
1912 // get IPv4 addresses as mapped addresses.
1913 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1914 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1918 // Add multicast group membership on this interface, if it's for multicast receiving
1919 int interface_id
= if_nametoindex(cp
->info
->ifa_name
);
1920 struct ipv6_mreq i6mr
;
1921 i6mr
.ipv6mr_interface
= interface_id
;
1922 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroupv6
;
1923 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
1924 if (err
< 0) { errstr
= "setsockopt - IPV6_JOIN_GROUP"; goto fail
; }
1926 // Specify outgoing interface too
1927 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &interface_id
, sizeof(interface_id
));
1928 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_IF"; goto fail
; }
1931 // Send unicast packets with TTL 255
1932 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1933 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1935 // And multicast packets with TTL 255 too
1936 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1937 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1939 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1941 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1942 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1943 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1944 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1947 // Want to receive our own packets
1948 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1949 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1951 // And start listening for packets
1952 struct sockaddr_in6 listening_sockaddr6
;
1953 bzero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1954 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1955 listening_sockaddr6
.sin6_family
= AF_INET6
;
1956 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1957 listening_sockaddr6
.sin6_flowinfo
= 0;
1958 // listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
1959 listening_sockaddr6
.sin6_scope_id
= 0;
1960 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1961 if (err
) { errstr
= "bind"; goto fail
; }
1964 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1966 CFSocketContext myCFSocketContext
= { 0, cp
, NULL
, NULL
, NULL
};
1967 *c
= CFSocketCreateWithNative(kCFAllocatorDefault
, *s
, kCFSocketReadCallBack
, myCFSocketCallBack
, &myCFSocketContext
);
1968 *r
= CFSocketCreateRunLoopSource(kCFAllocatorDefault
, *c
, 0);
1969 CFRunLoopAddSource(CFRunLoopGetCurrent(), *r
, kCFRunLoopDefaultMode
);
1974 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1975 if (!strcmp(errstr
, "bind") && errno
== EADDRINUSE
)
1976 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
1977 "Alternatively, you can send email to radar-3387020@group.apple.com. "
1978 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1983 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
1985 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
1987 if (sa
->sa_family
== AF_INET
)
1989 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
1990 ip
->type
= mDNSAddrType_IPv4
;
1991 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
1992 return(mStatus_NoError
);
1995 if (sa
->sa_family
== AF_INET6
)
1997 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
1998 ip
->type
= mDNSAddrType_IPv6
;
1999 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2000 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2001 return(mStatus_NoError
);
2004 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2005 return(mStatus_Invalid
);
2008 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2010 mDNSEthAddr eth
= zeroEthAddr
;
2011 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2014 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2017 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2020 CFRange range
= { 0, 6 }; // Offset, length
2021 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2022 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2025 CFRelease(entityname
);
2032 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2034 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2035 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2038 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2039 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2041 NetworkInterfaceInfoOSX
**p
;
2042 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2043 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2045 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2046 (*p
)->Exists
= mDNStrue
;
2050 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2051 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2052 if (!i
) return(mDNSNULL
);
2053 bzero(i
, sizeof(NetworkInterfaceInfoOSX
));
2054 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2055 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2056 strcpy(i
->ifa_name
, ifa
->ifa_name
);
2058 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2060 i
->ifinfo
.mask
= mask
;
2061 strncpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2062 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2063 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2064 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2067 i
->Exists
= mDNStrue
;
2069 i
->scope_id
= scope_id
;
2071 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2072 i
->Multicast
= (ifa
->ifa_flags
& IFF_MULTICAST
) && !(ifa
->ifa_flags
& IFF_POINTOPOINT
);
2076 i
->ss
.sktv4
= i
->ss
.sktv6
= -1;
2077 i
->ss
.cfsv4
= i
->ss
.cfsv6
= NULL
;
2078 i
->ss
.rlsv4
= i
->ss
.rlsv6
= NULL
;
2084 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2086 NetworkInterfaceInfoOSX
*i
;
2087 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2088 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2089 if (!(i
->ifinfo
.ip
.ip
.v4
.b
[0] == 169 && i
->ifinfo
.ip
.ip
.v4
.b
[1] == 254))
2094 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2096 mDNSBool foundav4
= mDNSfalse
;
2097 mDNSBool foundav6
= mDNSfalse
;
2098 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2099 struct ifaddrs
*v4Loopback
= NULL
;
2100 struct ifaddrs
*v6Loopback
= NULL
;
2101 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2102 char defaultname
[32];
2103 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2104 if (InfoSocket
< 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2105 if (m
->SleepState
) ifa
= NULL
;
2109 #if LIST_ALL_INTERFACES
2110 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2111 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2112 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2113 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2114 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2115 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2116 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2117 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2118 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2119 if (!(ifa
->ifa_flags
& IFF_UP
))
2120 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2121 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2122 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2123 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2124 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2125 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2126 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2127 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2128 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2129 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2130 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2133 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2135 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2136 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2137 mDNSPlatformMemCopy(sdl
->sdl_data
+ sdl
->sdl_nlen
, PrimaryMAC
.b
, 6);
2140 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2141 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2143 if (!ifa
->ifa_netmask
)
2146 SetupAddr(&ip
, ifa
->ifa_addr
);
2147 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2148 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2150 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2153 SetupAddr(&ip
, ifa
->ifa_addr
);
2154 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2155 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2159 int ifru_flags6
= 0;
2160 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2162 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2163 struct in6_ifreq ifr6
;
2164 bzero((char *)&ifr6
, sizeof(ifr6
));
2165 strncpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2166 ifr6
.ifr_addr
= *sin6
;
2167 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2168 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2169 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2171 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2173 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2174 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2175 else v6Loopback
= ifa
;
2178 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2179 if (i
&& i
->Multicast
)
2181 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2182 else foundav6
= mDNStrue
;
2188 ifa
= ifa
->ifa_next
;
2191 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2192 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2193 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2195 // Now the list is complete, set the McastTxRx setting for each interface.
2196 // We always send and receive using IPv4.
2197 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
2198 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
2199 // which means there's a good chance that most or all the other devices on that network should also have v4.
2200 // 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.
2201 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
2202 // so we are willing to make that sacrifice.
2203 NetworkInterfaceInfoOSX
*i
;
2204 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2207 mDNSBool txrx
= i
->Multicast
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2208 if (i
->ifinfo
.McastTxRx
!= txrx
)
2210 i
->ifinfo
.McastTxRx
= txrx
;
2211 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2214 if (InfoSocket
>= 0) close(InfoSocket
);
2216 mDNS_snprintf(defaultname
, sizeof(defaultname
), "Macintosh-%02X%02X%02X%02X%02X%02X",
2217 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2219 // Set up the nice label
2220 domainlabel nicelabel
;
2222 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2223 if (nicelabel
.c
[0] == 0)
2225 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2226 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2229 // Set up the RFC 1034-compliant label
2230 domainlabel hostlabel
;
2232 GetUserSpecifiedLocalHostName(&hostlabel
);
2233 if (hostlabel
.c
[0] == 0)
2235 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2236 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2239 if (SameDomainLabel(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2240 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2243 debugf("Updating m->nicelabel to %#s", nicelabel
.c
);
2244 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2247 if (SameDomainLabel(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2248 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2251 debugf("Updating m->hostlabel to %#s", hostlabel
.c
);
2252 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2256 return(mStatus_NoError
);
2259 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2261 int i
= 0, bits
= 0;
2262 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2265 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2266 while (b
& 0x80) { bits
++; b
<<= 1; }
2269 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2273 // returns count of non-link local V4 addresses registered
2274 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2276 NetworkInterfaceInfoOSX
*i
;
2278 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2281 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
2282 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2283 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2285 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2287 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2288 n
->InterfaceID
= mDNSNULL
;
2291 if (!n
->InterfaceID
)
2293 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2294 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2295 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2296 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2297 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2298 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2299 // 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.
2300 mDNSBool flapping
= (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2301 mDNS_RegisterInterface(m
, n
, flapping
? mDNSPlatformOneSecond
* 5 : 0);
2302 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2303 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
2304 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2305 flapping
? " (Flapping)" : "", n
->InterfaceActive
? " (Primary)" : "");
2309 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2312 if (i
->sa_family
== AF_INET
&& primary
->ss
.sktv4
== -1)
2314 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET
);
2315 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
));
2316 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
));
2319 if (i
->sa_family
== AF_INET6
&& primary
->ss
.sktv6
== -1)
2321 mStatus err
= SetupSocket(m
, &primary
->ss
, mDNStrue
, &i
->ifinfo
.ip
, AF_INET6
);
2322 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
));
2323 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
));
2330 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2332 NetworkInterfaceInfoOSX
*i
;
2333 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2335 if (i
->Exists
) i
->LastSeen
= utc
;
2336 i
->Exists
= mDNSfalse
;
2340 mDNSlocal
void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls
, CFSocketRef cfs
)
2342 // Note: CFSocketInvalidate also closes the underlying socket for us
2343 // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
2344 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
); // rls 2 cfs 3
2345 CFRelease(rls
); // rls ? cfs 3
2346 CFSocketInvalidate(cfs
); // rls ? cfs 1
2347 CFRelease(cfs
); // rls ? cfs ?
2350 mDNSlocal
void CloseSocketSet(CFSocketSet
*ss
)
2352 // Note: MUST NOT close the underlying native BSD sockets.
2353 // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
2354 // because it first has to unhook the sockets from its select() call, before it can safely close them.
2355 if (ss
->cfsv4
) CloseRunLoopSourceSocket(ss
->rlsv4
, ss
->cfsv4
);
2356 if (ss
->cfsv6
) CloseRunLoopSourceSocket(ss
->rlsv6
, ss
->cfsv6
);
2357 ss
->sktv4
= ss
->sktv6
= -1;
2358 ss
->cfsv4
= ss
->cfsv6
= NULL
;
2359 ss
->rlsv4
= ss
->rlsv6
= NULL
;
2362 // returns count of non-link local V4 addresses deregistered
2363 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2366 // If an interface is going away, then deregister this from the mDNSCore.
2367 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2368 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2369 // it refers to has gone away we'll crash.
2370 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2371 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2372 NetworkInterfaceInfoOSX
*i
;
2374 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2376 // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
2377 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2378 if (i
->ifinfo
.InterfaceID
)
2379 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2381 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
2382 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2383 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2384 mDNS_DeregisterInterface(m
, &i
->ifinfo
);
2385 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& (i
->ifinfo
.ip
.ip
.v4
.b
[0] != 169 || i
->ifinfo
.ip
.ip
.v4
.b
[1] != 254)) count
++;
2386 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2387 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2388 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2389 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2394 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2395 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2399 // 2. Close all our CFSockets. We'll recreate them later as necessary.
2400 // (We may have previously had both v4 and v6, and we may not need both any more.)
2401 CloseSocketSet(&i
->ss
);
2402 // 3. If no longer active, delete interface from list and free memory
2405 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2406 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2407 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2408 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2409 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2410 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2414 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2415 freeL("NetworkInterfaceInfoOSX", i
);
2416 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2424 mDNSlocal mStatus
GetDNSConfig(void **result
)
2427 static int MessageShown
= 0;
2428 if (!MessageShown
) { MessageShown
= 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
2430 return mStatus_UnsupportedErr
;
2433 *result
= dns_configuration_copy();
2437 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2438 if (mDNSMacOSXSystemBuildNumber(NULL
) < 8) return mStatus_UnsupportedErr
;
2440 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2441 // Apparently this is expected behaviour -- "not a bug".
2442 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2443 // If we are still getting failures after three minutes, then we log them.
2444 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return mStatus_NoError
;
2446 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2447 return mStatus_UnknownErr
;
2449 return mStatus_NoError
;
2450 #endif // MDNS_NO_DNSINFO
2453 mDNSlocal mStatus
RegisterSplitDNS(mDNS
*m
, int *nAdditions
, int *nDeletions
)
2455 (void)m
; // unused on 10.3 systems
2457 *nAdditions
= *nDeletions
= 0;
2458 mStatus err
= GetDNSConfig(&v
);
2460 #if !MDNS_NO_DNSINFO
2465 dns_config_t
*config
= v
; // use void * to allow compilation on 10.3 systems
2467 p
= m
->uDNS_info
.Servers
;
2468 while (p
) { p
->flag
= -1; p
= p
->next
; } // mark all for deletion
2470 LogOperation("RegisterSplitDNS: Registering %d resolvers", config
->n_resolver
);
2471 for (i
= 0; i
< config
->n_resolver
; i
++)
2475 dns_resolver_t
*r
= config
->resolver
[i
];
2476 if (r
->port
== MulticastDNSPort
.NotAnInteger
) continue; // ignore configurations for .local
2477 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2478 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2480 // check if this is the lowest-weighted server for the domain
2481 for (j
= 0; j
< config
->n_resolver
; j
++)
2483 dns_resolver_t
*p
= config
->resolver
[j
];
2484 if (p
->port
== MulticastDNSPort
.NotAnInteger
) continue;
2485 if (p
->search_order
<= r
->search_order
)
2488 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2489 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2490 if (SameDomainName(&d
, &tmp
))
2491 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2494 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2495 { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
); continue; }
2496 // we're using this resolver - find the first IPv4 address
2497 for (n
= 0; n
< r
->n_nameserver
; n
++)
2499 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& !AddrRequiresPPPConnection(r
->nameserver
[n
]))
2502 if (SetupAddr(&saddr
, r
->nameserver
[n
])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
2503 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
);
2504 p
= m
->uDNS_info
.Servers
;
2507 if (mDNSSameAddress(&p
->addr
, &saddr
) && SameDomainName(&p
->domain
, &d
)) { p
->flag
= 0; break; }
2512 p
= mallocL("DNSServer", sizeof(*p
));
2513 if (!p
) { LogMsg("Error: malloc"); mDNS_Unlock(m
); return mStatus_UnknownErr
; }
2515 AssignDomainName(&p
->domain
, &d
);
2517 p
->next
= m
->uDNS_info
.Servers
;
2518 m
->uDNS_info
.Servers
= p
;
2521 break; // !!!KRS if we ever support round-robin servers, don't break here
2526 // remove all servers marked for deletion
2527 DNSServer
**s
= &m
->uDNS_info
.Servers
;
2534 freeL("DNSServer", p
);
2537 else s
= &(*s
)->next
;
2540 dns_configuration_free(config
);
2547 mDNSlocal mStatus
RegisterNameServers(mDNS
*const m
, CFDictionaryRef dict
)
2552 mDNSAddr saddr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
2555 mDNS_DeleteDNSServers(m
); // deregister orig list
2556 values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
2557 if (!values
) return mStatus_NoError
;
2559 count
= CFArrayGetCount(values
);
2560 for (i
= 0; i
< count
; i
++)
2562 s
= CFArrayGetValueAtIndex(values
, i
);
2563 if (!s
) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
2564 if (!CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
))
2566 LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
2569 if (!inet_aton(buf
, (struct in_addr
*)saddr
.ip
.v4
.b
))
2571 LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf
);
2574 LogOperation("RegisterNameServers: Adding %#a", &saddr
);
2575 mDNS_AddDNSServer(m
, &saddr
, NULL
);
2577 return mStatus_NoError
;
2580 mDNSlocal
void FreeARElemCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2583 ARListElem
*elem
= rr
->RecordContext
;
2584 if (result
== mStatus_MemFree
) freeL("FreeARElemCallback", elem
);
2587 mDNSlocal
void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
2589 SearchListElem
*slElem
= question
->QuestionContext
;
2590 ARListElem
*arElem
, *ptr
, *prev
;
2597 arElem
= mallocL("FoundDomain - arElem", sizeof(ARListElem
));
2598 if (!arElem
) { LogMsg("ERROR: malloc"); return; }
2599 mDNS_SetupResourceRecord(&arElem
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, arElem
);
2600 if (question
== &slElem
->BrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowse
];
2601 else if (question
== &slElem
->DefBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseDefault
];
2602 else if (question
== &slElem
->LegacyBrowseQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeBrowseLegacy
];
2603 else if (question
== &slElem
->RegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
];
2604 else if (question
== &slElem
->DefRegisterQ
) name
= mDNS_DomainTypeNames
[mDNS_DomainTypeRegistrationDefault
];
2605 else { LogMsg("FoundDomain - unknown question"); return; }
2607 MakeDomainNameFromDNSNameString(arElem
->ar
.resrec
.name
, name
);
2608 AppendDNSNameString (arElem
->ar
.resrec
.name
, "local");
2609 AssignDomainName(&arElem
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
);
2610 err
= mDNS_Register(m
, &arElem
->ar
);
2613 LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err
);
2614 freeL("FoundDomain - arElem", arElem
);
2617 arElem
->next
= slElem
->AuthRecs
;
2618 slElem
->AuthRecs
= arElem
;
2622 ptr
= slElem
->AuthRecs
;
2626 if (SameDomainName(&ptr
->ar
.resrec
.rdata
->u
.name
, &answer
->rdata
->u
.name
))
2628 debugf("Deregistering PTR %##s -> %##s", ptr
->ar
.resrec
.name
->c
, ptr
->ar
.resrec
.rdata
->u
.name
.c
);
2630 if (prev
) prev
->next
= ptr
->next
;
2631 else slElem
->AuthRecs
= ptr
->next
;
2633 err
= mDNS_Deregister(m
, dereg
);
2634 if (err
) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err
);
2645 mDNSlocal
void MarkSearchListElem(const char *d
)
2647 SearchListElem
*new, *ptr
;
2650 if (!MakeDomainNameFromDNSNameString(&domain
, d
))
2651 { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d
); return; }
2653 if (SameDomainName(&domain
, &localdomain
) || SameDomainName(&domain
, &LocalReverseMapomain
))
2654 { debugf("MarkSearchListElem - ignoring local domain %##s", domain
.c
); return; }
2656 // if domain is in list, mark as pre-existent (0)
2657 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
)
2658 if (SameDomainName(&ptr
->domain
, &domain
))
2660 if (ptr
->flag
!= 1) ptr
->flag
= 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
2664 // if domain not in list, add to list, mark as add (1)
2667 new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem
));
2668 if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
2669 bzero(new, sizeof(SearchListElem
));
2670 AssignDomainName(&new->domain
, &domain
);
2671 new->flag
= 1; // add
2672 new->next
= SearchList
;
2677 // Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
2678 mDNSlocal mStatus
GetSearchDomains(void)
2681 mStatus err
= GetDNSConfig(&v
);
2683 #if !MDNS_NO_DNSINFO
2687 dns_config_t
*config
= v
;
2688 if (!config
->n_resolver
) return err
;
2689 dns_resolver_t
*resolv
= config
->resolver
[0]; // use the first slot for search domains
2691 for (i
= 0; i
< resolv
->n_search
; i
++) MarkSearchListElem(resolv
->search
[i
]);
2692 if (resolv
->domain
) MarkSearchListElem(resolv
->domain
);
2693 dns_configuration_free(config
);
2700 // Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
2701 mDNSlocal
void GetDSSearchDomains(CFDictionaryRef dict
)
2703 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2708 // get all the domains from "Search Domains" field of sharing prefs
2711 CFArrayRef searchdomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
2714 count
= CFArrayGetCount(searchdomains
);
2715 for (i
= 0; i
< count
; i
++)
2717 s
= CFArrayGetValueAtIndex(searchdomains
, i
);
2718 if (!s
) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
2719 if (!CFStringGetCString(s
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2721 LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2724 MarkSearchListElem(buf
);
2728 // get DHCP domain field
2729 CFStringRef dname
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
2732 if (CFStringGetCString(dname
, buf
, MAX_ESCAPED_DOMAIN_NAME
, kCFStringEncodingUTF8
))
2733 MarkSearchListElem(buf
);
2734 else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
2739 mDNSlocal mStatus
RegisterSearchDomains(mDNS
*const m
, CFDictionaryRef dict
)
2741 struct ifaddrs
*ifa
= NULL
;
2742 SearchListElem
*ptr
, *prev
, *freeSLPtr
;
2746 if (DomainDiscoveryDisabled
) return mStatus_NoError
;
2748 // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
2749 for (ptr
= SearchList
; ptr
; ptr
= ptr
->next
) ptr
->flag
= dict
? -1 : 0;
2751 // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
2752 if (GetSearchDomains() == mStatus_UnsupportedErr
) GetDSSearchDomains(dict
);
2754 // Construct reverse-map search domains
2755 ifa
= myGetIfAddrs(1);
2759 if (ifa
->ifa_addr
->sa_family
== AF_INET
&& !SetupAddr(&addr
, ifa
->ifa_addr
) && !IsPrivateV4Addr(&addr
) && !(ifa
->ifa_flags
& IFF_LOOPBACK
) && ifa
->ifa_netmask
)
2763 if (!SetupAddr(&netmask
, ifa
->ifa_netmask
))
2765 sprintf(buffer
, "%d.%d.%d.%d.in-addr.arpa.", addr
.ip
.v4
.b
[3] & netmask
.ip
.v4
.b
[3],
2766 addr
.ip
.v4
.b
[2] & netmask
.ip
.v4
.b
[2],
2767 addr
.ip
.v4
.b
[1] & netmask
.ip
.v4
.b
[1],
2768 addr
.ip
.v4
.b
[0] & netmask
.ip
.v4
.b
[0]);
2769 MarkSearchListElem(buffer
);
2772 ifa
= ifa
->ifa_next
;
2775 // delete elems marked for removal, do queries for elems marked add
2780 if (ptr
->flag
== -1) // remove
2782 mDNS_StopQuery(m
, &ptr
->BrowseQ
);
2783 mDNS_StopQuery(m
, &ptr
->RegisterQ
);
2784 mDNS_StopQuery(m
, &ptr
->DefBrowseQ
);
2785 mDNS_StopQuery(m
, &ptr
->DefRegisterQ
);
2786 mDNS_StopQuery(m
, &ptr
->LegacyBrowseQ
);
2788 // deregister records generated from answers to the query
2789 arList
= ptr
->AuthRecs
;
2790 ptr
->AuthRecs
= NULL
;
2793 AuthRecord
*dereg
= &arList
->ar
;
2794 arList
= arList
->next
;
2795 debugf("Deregistering PTR %##s -> %##s", dereg
->resrec
.name
->c
, dereg
->resrec
.rdata
->u
.name
.c
);
2796 err
= mDNS_Deregister(m
, dereg
);
2797 if (err
) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err
);
2800 // remove elem from list, delete
2801 if (prev
) prev
->next
= ptr
->next
;
2802 else SearchList
= ptr
->next
;
2805 freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr
);
2809 if (ptr
->flag
== 1) // add
2811 mStatus err1
, err2
, err3
, err4
, err5
;
2812 err1
= mDNS_GetDomains(m
, &ptr
->BrowseQ
, mDNS_DomainTypeBrowse
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2813 err2
= mDNS_GetDomains(m
, &ptr
->DefBrowseQ
, mDNS_DomainTypeBrowseDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2814 err3
= mDNS_GetDomains(m
, &ptr
->RegisterQ
, mDNS_DomainTypeRegistration
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2815 err4
= mDNS_GetDomains(m
, &ptr
->DefRegisterQ
, mDNS_DomainTypeRegistrationDefault
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2816 err5
= mDNS_GetDomains(m
, &ptr
->LegacyBrowseQ
, mDNS_DomainTypeBrowseLegacy
, &ptr
->domain
, mDNSInterface_Any
, FoundDomain
, ptr
);
2817 if (err1
|| err2
|| err3
|| err4
|| err5
)
2818 LogMsg("GetDomains for domain %##s returned error(s):\n"
2819 "%d (mDNS_DomainTypeBrowse)\n"
2820 "%d (mDNS_DomainTypeBrowseDefault)\n"
2821 "%d (mDNS_DomainTypeRegistration)\n"
2822 "%d (mDNS_DomainTypeRegistrationDefault)"
2823 "%d (mDNS_DomainTypeBrowseLegacy)\n",
2824 ptr
->domain
.c
, err1
, err2
, err3
, err4
, err5
);
2828 if (ptr
->flag
) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr
->flag
); }
2834 return mStatus_NoError
;
2837 //!!!KRS here is where we will give success/failure notification to the UI
2838 mDNSlocal
void SCPrefsDynDNSCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2841 debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result
, rr
->resrec
.name
->c
);
2842 SetDDNSNameStatus(rr
->resrec
.name
, result
);
2845 mDNSlocal
void SetSecretForDomain(mDNS
*m
, const domainname
*domain
)
2848 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
2850 void *secret
= NULL
;
2851 domainname
*d
, canon
;
2853 mDNSu32 type
= 'ddns';
2854 mDNSu32 typelen
= sizeof(type
);
2855 char *failedfn
= "(none)";
2856 SecKeychainAttributeList
*attrList
= NULL
;
2857 SecKeychainItemRef itemRef
= NULL
;
2859 err
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
2860 if (err
) { failedfn
= "SecKeychainSetPreferenceDomain"; goto cleanup
; }
2862 // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
2863 ConvertDomainNameToCString(domain
, dstring
);
2864 dlen
= strlen(dstring
);
2865 for (i
= 0; i
< dlen
; i
++) dstring
[i
] = tolower(dstring
[i
]); // canonicalize -> lower case
2866 MakeDomainNameFromDNSNameString(&canon
, dstring
);
2869 // find longest-match key, excluding last label (e.g. excluding ".com")
2870 while (d
->c
[0] && *(d
->c
+ d
->c
[0] + 1))
2872 if (!ConvertDomainNameToCString(d
, dstring
)) { LogMsg("SetSecretForDomain: bad domain %##s", d
->c
); return; }
2873 dlen
= strlen(dstring
);
2874 if (dstring
[dlen
-1] == '.') { dstring
[dlen
-1] = '\0'; dlen
--; } // chop trailing dot
2875 SecKeychainAttribute attrs
[] = { { kSecServiceItemAttr
, strlen(dstring
), dstring
},
2876 { kSecTypeItemAttr
, typelen
, (UInt32
*)&type
} };
2877 SecKeychainAttributeList attributes
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs
};
2878 SecKeychainSearchRef searchRef
;
2880 err
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attributes
, &searchRef
);
2881 if (err
) { failedfn
= "SecKeychainSearchCreateFromAttributes"; goto cleanup
; }
2883 err
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
2887 SecKeychainAttributeInfo attrInfo
;
2889 char keybuf
[MAX_ESCAPED_DOMAIN_NAME
+1];
2892 tags
[0] = kSecAccountItemAttr
;
2894 attrInfo
.tag
= tags
;
2895 attrInfo
.format
= NULL
;
2897 err
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrList
, &secretlen
, &secret
);
2898 if (err
|| !attrList
) { failedfn
= "SecKeychainItemCopyAttributesAndData"; goto cleanup
; }
2899 if (!secretlen
|| !secret
) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
2900 if (((char *)secret
)[secretlen
-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup
; }
2902 for (i
= 0; i
< attrList
->count
; i
++)
2904 SecKeychainAttribute attr
= attrList
->attr
[i
];
2905 if (attr
.tag
== kSecAccountItemAttr
)
2907 if (!attr
.length
|| attr
.length
> MAX_ESCAPED_DOMAIN_NAME
) { LogMsg("SetSecretForDomain - Bad key length %d", attr
.length
); goto cleanup
; }
2908 strncpy(keybuf
, attr
.data
, attr
.length
);
2909 if (!MakeDomainNameFromDNSNameString(&keyname
, keybuf
)) { LogMsg("SetSecretForDomain - bad key %s", keybuf
); goto cleanup
; }
2910 debugf("Setting shared secret for zone %s with key %##s", dstring
, keyname
.c
);
2911 mDNS_SetSecretForZone(m
, d
, &keyname
, secret
);
2915 if (i
== attrList
->count
) LogMsg("SetSecretForDomain - no key name set");
2918 else if (err
== errSecItemNotFound
) d
= (domainname
*)(d
->c
+ d
->c
[0] + 1);
2919 else { failedfn
= "SecKeychainSearchCopyNext"; goto cleanup
; }
2923 if (err
&& err
!= errSecItemNotFound
) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn
, err
);
2924 if (attrList
) SecKeychainItemFreeAttributesAndData(attrList
, secret
);
2925 if (itemRef
) CFRelease(itemRef
);
2928 mDNSlocal
void SetSCPrefsBrowseDomainsFromCFArray(mDNS
*m
, CFArrayRef browseDomains
, mDNSBool add
)
2932 CFIndex count
= CFArrayGetCount(browseDomains
);
2933 CFDictionaryRef browseDict
;
2934 char buf
[MAX_ESCAPED_DOMAIN_NAME
];
2937 for (i
= 0; i
< count
; i
++)
2939 browseDict
= (CFDictionaryRef
)CFArrayGetValueAtIndex(browseDomains
, i
);
2940 if (browseDict
&& DDNSSettingEnabled(browseDict
))
2942 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
2945 domainname BrowseDomain
;
2946 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) || !MakeDomainNameFromDNSNameString(&BrowseDomain
, buf
) || !BrowseDomain
.c
[0])
2947 LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf
[0] ? buf
: "(unknown)");
2948 else SetSCPrefsBrowseDomain(m
, &BrowseDomain
, add
);
2956 mDNSlocal
void DynDNSConfigChanged(mDNS
*const m
)
2958 static mDNSBool LegacyNATInitialized
= mDNSfalse
;
2959 uDNS_GlobalInfo
*u
= &m
->uDNS_info
;
2960 CFDictionaryRef dict
;
2962 domainname RegDomain
, fqdn
;
2963 CFArrayRef NewBrowseDomains
= NULL
;
2964 int nAdditions
= 0, nDeletions
= 0;
2966 // get fqdn, zone from SCPrefs
2967 GetUserSpecifiedDDNSConfig(&fqdn
, &RegDomain
, &NewBrowseDomains
);
2968 ReadDDNSSettingsFromConfFile(m
, CONFIG_FILE
, fqdn
.c
[0] ? NULL
: &fqdn
, RegDomain
.c
[0] ? NULL
: &RegDomain
, &DomainDiscoveryDisabled
);
2970 if (!SameDomainName(&RegDomain
, &DynDNSRegDomain
))
2972 if (DynDNSRegDomain
.c
[0])
2974 RemoveDefRegDomain(&DynDNSRegDomain
);
2975 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNSfalse
); // if we were automatically browsing in our registration domain, stop
2977 AssignDomainName(&DynDNSRegDomain
, &RegDomain
);
2978 if (DynDNSRegDomain
.c
[0])
2980 SetSecretForDomain(m
, &DynDNSRegDomain
);
2981 AddDefRegDomain(&DynDNSRegDomain
);
2982 SetSCPrefsBrowseDomain(m
, &DynDNSRegDomain
, mDNStrue
);
2986 // Add new browse domains to internal list
2987 if (NewBrowseDomains
) SetSCPrefsBrowseDomainsFromCFArray(m
, NewBrowseDomains
, mDNStrue
);
2989 // Remove old browse domains from internal list
2990 if (DynDNSBrowseDomains
)
2992 SetSCPrefsBrowseDomainsFromCFArray(m
, DynDNSBrowseDomains
, mDNSfalse
);
2993 CFRelease(DynDNSBrowseDomains
);
2996 // Replace the old browse domains array with the new array
2997 DynDNSBrowseDomains
= NewBrowseDomains
;
2999 if (!SameDomainName(&fqdn
, &DynDNSHostname
))
3001 if (DynDNSHostname
.c
[0]) mDNS_RemoveDynDNSHostName(m
, &DynDNSHostname
);
3002 AssignDomainName(&DynDNSHostname
, &fqdn
);
3003 if (DynDNSHostname
.c
[0])
3005 SetSecretForDomain(m
, &fqdn
); // no-op if "zone" secret, above, is to be used for hostname
3006 SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate "in progress"
3007 mDNS_AddDynDNSHostName(m
, &DynDNSHostname
, SCPrefsDynDNSCallback
, NULL
);
3012 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL
, NULL
);
3015 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3016 if (!key
) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3017 dict
= SCDynamicStoreCopyValue(store
, key
);
3020 // handle any changes to search domains and DNS server addresses
3021 if (RegisterSplitDNS(m
, &nAdditions
, &nDeletions
) != mStatus_NoError
)
3022 if (dict
) RegisterNameServers(m
, dict
); // fall back to non-split DNS aware configuration on failure
3023 RegisterSearchDomains(m
, dict
); // note that we register name servers *before* search domains
3024 if (dict
) CFRelease(dict
);
3026 // get IPv4 settings
3027 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
,kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3028 if (!key
) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store
); return; }
3029 dict
= SCDynamicStoreCopyValue(store
, key
);
3032 if (!dict
) // lost v4
3034 mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3035 if (DynDNSHostname
.c
[0]) SetDDNSNameStatus(&DynDNSHostname
, 1); // Set status to 1 to indicate temporary failure
3039 // handle router changes
3042 r
.type
= mDNSAddrType_IPv4
;
3043 r
.ip
.v4
.NotAnInteger
= 0;
3044 CFStringRef router
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3047 struct sockaddr_in saddr
;
3049 if (!CFStringGetCString(router
, buf
, 256, kCFStringEncodingUTF8
))
3050 LogMsg("Could not convert router to CString");
3053 saddr
.sin_len
= sizeof(saddr
);
3054 saddr
.sin_family
= AF_INET
;
3056 inet_aton(buf
, &saddr
.sin_addr
);
3057 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) { debugf("Ignoring router %s (requires PPP connection)", buf
); }
3058 else *(in_addr_t
*)&r
.ip
.v4
= saddr
.sin_addr
.s_addr
;
3062 // handle primary interface changes
3063 // 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
3064 if (nAdditions
|| nDeletions
) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3065 CFStringRef primary
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3068 mDNSAddr v4
= zeroAddr
, v6
= zeroAddr
;
3069 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3070 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3072 if (!CFStringGetCString(primary
, buf
, 256, kCFStringEncodingUTF8
))
3073 { LogMsg("Could not convert router to CString"); goto error
; }
3075 // find primary interface in list
3076 while (ifa
&& (!v4
.ip
.v4
.NotAnInteger
|| !HavePrimaryGlobalv6
))
3078 mDNSAddr tmp6
= zeroAddr
;
3079 if (!strcmp(buf
, ifa
->ifa_name
))
3081 if (ifa
->ifa_addr
->sa_family
== AF_INET
) SetupAddr(&v4
, ifa
->ifa_addr
);
3082 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3084 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3085 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3086 { HavePrimaryGlobalv6
= mDNStrue
; v6
= tmp6
; }
3091 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3092 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
.ip
.v6
.b
[0])
3094 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3095 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) v6
= tmp6
;
3098 ifa
= ifa
->ifa_next
;
3101 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3102 // V4 to communicate w/ our DNS server
3104 if (v4
.ip
.v4
.b
[0] == 169 && v4
.ip
.v4
.b
[1] == 254) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
); // primary IP is link-local
3107 if (v4
.ip
.v4
.NotAnInteger
!= u
->AdvertisedV4
.ip
.v4
.NotAnInteger
||
3108 memcmp(v6
.ip
.v6
.b
, u
->AdvertisedV6
.ip
.v6
.b
, 16) ||
3109 r
.ip
.v4
.NotAnInteger
!= u
->Router
.ip
.v4
.NotAnInteger
)
3111 if (LegacyNATInitialized
) { LegacyNATDestroy(); LegacyNATInitialized
= mDNSfalse
; }
3112 if (r
.ip
.v4
.NotAnInteger
&& IsPrivateV4Addr(&v4
))
3114 mStatus err
= LegacyNATInit();
3115 if (err
) LogMsg("ERROR: LegacyNATInit");
3116 else LegacyNATInitialized
= mDNStrue
;
3118 mDNS_SetPrimaryInterfaceInfo(m
, &v4
, v6
.ip
.v6
.b
[0] ? &v6
: NULL
, r
.ip
.v4
.NotAnInteger
? &r
: NULL
);
3126 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3128 LogOperation("*** Network Configuration Change ***");
3129 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3130 mDNSs32 utc
= mDNSPlatformUTC();
3131 MarkAllInterfacesInactive(m
, utc
);
3132 UpdateInterfaceList(m
, utc
);
3133 int nDeletions
= ClearInactiveInterfaces(m
, utc
);
3134 int nAdditions
= SetupActiveInterfaces(m
, utc
);
3135 DynDNSConfigChanged(m
); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
3136 if (nDeletions
|| nAdditions
) mDNS_UpdateLLQs(m
); // so that LLQs are restarted against the up to date name servers
3138 if (m
->MainCallback
)
3139 m
->MainCallback(m
, mStatus_ConfigChanged
);
3142 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3144 (void)store
; // Parameter not used
3145 (void)changedKeys
; // Parameter not used
3146 mDNS
*const m
= (mDNS
*const)context
;
3149 mDNSs32 delay
= mDNSPlatformOneSecond
* 2; // Start off assuming a two-second delay
3151 int c
= CFArrayGetCount(changedKeys
); // Count changes
3152 CFRange range
= { 0, c
};
3153 CFStringRef k1
= SCDynamicStoreKeyCreateComputerName(NULL
);
3154 CFStringRef k2
= SCDynamicStoreKeyCreateHostNames(NULL
);
3157 int c1
= (CFArrayContainsValue(changedKeys
, range
, k1
) != 0); // See if ComputerName changed
3158 int c2
= (CFArrayContainsValue(changedKeys
, range
, k2
) != 0); // See if Local Hostname changed
3159 int c3
= (CFArrayContainsValue(changedKeys
, range
, CFSTR("Setup:/Network/DynamicDNS")) != 0);
3160 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/10; // If these were the only changes, shorten delay
3162 if (k1
) CFRelease(k1
);
3163 if (k2
) CFRelease(k2
);
3165 LogOperation("*** NetworkChanged *** %d change%s, delay %d", c
, c
>1?"s":"", delay
);
3167 if (!m
->p
->NetworkChanged
||
3168 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3169 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3171 if (!m
->SuppressSending
||
3172 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3173 m
->SuppressSending
= m
->p
->NetworkChanged
;
3177 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3180 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3181 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3182 CFStringRef key1
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3183 CFStringRef key2
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
3184 CFStringRef key3
= SCDynamicStoreKeyCreateComputerName(NULL
);
3185 CFStringRef key4
= SCDynamicStoreKeyCreateHostNames(NULL
);
3186 CFStringRef key5
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3187 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3188 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3190 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3191 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3193 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3194 if (!key1
|| !key2
|| !key3
|| !key4
|| !keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3196 CFArrayAppendValue(keys
, key1
);
3197 CFArrayAppendValue(keys
, key2
);
3198 CFArrayAppendValue(keys
, key3
);
3199 CFArrayAppendValue(keys
, key4
);
3200 CFArrayAppendValue(keys
, key5
);
3201 CFArrayAppendValue(keys
, CFSTR("Setup:/Network/DynamicDNS"));
3202 CFArrayAppendValue(patterns
, pattern1
);
3203 CFArrayAppendValue(patterns
, pattern2
);
3204 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3205 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3206 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3208 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3209 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3211 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3212 m
->p
->Store
= store
;
3217 if (store
) CFRelease(store
);
3220 if (key1
) CFRelease(key1
);
3221 if (key2
) CFRelease(key2
);
3222 if (key3
) CFRelease(key3
);
3223 if (key4
) CFRelease(key4
);
3224 if (key5
) CFRelease(key5
);
3225 if (pattern1
) CFRelease(pattern1
);
3226 if (pattern2
) CFRelease(pattern2
);
3227 if (keys
) CFRelease(keys
);
3228 if (patterns
) CFRelease(patterns
);
3233 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3235 mDNS
*const m
= (mDNS
*const)refcon
;
3236 (void)service
; // Parameter not used
3239 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3240 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3241 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3242 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3243 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3244 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3245 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3246 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3247 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3248 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3249 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3250 // Just to be safe, also make sure our interface list is fully up to date, in case we
3251 // haven't yet received the System Configuration Framework "network changed" event that
3252 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3253 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3254 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3255 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3256 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3257 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3258 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3260 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3263 mDNSlocal mStatus
WatchForPowerChanges(mDNS
*const m
)
3265 IONotificationPortRef thePortRef
;
3266 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &thePortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
3267 if (m
->p
->PowerConnection
)
3269 m
->p
->PowerRLS
= IONotificationPortGetRunLoopSource(thePortRef
);
3270 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3271 return(mStatus_NoError
);
3276 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3277 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3278 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3279 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3281 // Major version 6 is 10.2.x (Jaguar)
3282 // Major version 7 is 10.3.x (Panther)
3283 // Major version 8 is 10.4.x (Tiger)
3284 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3286 int major
= 0, minor
= 0;
3287 char letter
= 0, prodname
[256]="Mac OS X", prodvers
[256]="", buildver
[256]="?";
3288 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3291 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3292 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3293 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3294 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3295 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3296 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3297 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3300 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3304 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3305 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3306 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3307 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3310 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3312 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3315 struct sockaddr_in s5353
;
3316 s5353
.sin_family
= AF_INET
;
3317 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3318 s5353
.sin_addr
.s_addr
= 0;
3319 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3323 if (err
) LogMsg("No unicast UDP responses");
3324 else debugf("Unicast UDP responses okay");
3328 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
3329 mDNSlocal
void FoundLegacyBrowseDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
3331 DNameListElem
*ptr
, *prev
, *new;
3333 (void)question
; // unused
3335 LogMsg("%s browse domain %##s", AddRecord
? "Adding" : "Removing", answer
->rdata
->u
.name
.c
);
3339 new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem
));
3340 if (!new) { LogMsg("ERROR: malloc"); return; }
3341 AssignDomainName(&new->name
, &answer
->rdata
->u
.name
);
3342 new->next
= DefBrowseList
;
3343 DefBrowseList
= new;
3344 DefaultBrowseDomainChanged(&new->name
, mDNStrue
);
3345 udsserver_default_browse_domain_changed(&new->name
, mDNStrue
);
3350 ptr
= DefBrowseList
;
3354 if (SameDomainName(&ptr
->name
, &answer
->rdata
->u
.name
))
3356 DefaultBrowseDomainChanged(&ptr
->name
, mDNSfalse
);
3357 udsserver_default_browse_domain_changed(&ptr
->name
, mDNSfalse
);
3358 if (prev
) prev
->next
= ptr
->next
;
3359 else DefBrowseList
= ptr
->next
;
3360 freeL("FoundLegacyBrowseDomain", ptr
);
3366 LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer
->rdata
->u
.name
.c
);
3370 mDNSlocal
void RegisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3372 // allocate/register legacy and non-legacy _browse PTR record
3373 ARListElem
*browse
= mallocL("ARListElem", sizeof(*browse
));
3374 mDNS_SetupResourceRecord(&browse
->ar
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, FreeARElemCallback
, browse
);
3375 MakeDomainNameFromDNSNameString(browse
->ar
.resrec
.name
, mDNS_DomainTypeNames
[type
]);
3376 AppendDNSNameString (browse
->ar
.resrec
.name
, "local");
3377 AssignDomainName(&browse
->ar
.resrec
.rdata
->u
.name
, d
);
3378 mStatus err
= mDNS_Register(m
, &browse
->ar
);
3381 LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err
);
3382 freeL("ARListElem", browse
);
3386 browse
->next
= SCPrefBrowseDomains
;
3387 SCPrefBrowseDomains
= browse
;
3391 mDNSlocal
void DeregisterBrowseDomainPTR(mDNS
*m
, const domainname
*d
, int type
)
3393 ARListElem
*remove
, **ptr
= &SCPrefBrowseDomains
;
3394 domainname lhs
; // left-hand side of PTR, for comparison
3396 MakeDomainNameFromDNSNameString(&lhs
, mDNS_DomainTypeNames
[type
]);
3397 AppendDNSNameString (&lhs
, "local");
3401 if (SameDomainName(&(*ptr
)->ar
.resrec
.rdata
->u
.name
, d
) && SameDomainName((*ptr
)->ar
.resrec
.name
, &lhs
))
3404 *ptr
= (*ptr
)->next
;
3405 mDNS_Deregister(m
, &remove
->ar
);
3408 else ptr
= &(*ptr
)->next
;
3412 // Add or remove a user-specified domain to the list of empty-string browse domains
3413 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
3414 mDNSlocal
void SetSCPrefsBrowseDomain(mDNS
*m
, const domainname
*d
, mDNSBool add
)
3416 debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add
? "Adding" : "Removing", d
->c
);
3420 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3421 RegisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3425 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowse
);
3426 DeregisterBrowseDomainPTR(m
, d
, mDNS_DomainTypeBrowseLegacy
);
3430 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3431 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3432 // (.local manually generated via explicit callback)
3433 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3434 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3435 // 4) result above should generate a callback from question in (1). result added to global list
3436 // 5) global list delivered to client via GetSearchDomainList()
3437 // 6) client calls to enumerate domains now go over LocalOnly interface
3438 // (!!!KRS may add outgoing interface in addition)
3440 mDNSlocal mStatus
InitDNSConfig(mDNS
*const m
)
3443 static AuthRecord LocalRegPTR
;
3445 // start query for domains to be used in default (empty string domain) browses
3446 err
= mDNS_GetDomains(m
, &LegacyBrowseDomainQ
, mDNS_DomainTypeBrowseLegacy
, NULL
, mDNSInterface_LocalOnly
, FoundLegacyBrowseDomain
, NULL
);
3448 // provide browse domain "local" automatically
3449 SetSCPrefsBrowseDomain(m
, &localdomain
, mDNStrue
);
3451 // register registration domain "local"
3452 mDNS_SetupResourceRecord(&LocalRegPTR
, mDNSNULL
, mDNSInterface_LocalOnly
, kDNSType_PTR
, 7200, kDNSRecordTypeShared
, NULL
, NULL
);
3453 MakeDomainNameFromDNSNameString(LocalRegPTR
.resrec
.name
, mDNS_DomainTypeNames
[mDNS_DomainTypeRegistration
]);
3454 AppendDNSNameString (LocalRegPTR
.resrec
.name
, "local");
3455 AssignDomainName(&LocalRegPTR
.resrec
.rdata
->u
.name
, &localdomain
);
3456 err
= mDNS_Register(m
, &LocalRegPTR
);
3457 if (err
) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err
);
3459 return mStatus_NoError
;
3462 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3464 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3465 // 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.
3467 for (i
=0; i
<100; i
++)
3469 domainlabel testlabel
;
3471 GetUserSpecifiedLocalHostName(&testlabel
);
3472 if (testlabel
.c
[0]) break;
3478 m
->hostlabel
.c
[0] = 0;
3480 char *HINFO_HWstring
= "Macintosh";
3481 char HINFO_HWstring_buffer
[256];
3482 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3483 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3484 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3485 HINFO_HWstring
= HINFO_HWstring_buffer
;
3487 char HINFO_SWstring
[256] = "";
3488 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3489 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3491 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3492 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3493 if (hlen
+ slen
< 254)
3495 m
->HIHardware
.c
[0] = hlen
;
3496 m
->HISoftware
.c
[0] = slen
;
3497 mDNSPlatformMemCopy(HINFO_HWstring
, &m
->HIHardware
.c
[1], hlen
);
3498 mDNSPlatformMemCopy(HINFO_SWstring
, &m
->HISoftware
.c
[1], slen
);
3501 m
->p
->unicastsockets
.m
= m
;
3502 m
->p
->unicastsockets
.info
= NULL
;
3503 m
->p
->unicastsockets
.sktv4
= m
->p
->unicastsockets
.sktv6
= -1;
3504 m
->p
->unicastsockets
.cfsv4
= m
->p
->unicastsockets
.cfsv6
= NULL
;
3505 m
->p
->unicastsockets
.rlsv4
= m
->p
->unicastsockets
.rlsv6
= NULL
;
3507 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET
);
3508 err
= SetupSocket(m
, &m
->p
->unicastsockets
, mDNSfalse
, &zeroAddr
, AF_INET6
);
3510 struct sockaddr_in s4
;
3511 struct sockaddr_in6 s6
;
3512 socklen_t n4
= sizeof(s4
);
3513 socklen_t n6
= sizeof(s6
);
3514 if (getsockname(m
->p
->unicastsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
3515 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
3516 if (getsockname(m
->p
->unicastsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
3517 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
3519 m
->p
->InterfaceList
= mDNSNULL
;
3520 m
->p
->userhostlabel
.c
[0] = 0;
3521 m
->p
->usernicelabel
.c
[0] = 0;
3522 m
->p
->NotifyUser
= 0;
3523 mDNSs32 utc
= mDNSPlatformUTC();
3524 UpdateInterfaceList(m
, utc
);
3525 SetupActiveInterfaces(m
, utc
);
3527 err
= WatchForNetworkChanges(m
);
3528 if (err
) return(err
);
3530 err
= WatchForPowerChanges(m
);
3531 if (err
) return err
;
3533 DynDNSRegDomain
.c
[0] = '\0';
3534 DynDNSConfigChanged(m
); // Get initial DNS configuration
3540 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
3542 mStatus result
= mDNSPlatformInit_setup(m
);
3544 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3545 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3546 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
3550 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
3552 if (m
->p
->PowerConnection
)
3554 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->PowerRLS
, kCFRunLoopDefaultMode
);
3555 CFRunLoopSourceInvalidate(m
->p
->PowerRLS
);
3556 CFRelease(m
->p
->PowerRLS
);
3557 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
3558 m
->p
->PowerConnection
= 0;
3559 m
->p
->PowerNotifier
= 0;
3560 m
->p
->PowerRLS
= NULL
;
3565 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3566 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
3567 CFRelease(m
->p
->StoreRLS
);
3568 CFRelease(m
->p
->Store
);
3570 m
->p
->StoreRLS
= NULL
;
3573 mDNSs32 utc
= mDNSPlatformUTC();
3574 MarkAllInterfacesInactive(m
, utc
);
3575 ClearInactiveInterfaces(m
, utc
);
3576 CloseSocketSet(&m
->p
->unicastsockets
);
3579 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
3581 return(mach_absolute_time());
3584 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
3586 mDNSexport mStatus
mDNSPlatformTimeInit(void)
3588 // Notes: Typical values for mach_timebase_info:
3589 // tbi.numer = 1000 million
3590 // tbi.denom = 33 million
3591 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3592 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3593 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3594 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3595 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3597 // Arithmetic notes:
3598 // tbi.denom is at least 1, and not more than 2^32-1.
3599 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3600 // tbi.denom is at least 1, and not more than 2^32-1.
3601 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3602 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3603 // which is unlikely on any current or future Macintosh.
3604 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3605 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3606 struct mach_timebase_info tbi
;
3607 kern_return_t result
= mach_timebase_info(&tbi
);
3608 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
3612 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
3614 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3616 static uint64_t last_mach_absolute_time
= 0;
3617 uint64_t this_mach_absolute_time
= mach_absolute_time();
3618 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
3620 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
3621 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
3622 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3623 last_mach_absolute_time
= this_mach_absolute_time
;
3624 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later
3625 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
3626 NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
3628 last_mach_absolute_time
= this_mach_absolute_time
;
3630 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
3633 mDNSexport mDNSs32
mDNSPlatformUTC(void)
3638 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
3639 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
3640 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
3641 mDNSexport
void mDNSPlatformStrCopy(const void *src
, void *dst
) { strcpy((char *)dst
, (char *)src
); }
3642 mDNSexport mDNSu32
mDNSPlatformStrLen (const void *src
) { return(strlen((char*)src
)); }
3643 mDNSexport
void mDNSPlatformMemCopy(const void *src
, void *dst
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
3644 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *src
, const void *dst
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
3645 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
3646 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
3647 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }