1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: mDNSMacOSX.c,v $
20 Revision 1.521 2007/12/14 00:58:28 cheshire
21 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
22 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
23 until TLS/TCP deregistrations have completed (up to five seconds maximum)
25 Revision 1.520 2007/12/10 23:01:01 cheshire
26 Remove some unnecessary log messages
28 Revision 1.519 2007/12/06 00:22:27 mcguire
29 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
31 Revision 1.518 2007/12/05 01:52:30 cheshire
32 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
33 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
35 Revision 1.517 2007/12/03 18:37:26 cheshire
36 Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
37 from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
39 Revision 1.516 2007/12/01 01:21:27 jgraessley
40 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
42 Revision 1.515 2007/12/01 00:40:00 cheshire
43 Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
45 Revision 1.514 2007/12/01 00:38:32 cheshire
46 Fixed compile warning: declaration of 'index' shadows a global declaration
48 Revision 1.513 2007/11/27 00:08:49 jgraessley
49 <rdar://problem/5613538> Interface-specific resolvers not setup correctly
51 Revision 1.512 2007/11/16 22:09:26 cheshire
52 Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
54 Revision 1.511 2007/11/14 23:06:13 cheshire
55 <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
57 Revision 1.510 2007/11/14 22:29:19 cheshire
58 Updated comments and debugging log messages
60 Revision 1.509 2007/11/14 01:07:53 cheshire
63 Revision 1.508 2007/11/02 21:59:37 cheshire
64 Added comment about locking
66 Revision 1.507 2007/11/02 20:18:13 cheshire
67 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
69 Revision 1.506 2007/10/30 20:46:45 cheshire
70 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
72 Revision 1.505 2007/10/29 23:55:10 cheshire
73 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
74 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
75 (and indeed should not, since the result fields will not yet be set up correctly in this case)
77 Revision 1.504 2007/10/26 00:50:37 cheshire
78 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
80 Revision 1.503 2007/10/25 23:11:42 cheshire
81 Ignore IPv6 ULA addresses configured on lo0 loopback interface
83 Revision 1.502 2007/10/22 20:07:07 cheshire
84 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
85 Posix build can share the code (better than just pasting it into mDNSPosix.c)
87 Revision 1.501 2007/10/22 19:40:30 cheshire
88 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
89 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
91 Revision 1.500 2007/10/17 22:49:55 cheshire
92 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
94 Revision 1.499 2007/10/17 19:47:54 cheshire
95 Improved debugging messages
97 Revision 1.498 2007/10/17 18:42:06 cheshire
98 Export SetDomainSecrets so its callable from other files
100 Revision 1.497 2007/10/16 17:03:07 cheshire
101 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
102 Cut SetDomainSecrets stack from 3792 to 1760 bytes
104 Revision 1.496 2007/10/04 20:33:05 mcguire
105 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
107 Revision 1.495 2007/10/02 05:03:38 cheshire
108 Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
110 Revision 1.494 2007/09/29 20:40:19 cheshire
111 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
113 Revision 1.493 2007/09/29 03:16:45 cheshire
114 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
115 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
117 Revision 1.492 2007/09/28 23:58:35 mcguire
118 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
121 Revision 1.491 2007/09/27 23:28:53 mcguire
122 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
124 Revision 1.490 2007/09/26 23:01:21 mcguire
125 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
127 Revision 1.489 2007/09/26 22:58:16 mcguire
128 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
130 Revision 1.488 2007/09/26 00:32:45 cheshire
131 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
133 Revision 1.487 2007/09/21 17:07:41 mcguire
134 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
136 Revision 1.486 2007/09/19 23:17:38 cheshire
137 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
139 Revision 1.485 2007/09/19 21:44:29 cheshire
140 Improved "mDNSKeychainGetSecrets failed" error message
142 Revision 1.484 2007/09/18 21:44:55 cheshire
143 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
144 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
146 Revision 1.483 2007/09/17 22:19:39 mcguire
147 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
148 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
150 Revision 1.482 2007/09/14 21:16:03 cheshire
151 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
153 Revision 1.481 2007/09/14 21:14:56 mcguire
154 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
156 Revision 1.480 2007/09/13 00:16:42 cheshire
157 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
159 Revision 1.479 2007/09/12 19:22:20 cheshire
160 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
161 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
163 Revision 1.478 2007/09/07 22:21:45 vazquez
164 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
166 Revision 1.477 2007/09/07 21:22:30 cheshire
167 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
168 Don't log failures binding to port 5351
170 Revision 1.476 2007/09/06 20:38:08 cheshire
171 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
173 Revision 1.475 2007/09/05 02:24:28 cheshire
174 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
175 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
177 Revision 1.474 2007/09/04 22:32:58 mcguire
178 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
180 Revision 1.473 2007/08/31 19:53:15 cheshire
181 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
182 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
184 Revision 1.472 2007/08/31 18:49:49 vazquez
185 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
187 Revision 1.471 2007/08/31 02:05:46 cheshire
188 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
190 Revision 1.470 2007/08/30 22:50:04 mcguire
191 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
193 Revision 1.469 2007/08/30 19:40:51 cheshire
194 Added syslog messages to report various initialization failures
196 Revision 1.468 2007/08/30 00:12:20 cheshire
197 Check error codes and log failures during AutoTunnel setup
199 Revision 1.467 2007/08/28 00:33:04 jgraessley
200 <rdar://problem/5423932> Selective compilation options
202 Revision 1.466 2007/08/24 23:25:55 cheshire
203 Debugging messages to help track down duplicate items being read from system keychain
205 Revision 1.465 2007/08/24 00:39:12 cheshire
206 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
208 Revision 1.464 2007/08/24 00:15:21 cheshire
209 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
211 Revision 1.463 2007/08/23 21:02:35 cheshire
212 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
214 Revision 1.462 2007/08/18 01:02:03 mcguire
215 <rdar://problem/5415593> No Bonjour services are getting registered at boot
217 Revision 1.461 2007/08/10 22:25:57 mkrochma
218 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
220 Revision 1.460 2007/08/08 22:34:59 mcguire
221 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
223 Revision 1.459 2007/08/08 21:07:48 vazquez
224 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
226 Revision 1.458 2007/08/03 02:18:41 mcguire
227 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
229 Revision 1.457 2007/08/02 16:48:45 mcguire
230 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
232 Revision 1.456 2007/08/02 03:28:30 vazquez
233 Make ExternalAddress and err unused to fix build warnings
235 Revision 1.455 2007/08/01 03:09:22 cheshire
236 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
238 Revision 1.454 2007/07/31 23:08:34 mcguire
239 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
241 Revision 1.453 2007/07/31 19:13:58 mkrochma
242 No longer need to include "btmm" in hostname to avoid name conflicts
244 Revision 1.452 2007/07/27 19:30:41 cheshire
245 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
246 to properly reflect tri-state nature of the possible responses
248 Revision 1.451 2007/07/25 22:25:45 cheshire
249 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
251 Revision 1.450 2007/07/25 21:19:10 cheshire
252 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
254 Revision 1.449 2007/07/25 01:36:09 mcguire
255 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
257 Revision 1.448 2007/07/24 21:30:09 cheshire
258 Added "AutoTunnel server listening for connections..." diagnostic message
260 Revision 1.447 2007/07/24 20:24:18 cheshire
261 Only remove AutoTunnel address if we have created it.
262 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
264 Revision 1.446 2007/07/24 03:00:09 cheshire
265 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
267 Revision 1.445 2007/07/23 20:26:26 cheshire
268 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
269 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
270 for existence of "Setup:/Network/DynamicDNS" settings
272 Revision 1.444 2007/07/21 00:54:49 cheshire
273 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
275 Revision 1.443 2007/07/20 23:23:11 cheshire
276 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
278 Revision 1.442 2007/07/20 20:23:24 cheshire
279 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
280 Fixed errors reading the Setup:/Network/BackToMyMac preferences
282 Revision 1.441 2007/07/20 16:46:45 mcguire
283 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
285 Revision 1.440 2007/07/20 16:22:07 mcguire
286 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
288 Revision 1.439 2007/07/20 01:14:56 cheshire
289 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
290 Cleaned up log messages
292 Revision 1.438 2007/07/20 00:54:21 cheshire
293 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
295 Revision 1.437 2007/07/19 22:01:27 cheshire
296 Added "#pragma mark" sections headings to divide code into related function groups
298 Revision 1.436 2007/07/18 03:25:25 cheshire
299 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
300 Bring up server-side tunnel on demand, when necessary
302 Revision 1.435 2007/07/18 01:05:08 cheshire
303 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
304 Add list of client tunnels so we can automatically reconfigure when local address changes
306 Revision 1.434 2007/07/16 20:16:00 vazquez
307 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
308 Remove unnecessary LNT init code
310 Revision 1.433 2007/07/14 00:36:07 cheshire
311 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
313 Revision 1.432 2007/07/12 23:55:11 cheshire
314 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
315 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
317 Revision 1.431 2007/07/12 23:34:48 cheshire
318 Removed 'LogOperation' message to reduce verbosity in syslog
320 Revision 1.430 2007/07/12 22:16:46 cheshire
321 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
323 Revision 1.429 2007/07/12 02:51:28 cheshire
324 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
326 Revision 1.428 2007/07/11 23:17:31 cheshire
327 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
328 Improve log message to indicate if we're starting or restarting racoon
330 Revision 1.427 2007/07/11 22:50:30 cheshire
331 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
332 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
334 Revision 1.426 2007/07/11 20:40:49 cheshire
335 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
336 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
338 Revision 1.425 2007/07/11 19:24:19 cheshire
339 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
340 Configure internal AutoTunnel address
341 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
342 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
344 Revision 1.424 2007/07/11 19:00:27 cheshire
345 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
347 Revision 1.423 2007/07/11 03:00:59 cheshire
348 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
349 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
351 Revision 1.422 2007/07/10 01:21:20 cheshire
352 Added (commented out) line for displaying key data for debugging
354 Revision 1.421 2007/06/25 20:58:11 cheshire
355 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
356 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
358 Revision 1.420 2007/06/22 21:52:14 cheshire
359 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
361 Revision 1.419 2007/06/22 21:32:00 cheshire
362 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
364 Revision 1.418 2007/06/21 16:37:43 jgraessley
366 Reviewed by: Stuart Cheshire
367 Additional changes to get this compiling on the embedded platform.
369 Revision 1.417 2007/06/20 01:44:00 cheshire
370 More information in "Network Configuration Change" message
372 Revision 1.416 2007/06/20 01:10:12 cheshire
373 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
375 Revision 1.415 2007/06/15 19:23:38 cheshire
376 <rdar://problem/5254053> mDNSResponder renames my host without asking
377 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
379 Revision 1.414 2007/05/17 22:00:59 cheshire
380 <rdar://problem/5210966> Lower network change delay from two seconds to one second
382 Revision 1.413 2007/05/16 16:43:27 cheshire
383 Only log "bind" failures for our shared mDNS port and for binding to zero
384 -- other attempts to bind to a particular port may legitimately fail
386 Revision 1.412 2007/05/15 21:49:21 cheshire
387 Get rid of "#pragma unused"
389 Revision 1.411 2007/05/14 23:54:55 cheshire
390 Instead of sprintf, use safer length-limited mDNS_snprintf
392 Revision 1.410 2007/05/12 01:05:00 cheshire
393 Updated debugging messages
395 Revision 1.409 2007/05/10 22:39:48 cheshire
396 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
397 Only define CountMaskBits for builds with debugging messages
399 Revision 1.408 2007/05/10 22:19:00 cheshire
400 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
401 Don't deliver multicast packets for which we can't find an associated InterfaceID
403 Revision 1.407 2007/05/10 21:40:28 cheshire
404 Don't log unnecessary "Address already in use" errors when joining multicast groups
406 Revision 1.406 2007/05/08 00:56:17 cheshire
407 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
409 Revision 1.405 2007/05/04 20:21:39 cheshire
410 Improve "connect failed" error message
412 Revision 1.404 2007/05/02 19:41:53 cheshire
413 No need to alarm people with "Connection reset by peer" syslog message
415 Revision 1.403 2007/04/28 01:31:59 cheshire
416 Improve debugging support for catching memory corruption problems
418 Revision 1.402 2007/04/26 22:54:57 cheshire
419 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
421 Revision 1.401 2007/04/26 00:35:16 cheshire
422 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
423 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
424 inside the firewall may give answers where a public one gives none, and vice versa.)
426 Revision 1.400 2007/04/24 21:50:27 cheshire
427 Debugging: Show list of changedKeys in NetworkChanged callback
429 Revision 1.399 2007/04/23 22:28:47 cheshire
430 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
432 Revision 1.398 2007/04/23 04:57:00 cheshire
433 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
435 Revision 1.397 2007/04/22 06:02:03 cheshire
436 <rdar://problem/4615977> Query should immediately return failure when no server
438 Revision 1.396 2007/04/21 21:47:47 cheshire
439 <rdar://problem/4376383> Daemon: Add watchdog timer
441 Revision 1.395 2007/04/18 20:58:34 cheshire
442 <rdar://problem/5140339> Domain discovery not working over VPN
443 Needed different code to handle the case where there's only a single search domain
445 Revision 1.394 2007/04/17 23:05:50 cheshire
446 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
448 Revision 1.393 2007/04/17 19:21:29 cheshire
449 <rdar://problem/5140339> Domain discovery not working over VPN
451 Revision 1.392 2007/04/17 17:15:09 cheshire
452 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
454 Revision 1.391 2007/04/07 01:01:48 cheshire
455 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
457 Revision 1.390 2007/04/06 18:45:02 cheshire
458 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
460 Revision 1.389 2007/04/05 21:39:49 cheshire
461 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
463 Revision 1.388 2007/04/05 21:09:52 cheshire
464 Condense sprawling code
466 Revision 1.387 2007/04/05 20:40:37 cheshire
467 Remove unused mDNSPlatformTCPGetFlags()
469 Revision 1.386 2007/04/05 19:50:56 cheshire
470 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
472 Revision 1.385 2007/04/03 19:39:19 cheshire
473 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
475 Revision 1.384 2007/03/31 01:10:53 cheshire
478 Revision 1.383 2007/03/31 00:13:48 cheshire
481 Revision 1.382 2007/03/28 21:01:29 cheshire
482 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
484 Revision 1.381 2007/03/28 15:56:37 cheshire
485 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
487 Revision 1.380 2007/03/26 22:54:46 cheshire
490 Revision 1.379 2007/03/22 18:31:48 cheshire
491 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
493 Revision 1.378 2007/03/22 00:49:20 cheshire
494 <rdar://problem/4848295> Advertise model information via Bonjour
496 Revision 1.377 2007/03/21 00:30:05 cheshire
497 <rdar://problem/4789455> Multiple errors in DNameList-related code
499 Revision 1.376 2007/03/20 17:07:15 cheshire
500 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
502 Revision 1.375 2007/03/20 00:50:57 cheshire
503 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
505 Revision 1.374 2007/03/06 23:29:50 cheshire
506 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
508 Revision 1.373 2007/02/28 01:51:20 cheshire
509 Added comment about reverse-order IP address
511 Revision 1.372 2007/02/28 01:06:48 cheshire
512 Use %#a format code instead of %d.%d.%d.%d
514 Revision 1.371 2007/02/08 21:12:28 cheshire
515 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
517 Revision 1.370 2007/01/16 22:59:58 cheshire
518 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
520 Revision 1.369 2007/01/10 02:09:32 cheshire
521 Better LogOperation record of keys read from System Keychain
523 Revision 1.368 2007/01/10 01:25:31 cheshire
524 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
526 Revision 1.367 2007/01/10 01:22:01 cheshire
527 Make sure c1, c2, c3 are initialized
529 Revision 1.366 2007/01/09 22:37:20 cheshire
530 Provide ten-second grace period for deleted keys, to give mDNSResponder
531 time to delete host name before it gives up access to the required key.
533 Revision 1.365 2007/01/09 21:09:20 cheshire
534 Need locking in KeychainChanged()
536 Revision 1.364 2007/01/09 20:17:04 cheshire
537 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
539 Revision 1.363 2007/01/09 02:41:18 cheshire
540 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
541 moved it to mDNS_Init() in mDNS.c (core code)
543 Revision 1.362 2007/01/08 23:54:01 cheshire
544 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
546 Revision 1.361 2007/01/05 08:30:48 cheshire
547 Trim excessive "$Log" checkin history from before 2006
548 (checkin history still available via "cvs log ..." of course)
550 Revision 1.360 2007/01/04 00:12:24 cheshire
551 <rdar://problem/4742742> Read *all* DNS keys from keychain,
552 not just key for the system-wide default registration domain
554 Revision 1.359 2006/12/22 21:14:37 cheshire
555 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
556 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
558 Revision 1.358 2006/12/22 20:59:50 cheshire
559 <rdar://problem/4742742> Read *all* DNS keys from keychain,
560 not just key for the system-wide default registration domain
562 Revision 1.357 2006/12/21 00:09:45 cheshire
563 Use mDNSPlatformMemZero instead of bzero
565 Revision 1.356 2006/12/20 23:15:53 mkrochma
566 Fix the private domain list code so that it actually works
568 Revision 1.355 2006/12/20 23:04:36 mkrochma
569 Fix crash when adding private domain list to Dynamic Store
571 Revision 1.354 2006/12/19 22:43:55 cheshire
572 Fix compiler warnings
574 Revision 1.353 2006/12/14 22:08:29 cheshire
575 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
576 to release data allocated by SecKeychainItemCopyAttributesAndData()
578 Revision 1.352 2006/12/14 02:33:26 cheshire
579 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
581 Revision 1.351 2006/11/28 21:37:51 mkrochma
582 Tweak where the private DNS data is written
584 Revision 1.350 2006/11/28 07:55:02 herscher
585 <rdar://problem/4742743> dnsextd has a slow memory leak
587 Revision 1.349 2006/11/28 07:45:58 herscher
588 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
590 Revision 1.348 2006/11/16 21:47:20 mkrochma
591 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
593 Revision 1.347 2006/11/10 00:54:16 cheshire
594 <rdar://problem/4816598> Changing case of Computer Name doesn't work
596 Revision 1.346 2006/10/31 02:34:58 cheshire
597 <rdar://problem/4692130> Stop creating HINFO records
599 Revision 1.345 2006/09/21 20:04:38 mkrochma
600 Accidently changed function name while checking in previous fix
602 Revision 1.344 2006/09/21 19:04:13 mkrochma
603 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
605 Revision 1.343 2006/09/15 21:20:16 cheshire
606 Remove uDNS_info substructure from mDNS_struct
608 Revision 1.342 2006/08/16 00:31:50 mkrochma
609 <rdar://problem/4386944> Get rid of NotAnInteger references
611 Revision 1.341 2006/08/14 23:24:40 cheshire
612 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
614 Revision 1.340 2006/07/29 19:11:13 mkrochma
615 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
617 Revision 1.339 2006/07/27 03:24:35 cheshire
618 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
619 Further refinement: Declare KQueueEntry parameter "const"
621 Revision 1.338 2006/07/27 02:59:25 cheshire
622 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
623 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
624 after releasing BigMutex, in case actions it took have resulted in new work for the
625 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
626 add new active interfaces to its list, and consequently schedule queries to be sent).
628 Revision 1.337 2006/07/22 06:11:37 cheshire
629 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
631 Revision 1.336 2006/07/15 02:01:32 cheshire
632 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
633 Fix broken "empty string" browsing
635 Revision 1.335 2006/07/14 05:25:11 cheshire
636 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
637 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
639 Revision 1.334 2006/07/05 23:42:00 cheshire
640 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
642 Revision 1.333 2006/06/29 05:33:30 cheshire
643 <rdar://problem/4607043> mDNSResponder conditional compilation options
645 Revision 1.332 2006/06/28 09:10:36 cheshire
646 Extra debugging messages
648 Revision 1.331 2006/06/21 22:29:42 cheshire
649 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
651 Revision 1.330 2006/06/20 23:06:00 cheshire
652 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
654 Revision 1.329 2006/06/08 23:22:33 cheshire
657 Revision 1.328 2006/03/19 03:27:49 cheshire
658 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
660 Revision 1.327 2006/03/19 02:00:09 cheshire
661 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
663 Revision 1.326 2006/03/08 22:42:23 cheshire
664 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
666 Revision 1.325 2006/01/10 00:39:17 cheshire
667 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
669 Revision 1.324 2006/01/09 19:28:59 cheshire
670 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
672 Revision 1.323 2006/01/05 21:45:27 cheshire
673 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
675 Revision 1.322 2006/01/05 21:41:50 cheshire
676 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
678 Revision 1.321 2006/01/05 21:35:06 cheshire
679 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
683 // ***************************************************************************
685 // Supporting routines to run mDNS on a CFRunLoop platform
686 // ***************************************************************************
688 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
689 // including ones that mDNSResponder chooses not to use.
690 #define LIST_ALL_INTERFACES 0
692 // For enabling AAAA records over IPv4. Setting this to 0 sends only
693 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
694 // AAAA and A records over both IPv4 and IPv6.
695 #define AAAA_OVER_V4 1
697 // In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
698 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
699 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
700 // By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
701 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
702 // so were willing to make that sacrifice.
703 // In Mac OS X 10.5, in 2007, two things have changed:
704 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
705 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
707 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
709 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
710 #include "DNSCommon.h"
712 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
713 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
714 #include "PlatformCommon.h"
717 #include <stdarg.h> // For va_list support
719 #include <net/if_types.h> // For IFT_ETHER
720 #include <net/if_dl.h>
722 #include <sys/param.h>
723 #include <sys/socket.h>
724 #include <sys/sysctl.h>
725 #include <sys/event.h>
727 #include <sys/ioctl.h>
728 #include <time.h> // platform support for UTC time
729 #include <arpa/inet.h> // for inet_aton
732 #include <netinet/in.h> // For IP_RECVTTL
734 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
737 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
738 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
739 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
740 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
742 #if TARGET_OS_EMBEDDED
743 #define NO_SECURITYFRAMEWORK 1
744 #define NO_CFUSERNOTIFICATION 1
747 #ifndef NO_SECURITYFRAMEWORK
748 #include <Security/SecureTransport.h>
749 #include <Security/Security.h>
750 #endif /* NO_SECURITYFRAMEWORK */
752 #include <DebugServices.h>
755 // Code contributed by Dave Heller:
756 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
757 // work on Mac OS X 10.1, which does not have the getifaddrs call.
758 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
759 #if RUN_ON_PUMA_WITHOUT_IFADDRS
760 #include "mDNSMacOSXPuma.c"
765 #include <IOKit/IOKitLib.h>
766 #include <IOKit/IOMessage.h>
767 #include <mach/mach_error.h>
768 #include <mach/mach_port.h>
769 #include <mach/mach_time.h>
772 #define kInterfaceSpecificOption "interface="
774 // ***************************************************************************
777 #if COMPILER_LIKES_PRAGMA_MARK
778 #pragma mark - Globals
781 static mDNSu32 clockdivisor
= 0;
783 mDNSexport
int KQueueFD
;
785 #ifndef NO_SECURITYFRAMEWORK
786 static CFArrayRef ServerCerts
;
787 #endif /* NO_SECURITYFRAMEWORK */
789 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
791 CFStringRef NetworkChangedKey_IPv4
;
792 CFStringRef NetworkChangedKey_IPv6
;
793 CFStringRef NetworkChangedKey_Hostnames
;
794 CFStringRef NetworkChangedKey_Computername
;
795 CFStringRef NetworkChangedKey_DNS
;
796 CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
797 CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
799 // ***************************************************************************
802 #if COMPILER_LIKES_PRAGMA_MARK
804 #pragma mark - Utility Functions
807 // We only attempt to send and receive multicast packets on interfaces that are
808 // (a) flagged as multicast-capable
809 // (b) *not* flagged as point-to-point (e.g. modem)
810 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
811 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
812 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
813 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
815 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
817 static int notifyCount
= 0;
818 if (notifyCount
) return;
820 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
821 // To avoid this, we don't try to display alerts in the first three minutes after boot.
822 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
824 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
827 // Determine if we're at Apple (17.*.*.*)
828 extern mDNS mDNSStorage
;
829 NetworkInterfaceInfoOSX
*i
;
830 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
831 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
833 if (!i
) return; // If not at Apple, don't show the alert
839 // Display a notification to the user
842 #ifndef NO_CFUSERNOTIFICATION
843 static const char footer
[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
844 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
845 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
846 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
847 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
848 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
849 #endif /* NO_CFUSERNOTIFICATION */
852 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
854 static struct ifaddrs
*ifa
= NULL
;
862 if (ifa
== NULL
) getifaddrs(&ifa
);
867 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
868 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
870 NetworkInterfaceInfoOSX
*i
;
871 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
872 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
873 ((type
== AF_UNSPEC
) ||
874 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
875 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
879 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
882 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
883 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
884 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
885 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
889 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
891 NetworkInterfaceInfoOSX
*i
;
892 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
893 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
895 // Don't get tricked by inactive interfaces with no InterfaceID set
896 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
897 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) return(i
->ifinfo
.InterfaceID
);
899 // Not found. Make sure our interface list is up to date, then try again.
900 LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex
);
901 mDNSMacOSXNetworkChanged(m
);
902 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
903 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) return(i
->ifinfo
.InterfaceID
);
908 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
910 NetworkInterfaceInfoOSX
*i
;
911 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
912 if (id
== mDNSInterface_Any
) return(0);
914 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
915 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
916 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
918 // Not found. Make sure our interface list is up to date, then try again.
919 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id
);
920 mDNSMacOSXNetworkChanged(m
);
921 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
922 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
927 #if COMPILER_LIKES_PRAGMA_MARK
929 #pragma mark - UDP & TCP send & receive
932 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
934 mDNSBool result
= mDNSfalse
;
935 SCNetworkConnectionFlags flags
;
936 SCNetworkReachabilityRef ReachRef
= NULL
;
938 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
939 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
940 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
941 result
= flags
& kSCNetworkFlagsConnectionRequired
;
944 if (ReachRef
) CFRelease(ReachRef
);
948 struct UDPSocket_struct
950 mDNSIPPort port
; // MUST BE FIRST FIELD -- mDNSCore expects every UDPSocket_struct to begin with mDNSIPPort port
954 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
955 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
956 // OR send via our primary v4 unicast socket
957 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
958 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
960 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
961 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
962 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
963 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
964 char *ifa_name
= info
? info
->ifa_name
: "unicast";
965 struct sockaddr_storage to
;
967 mStatus result
= mStatus_NoError
;
969 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
970 // anonymous socket created for this purpose, so that we'll receive the response.
971 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
972 if (InterfaceID
&& !mDNSAddrIsDNSMulticast(dst
))
973 if ((((DNSMessage
*)msg
)->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
974 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
976 if (dst
->type
== mDNSAddrType_IPv4
)
978 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
979 sin_to
->sin_len
= sizeof(*sin_to
);
980 sin_to
->sin_family
= AF_INET
;
981 sin_to
->sin_port
= dstPort
.NotAnInteger
;
982 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
983 s
= m
->p
->permanentsockets
.sktv4
;
985 #ifdef _LEGACY_NAT_TRAVERSAL_
986 if (m
->SSDPSocket
&& mDNSSameIPPort(dstPort
, SSDPPort
))
987 s
= m
->SSDPSocket
->ss
.sktv4
;
988 #endif _LEGACY_NAT_TRAVERSAL_
990 if (info
) // Specify outgoing interface
992 if (!mDNSAddrIsDNSMulticast(dst
))
994 #ifdef IP_FORCE_OUT_IFP
995 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, ifa_name
, strlen(ifa_name
) + 1);
998 static int displayed
= 0;
1002 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
1009 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1010 if (err
< 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1014 else if (dst
->type
== mDNSAddrType_IPv6
)
1016 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1017 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1018 sin6_to
->sin6_family
= AF_INET6
;
1019 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1020 sin6_to
->sin6_flowinfo
= 0;
1021 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1022 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1023 s
= m
->p
->permanentsockets
.sktv6
;
1024 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1026 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1027 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
));
1032 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1036 return mStatus_BadParamErr
;
1039 // Don't send if it would cause dial-on-demand connection initiation.
1040 // As an optimization, don't bother consulting reachability API / routing
1041 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
1042 if (!info
&& !mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
1044 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1045 return mStatus_NoError
;
1049 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1050 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1052 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1053 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1055 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1056 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1057 if (s
< 0) return(mStatus_Invalid
);
1059 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1062 static int MessageCount
= 0;
1063 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1064 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1065 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1066 // Don't report EHOSTUNREACH in the first three minutes after boot
1067 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1068 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1069 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1070 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1071 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1072 if (MessageCount
< 1000)
1075 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1076 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1078 result
= mStatus_UnknownErr
;
1081 #ifdef IP_FORCE_OUT_IFP
1082 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1083 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, "", 1);
1089 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1090 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1092 static unsigned int numLogMessages
= 0;
1093 struct iovec databuffers
= { (char *)buffer
, max
};
1096 struct cmsghdr
*cmPtr
;
1097 char ancillary
[1024];
1099 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1101 // Set up the message
1102 msg
.msg_name
= (caddr_t
)from
;
1103 msg
.msg_namelen
= *fromlen
;
1104 msg
.msg_iov
= &databuffers
;
1106 msg
.msg_control
= (caddr_t
)&ancillary
;
1107 msg
.msg_controllen
= sizeof(ancillary
);
1111 n
= recvmsg(s
, &msg
, 0);
1114 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1117 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1119 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1120 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1123 if (msg
.msg_flags
& MSG_CTRUNC
)
1125 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1129 *fromlen
= msg
.msg_namelen
;
1131 // Parse each option out of the ancillary data.
1132 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1134 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1135 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1137 dstaddr
->type
= mDNSAddrType_IPv4
;
1138 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1139 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1141 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1143 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1144 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1146 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1147 ifname
[sdl
->sdl_nlen
] = 0;
1148 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1151 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1152 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1153 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1155 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1156 dstaddr
->type
= mDNSAddrType_IPv6
;
1157 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1158 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1160 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1161 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1167 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1169 const KQSocketSet
*const ss
= (const KQSocketSet
*)context
;
1170 mDNS
*const m
= ss
->m
;
1173 if (filter
!= EVFILT_READ
)
1174 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1176 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
1178 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1179 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1180 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1185 mDNSAddr senderAddr
, destAddr
;
1186 mDNSIPPort senderPort
, destPort
= (m
->SSDPSocket
&& ss
== &m
->SSDPSocket
->ss
? m
->SSDPSocket
->port
: MulticastDNSPort
);
1187 struct sockaddr_storage from
;
1188 size_t fromlen
= sizeof(from
);
1189 char packetifname
[IF_NAMESIZE
] = "";
1191 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1195 if (from
.ss_family
== AF_INET
)
1197 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
1198 senderAddr
.type
= mDNSAddrType_IPv4
;
1199 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
1200 senderPort
.NotAnInteger
= s
->sin_port
;
1201 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1203 else if (from
.ss_family
== AF_INET6
)
1205 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1206 senderAddr
.type
= mDNSAddrType_IPv6
;
1207 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1208 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1209 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1213 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1217 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1218 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1219 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1220 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1221 // When going to sleep we deregister all our interfaces, but if the machine
1222 // takes a few seconds to sleep we may continue to receive multicasts
1223 // during that time, which would confuse mDNSCoreReceive, because as far
1224 // as it's concerned, we should have no active interfaces any more.
1225 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1226 if (intf
) InterfaceID
= intf
->InterfaceID
;
1227 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1229 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1230 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1232 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1235 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1237 // Something is busted here.
1238 // kqueue says there is a packet, but myrecvfrom says there is not.
1239 // Try calling select() to get another opinion.
1240 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1241 // All of this is racy, as data may have arrived after the call to select()
1242 static unsigned int numLogMessages
= 0;
1243 int save_errno
= errno
;
1247 socklen_t solen
= sizeof(int);
1249 struct timeval timeout
;
1252 FD_SET(s1
, &readfds
);
1254 timeout
.tv_usec
= 0;
1255 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1256 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1257 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1258 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1259 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1260 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1261 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1262 if (numLogMessages
++ < 100)
1263 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1264 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1265 if (numLogMessages
> 5)
1266 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1267 "Congratulations, you've reproduced an elusive bug.\r"
1268 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1269 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1270 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1272 sleep(1); // After logging this error, rate limit so we don't flood syslog
1276 // TCP socket support
1278 struct TCPSocket_struct
1280 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1281 TCPConnectionCallback callback
;
1283 KQueueEntry kqEntry
;
1284 #ifndef NO_SECURITYFRAMEWORK
1285 SSLContextRef tlsContext
;
1286 #endif /* NO_SECURITYFRAMEWORK */
1289 mDNSBool handshakecomplete
;
1293 #ifndef NO_SECURITYFRAMEWORK
1295 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1297 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1298 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1299 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1301 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1302 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1303 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1304 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno
, strerror(errno
));
1305 return(errSSLClosedAbort
);
1308 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1310 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1311 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1312 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1314 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1315 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1316 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1317 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno
, strerror(errno
));
1318 return(errSSLClosedAbort
);
1321 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1323 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1324 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1326 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1327 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1329 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1330 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1335 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1337 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1338 const domainname
*d1
= mDNSNULL
; // TLD
1339 const domainname
*d2
= mDNSNULL
; // SLD
1340 const domainname
*d3
= mDNSNULL
;
1341 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1342 return(d3
&& SameDomainName(d3
, mmc
));
1345 #endif /* NO_SECURITYFRAMEWORK */
1347 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1349 TCPSocket
*sock
= context
;
1350 mStatus err
= mStatus_NoError
;
1352 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1353 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1354 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1355 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, &sock
->kqEntry
);
1357 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1359 #ifndef NO_SECURITYFRAMEWORK
1360 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1361 if (!sock
->handshakecomplete
)
1363 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1364 err
= SSLHandshake(sock
->tlsContext
);
1365 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1366 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1367 else if (err
== errSSLWouldBlock
) return;
1368 else { LogMsg("KQ SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1371 err
= mStatus_UnsupportedErr
;
1372 #endif /* NO_SECURITYFRAMEWORK */
1375 mDNSBool c
= !sock
->connected
;
1376 sock
->connected
= mDNStrue
;
1377 sock
->callback(sock
, sock
->context
, c
, err
);
1378 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1381 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1383 struct kevent new_event
;
1384 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1385 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1388 mDNSexport
void KQueueLock(mDNS
*const m
)
1390 pthread_mutex_lock(&m
->p
->BigMutex
);
1391 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1394 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1396 mDNSs32 end
= mDNSPlatformRawTime();
1398 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1399 LogOperation("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1401 pthread_mutex_unlock(&m
->p
->BigMutex
);
1404 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1405 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno
, strerror(errno
));
1408 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1412 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1413 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1415 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1416 sock
->callback
= mDNSNULL
;
1417 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
1418 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1419 sock
->kqEntry
.KQcontext
= sock
;
1420 sock
->kqEntry
.KQtask
= "mDNSPlatformTCPSocket";
1421 sock
->flags
= flags
;
1422 sock
->context
= mDNSNULL
;
1423 sock
->setup
= mDNSfalse
;
1424 sock
->handshakecomplete
= mDNSfalse
;
1425 sock
->connected
= mDNSfalse
;
1429 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1430 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1435 struct sockaddr_in addr
;
1436 memset(&addr
, 0, sizeof(addr
));
1437 addr
.sin_family
= AF_INET
;
1438 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1439 addr
.sin_port
= port
->NotAnInteger
;
1440 if (bind(sock
->fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
1441 { LogMsg("ERROR: bind %s", strerror(errno
)); goto error
; }
1443 // Receive interface identifiers
1444 const int on
= 1; // "on" for setsockopt
1445 if (setsockopt(sock
->fd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1446 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); goto error
; }
1448 memset(&addr
, 0, sizeof(addr
));
1449 socklen_t len
= sizeof(addr
);
1450 if (getsockname(sock
->fd
, (struct sockaddr
*) &addr
, &len
) < 0)
1451 { LogMsg("getsockname - %s", strerror(errno
)); goto error
; }
1453 port
->NotAnInteger
= addr
.sin_port
;
1458 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1462 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1463 TCPConnectionCallback callback
, void *context
)
1465 struct sockaddr_in saddr
;
1466 mStatus err
= mStatus_NoError
;
1468 sock
->callback
= callback
;
1469 sock
->context
= context
;
1470 sock
->setup
= mDNSfalse
;
1471 sock
->handshakecomplete
= mDNSfalse
;
1472 sock
->connected
= mDNSfalse
;
1474 (void) InterfaceID
; //!!!KRS use this if non-zero!!!
1476 if (dst
->type
!= mDNSAddrType_IPv4
)
1478 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1479 return mStatus_UnknownErr
;
1482 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1483 saddr
.sin_family
= AF_INET
;
1484 saddr
.sin_port
= dstport
.NotAnInteger
;
1485 saddr
.sin_len
= sizeof(saddr
);
1486 saddr
.sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1488 // Don't send if it would cause dial-on-demand connection initiation.
1489 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1491 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1492 return mStatus_UnknownErr
;
1495 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1496 sock
->kqEntry
.KQcontext
= sock
;
1497 sock
->kqEntry
.KQtask
= "Outgoing TCP";
1499 // Watch for connect complete (write is ready)
1500 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1501 if (KQueueSet(sock
->fd
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, &sock
->kqEntry
))
1503 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1508 // Watch for incoming data
1509 if (KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
))
1511 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1512 close(sock
->fd
); // Closing the descriptor removes all filters from the kqueue
1516 if (fcntl(sock
->fd
, F_SETFL
, fcntl(sock
->fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1518 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1519 return mStatus_UnknownErr
;
1522 // initiate connection wth peer
1523 if (connect(sock
->fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1525 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1526 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock
->fd
, errno
, strerror(errno
));
1528 return mStatus_ConnFailed
;
1531 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1532 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1536 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1537 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1539 mStatus err
= mStatus_NoError
;
1541 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1542 if (!sock
) return(mDNSNULL
);
1544 memset(sock
, 0, sizeof(*sock
));
1546 sock
->flags
= flags
;
1548 if (flags
& kTCPSocketFlags_UseTLS
)
1550 #ifndef NO_SECURITYFRAMEWORK
1551 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1553 err
= tlsSetupSock(sock
, mDNStrue
);
1554 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1556 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1557 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1559 err
= mStatus_UnsupportedErr
;
1560 #endif /* NO_SECURITYFRAMEWORK */
1562 #ifndef NO_SECURITYFRAMEWORK
1566 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1570 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1574 #ifndef NO_SECURITYFRAMEWORK
1575 if (sock
->tlsContext
)
1577 SSLClose(sock
->tlsContext
);
1578 SSLDisposeContext(sock
->tlsContext
);
1579 sock
->tlsContext
= NULL
;
1581 #endif /* NO_SECURITYFRAMEWORK */
1584 shutdown(sock
->fd
, 2);
1589 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
1593 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1596 *closed
= mDNSfalse
;
1598 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1600 #ifndef NO_SECURITYFRAMEWORK
1601 if (!sock
->handshakecomplete
)
1603 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1604 mStatus err
= SSLHandshake(sock
->tlsContext
);
1605 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1606 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1607 else if (err
== errSSLWouldBlock
) return(0);
1608 else { LogMsg("Read SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1611 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1612 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t*)&nread
);
1613 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1614 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1615 else if (err
&& err
!= errSSLWouldBlock
)
1616 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1620 #endif /* NO_SECURITYFRAMEWORK */
1624 static int CLOSEDcount
= 0;
1625 static int EAGAINcount
= 0;
1626 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1628 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
1629 else if (nread
== 0)
1632 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
1634 // else nread is negative -- see what kind of error we got
1635 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1636 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno
, strerror(errno
)); nread
= -1; }
1637 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1640 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1647 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1651 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1653 #ifndef NO_SECURITYFRAMEWORK
1655 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1657 if (!err
) nsent
= (int) processed
;
1658 else if (err
== errSSLWouldBlock
) nsent
= 0;
1659 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1662 #endif /* NO_SECURITYFRAMEWORK */
1666 nsent
= send(sock
->fd
, msg
, len
, 0);
1669 if (errno
== EAGAIN
) nsent
= 0;
1670 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1677 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1682 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1683 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1684 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
1686 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1687 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1688 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1690 const int twofivefive
= 255;
1691 mStatus err
= mStatus_NoError
;
1692 char *errstr
= mDNSNULL
;
1694 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1695 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1697 // ... with a shared UDP port, if it's for multicast receiving
1698 if (mDNSSameIPPort(port
, MulticastDNSPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1699 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1701 if (sa_family
== AF_INET
)
1703 // We want to receive destination addresses
1704 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1705 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1707 // We want to receive interface identifiers
1708 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1709 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1711 // We want to receive packet TTL value so we can check it
1712 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1713 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1715 // Send unicast packets with TTL 255
1716 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1717 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1719 // And multicast packets with TTL 255 too
1720 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1721 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1723 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1724 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1725 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1727 // And start listening for packets
1728 struct sockaddr_in listening_sockaddr
;
1729 listening_sockaddr
.sin_family
= AF_INET
;
1730 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1731 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1732 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1733 if (err
) { errstr
= "bind"; goto fail
; }
1734 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
1736 else if (sa_family
== AF_INET6
)
1738 // We want to receive destination addresses and receive interface identifiers
1739 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1740 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1742 // We want to receive packet hop count value so we can check it
1743 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1744 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1746 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1747 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1748 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1749 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1751 // Send unicast packets with TTL 255
1752 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1753 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1755 // And multicast packets with TTL 255 too
1756 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1757 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1759 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1761 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1762 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1763 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1764 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1767 // Want to receive our own packets
1768 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1769 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1771 // And start listening for packets
1772 struct sockaddr_in6 listening_sockaddr6
;
1773 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1774 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1775 listening_sockaddr6
.sin6_family
= AF_INET6
;
1776 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1777 listening_sockaddr6
.sin6_flowinfo
= 0;
1778 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
1779 listening_sockaddr6
.sin6_scope_id
= 0;
1780 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1781 if (err
) { errstr
= "bind"; goto fail
; }
1782 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
1785 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1786 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
1788 k
->KQcallback
= myKQSocketCallBack
;
1790 k
->KQtask
= "UDP packet reception";
1791 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
1796 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1797 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
1798 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1800 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1801 if (!strcmp(errstr
, "bind") && mDNSSameIPPort(port
, MulticastDNSPort
) && errno
== EADDRINUSE
)
1802 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1803 "Congratulations, you've reproduced an elusive bug.\r"
1804 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1805 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1806 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1812 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort port
)
1815 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
1816 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
1817 memset(p
, 0, sizeof(UDPSocket
));
1821 p
->port
= zeroIPPort
;
1822 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->port
);
1825 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1826 // of failing to bind to this port when Internet Sharing has already bound to it
1827 if (mDNSSameIPPort(port
, NATPMPPort
))
1828 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1829 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1830 freeL("UDPSocket", p
);
1836 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1838 if (ss
->sktv4
!= -1)
1843 if (ss
->sktv6
!= -1)
1850 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
1852 CloseSocketSet(&sock
->ss
);
1853 freeL("UDPSocket", sock
);
1856 #if COMPILER_LIKES_PRAGMA_MARK
1858 #pragma mark - Key Management
1861 #ifndef NO_SECURITYFRAMEWORK
1862 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
1864 CFMutableArrayRef certChain
= NULL
;
1865 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
1866 SecCertificateRef cert
;
1867 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
1868 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
1871 SecPolicySearchRef searchRef
;
1872 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
1873 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
1876 SecPolicyRef policy
;
1877 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
1878 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
1881 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
1882 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
1886 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
1887 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
1890 err
= SecTrustEvaluate(trust
, NULL
);
1891 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
1894 CFArrayRef rawCertChain
;
1895 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1896 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
1897 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
1900 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
1901 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
1904 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1905 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1906 CFArraySetValueAtIndex(certChain
, 0, identity
);
1907 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1908 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
1910 CFRelease(rawCertChain
);
1911 // Do not free statusChain:
1912 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1913 // certChain: Call the CFRelease function to release this object when you are finished with it.
1914 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1919 CFRelease(wrappedCert
);
1923 CFRelease(searchRef
);
1929 #endif /* NO_SECURITYFRAMEWORK */
1931 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
1933 #ifdef NO_SECURITYFRAMEWORK
1934 return mStatus_UnsupportedErr
;
1936 SecIdentityRef identity
= nil
;
1937 SecIdentitySearchRef srchRef
= nil
;
1940 // search for "any" identity matching specified key use
1941 // In this app, we expect there to be exactly one
1942 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
1943 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
1945 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
1946 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
1948 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
1949 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
1951 // Found one. Call getCertChain to create the correct certificate chain.
1952 ServerCerts
= GetCertChain(identity
);
1953 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
1955 return mStatus_NoError
;
1956 #endif /* NO_SECURITYFRAMEWORK */
1959 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
1961 #ifndef NO_SECURITYFRAMEWORK
1962 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
1963 #endif /* NO_SECURITYFRAMEWORK */
1966 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1967 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1969 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1970 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1973 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1978 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1979 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1981 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1984 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1989 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1992 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1993 if (!state
) return mDNSfalse
;
1994 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1995 return val
? mDNStrue
: mDNSfalse
;
1998 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2000 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2002 if (sa
->sa_family
== AF_INET
)
2004 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2005 ip
->type
= mDNSAddrType_IPv4
;
2006 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2007 return(mStatus_NoError
);
2010 if (sa
->sa_family
== AF_INET6
)
2012 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2013 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2014 // value into the second word of the IPv6 link-local address, so they can just
2015 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2016 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2017 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2018 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2019 ip
->type
= mDNSAddrType_IPv6
;
2020 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2021 return(mStatus_NoError
);
2024 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2025 return(mStatus_Invalid
);
2028 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2030 mDNSEthAddr eth
= zeroEthAddr
;
2031 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2034 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2037 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2040 CFRange range
= { 0, 6 }; // Offset, length
2041 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2042 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2045 CFRelease(entityname
);
2052 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2053 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2054 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2055 // (e.g. sa_family not AF_INET or AF_INET6)
2056 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2058 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2059 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2062 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2063 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2065 NetworkInterfaceInfoOSX
**p
;
2066 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2067 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2069 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2070 (*p
)->Exists
= mDNStrue
;
2071 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2072 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
2076 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2077 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2078 if (!i
) return(mDNSNULL
);
2079 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
2080 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2081 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2082 strcpy(i
->ifa_name
, ifa
->ifa_name
); // This is safe because we know we allocated i->ifa_name with sufficient space
2084 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2086 i
->ifinfo
.mask
= mask
;
2087 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2088 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2089 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2090 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2093 i
->Exists
= mDNStrue
;
2094 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
2096 i
->Flashing
= mDNSfalse
;
2097 i
->Occulting
= mDNSfalse
;
2098 i
->scope_id
= scope_id
;
2100 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2101 i
->ifa_flags
= ifa
->ifa_flags
;
2107 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2108 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2110 NetworkInterfaceInfoOSX
*i
;
2111 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2112 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2113 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
2119 #if APPLE_OSX_mDNSResponder
2121 #if COMPILER_LIKES_PRAGMA_MARK
2123 #pragma mark - AutoTunnel
2126 #define kRacoonPort 4500
2128 static mDNSBool AnonymousRacoonConfig
= mDNSfalse
;
2130 // MUST be called with lock held
2131 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
2133 ServiceRecordSet
*p
;
2134 for (p
= m
->ServiceRegistrations
; p
; p
= p
->uDNS_next
)
2136 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, p
->RR_SRV
.resrec
.name
);
2137 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
2142 // MUST be called with lock held
2143 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
2146 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
2147 if (p
->q
.ThisQInterval
< 0)
2152 mDNSlocal
void RegisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2154 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && AutoTunnelUnregistered(info
))
2157 LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
2159 // 1. Set up our address record for the internal tunnel address
2160 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2161 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
2162 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
2163 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
2164 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
2165 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2166 err
= mDNS_Register(m
, &info
->AutoTunnelHostRecord
);
2167 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2169 // 2. Set up device info record
2170 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
2171 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
2172 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
2173 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
2174 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
2175 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
2176 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2177 err
= mDNS_Register(m
, &info
->AutoTunnelDeviceInfo
);
2178 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2180 // 3. Set up our address record for the external tunnel address
2181 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2182 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
2183 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
2184 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
2185 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2188 mDNS_AddDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
, mDNSNULL
, info
);
2191 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2192 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2193 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
2194 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
2195 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
2196 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
2197 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
2198 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
2199 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2200 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
2201 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2203 LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2204 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
2205 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
2209 mDNSlocal
void DeregisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2211 LogOperation("DeregisterAutoTunnelRecords %##s", info
->domain
.c
);
2212 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2214 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
2217 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2218 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2222 mDNS_RemoveDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
);
2226 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2228 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
2231 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2232 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2236 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2238 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
2241 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2242 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2247 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2249 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
2250 if (result
== mStatus_MemFree
)
2252 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
2253 RegisterAutoTunnelRecords(m
,info
);
2257 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
2259 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
2260 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
2261 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
2263 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
2264 DeregisterAutoTunnelRecords(m
,info
);
2265 RegisterAutoTunnelRecords(m
,info
);
2267 // Determine whether we need racoon to accept incoming connections
2268 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2269 if (info
->AutoTunnel
&& !info
->deltime
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
))
2271 mDNSBool needRacoonConfig
= info
!= mDNSNULL
;
2272 if (needRacoonConfig
!= AnonymousRacoonConfig
)
2274 AnonymousRacoonConfig
= needRacoonConfig
;
2275 // Create or revert configuration file, and start (or SIGHUP) Racoon
2276 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, info
? info
->b64keydata
: "");
2280 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2282 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2284 LogOperation("Aborting deregistration of %s", ARDisplayString(m
, rr
));
2285 CompleteDeregistration(m
, rr
);
2287 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
2288 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
2291 // Before SetupLocalAutoTunnelInterface_internal is called,
2292 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2293 // Must be called with the lock held
2294 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
)
2296 LogOperation("SetupLocalAutoTunnelInterface");
2298 // 1. Configure the local IPv6 address
2299 if (!m
->AutoTunnelHostAddrActive
)
2301 m
->AutoTunnelHostAddrActive
= mDNStrue
;
2302 LogOperation("Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
2303 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
2306 // 2. If we have at least one server (pending) listening, publish our records
2307 if (TunnelServers(m
))
2309 DomainAuthInfo
*info
;
2310 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2312 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
2314 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
2315 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
2316 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
2317 AbortDeregistration(m
, &info
->AutoTunnelService
);
2319 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2320 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2321 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2322 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2324 // Try to get a NAT port mapping for the AutoTunnelService
2325 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
2326 info
->AutoTunnelNAT
.clientContext
= info
;
2327 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
2328 info
->AutoTunnelNAT
.IntPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2329 info
->AutoTunnelNAT
.RequestedPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2330 info
->AutoTunnelNAT
.NATLease
= 0;
2331 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
2332 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err
);
2338 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
2340 return(mDNSAutoTunnelSetKeys(AddNew
? kmDNSAutoTunnelSetKeysReplace
: kmDNSAutoTunnelSetKeysDelete
, tun
->loc_inner
.b
, tun
->loc_outer
.b
, kRacoonPort
, tun
->rmt_inner
.b
, tun
->rmt_outer
.b
, mDNSVal16(tun
->rmt_outer_port
), tun
->b64keydata
));
2343 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2344 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2346 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
2348 DNSQuestion
*q
= m
->Questions
;
2351 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
2353 LogOperation("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2354 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
2355 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2356 mDNS_StopQuery(m
, q
);
2357 mDNS_StartQuery(m
, q
);
2358 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
2359 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
2360 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2361 // In general we have to assume that the question list might have changed in arbitrary ways.
2362 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2363 // already in use. The safest solution is just to go back to the start of the list and start again.
2364 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2365 // just one suspended question, so it's really a 2n algorithm.
2373 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
2375 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
2376 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
2377 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
2378 // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
2379 // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
2380 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
2381 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
2384 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
2386 ClientTunnel
**p
= &m
->TunnelClients
;
2387 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
2388 if (*p
) *p
= tun
->next
;
2389 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
2390 LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
2391 freeL("ClientTunnel", tun
);
2394 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2396 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
2397 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
2399 if (!AddRecord
) return;
2400 mDNS_StopQuery(m
, question
);
2402 if (!answer
->rdlength
)
2404 LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
2405 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
2409 if (question
->qtype
== kDNSType_AAAA
)
2411 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
2413 LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
2414 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
2418 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
2419 LogOperation("AutoTunnelCallback: dst host %.16a", &tun
->rmt_inner
);
2420 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2421 AppendDomainName(&question
->qname
, &tun
->dstname
);
2422 question
->qtype
= kDNSType_SRV
;
2423 mDNS_StartQuery(m
, &tun
->q
);
2425 else if (question
->qtype
== kDNSType_SRV
)
2427 LogOperation("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
2428 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
2429 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
2430 question
->qtype
= kDNSType_A
;
2431 mDNS_StartQuery(m
, &tun
->q
);
2433 else if (question
->qtype
== kDNSType_A
)
2435 ClientTunnel
*old
= mDNSNULL
;
2436 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer
->rdata
->u
.ipv4
);
2437 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
2438 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
2439 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
2440 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
2441 tmpDst
.ip
.v4
= tun
->rmt_outer
;
2442 mDNSAddr tmpSrc
= zeroAddr
;
2443 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
2444 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
2445 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
2447 ClientTunnel
**p
= &tun
->next
;
2448 mDNSBool needSetKeys
= mDNStrue
;
2451 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
2454 LogOperation("Found existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2457 if (old
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &old
->q
);
2458 else if (!mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
2459 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
2460 !mDNSSameIPv6Address(old
->rmt_inner
, tun
->rmt_inner
) ||
2461 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
2462 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
2464 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2465 AutoTunnelSetKeys(old
, mDNSfalse
);
2467 else needSetKeys
= mDNSfalse
;
2469 LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun
);
2470 freeL("ClientTunnel", old
);
2474 if (needSetKeys
) LogOperation("New AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2476 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
); mDNS_Unlock(m
); };
2478 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
2479 // Kick off any questions that were held pending this tunnel setup
2480 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
2483 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
2486 // Must be called with the lock held
2487 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
2489 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
2491 AssignDomainName(&p
->dstname
, &q
->qname
);
2492 p
->MarkedForDeletion
= mDNSfalse
;
2493 p
->loc_inner
= zerov6Addr
;
2494 p
->loc_outer
= zerov4Addr
;
2495 p
->rmt_inner
= zerov6Addr
;
2496 p
->rmt_outer
= zerov4Addr
;
2497 p
->rmt_outer_port
= zeroIPPort
;
2498 mDNS_snprintf(p
->b64keydata
, sizeof(p
->b64keydata
), "%s", q
->AuthInfo
->b64keydata
);
2499 p
->next
= m
->TunnelClients
;
2500 m
->TunnelClients
= p
; // We intentionally build list in reverse order
2502 p
->q
.InterfaceID
= mDNSInterface_Any
;
2503 p
->q
.Target
= zeroAddr
;
2504 AssignDomainName(&p
->q
.qname
, &q
->qname
);
2505 p
->q
.qtype
= kDNSType_AAAA
;
2506 p
->q
.qclass
= kDNSClass_IN
;
2507 p
->q
.LongLived
= mDNSfalse
;
2508 p
->q
.ExpectUnique
= mDNStrue
;
2509 p
->q
.ForceMCast
= mDNSfalse
;
2510 p
->q
.ReturnIntermed
= mDNStrue
;
2511 p
->q
.QuestionCallback
= AutoTunnelCallback
;
2512 p
->q
.QuestionContext
= p
;
2514 LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
2515 mDNS_StartQuery_internal(m
, &p
->q
);
2518 #endif // APPLE_OSX_mDNSResponder
2520 #if COMPILER_LIKES_PRAGMA_MARK
2522 #pragma mark - Power State & Configuration Change Management
2525 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2527 mDNSBool foundav4
= mDNSfalse
;
2528 mDNSBool foundav6
= mDNSfalse
;
2529 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2530 struct ifaddrs
*v4Loopback
= NULL
;
2531 struct ifaddrs
*v6Loopback
= NULL
;
2532 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2533 char defaultname
[32];
2535 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2536 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2538 if (m
->SleepState
) ifa
= NULL
;
2542 #if LIST_ALL_INTERFACES
2543 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2544 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2545 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2546 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2547 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2548 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2549 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2550 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2551 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2552 if (!(ifa
->ifa_flags
& IFF_UP
))
2553 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2554 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2555 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2556 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2557 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2558 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2559 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2560 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2561 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2562 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2563 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2566 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2568 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2569 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2570 mDNSPlatformMemCopy(PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
2573 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2574 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2576 if (!ifa
->ifa_netmask
)
2579 SetupAddr(&ip
, ifa
->ifa_addr
);
2580 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2581 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2583 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2586 SetupAddr(&ip
, ifa
->ifa_addr
);
2587 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2588 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2592 int ifru_flags6
= 0;
2594 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2595 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2597 struct in6_ifreq ifr6
;
2598 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
2599 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2600 ifr6
.ifr_addr
= *sin6
;
2601 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2602 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2603 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2606 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2608 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2610 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2612 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
2617 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2618 if (i
&& MulticastInterface(i
))
2620 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2621 else foundav6
= mDNStrue
;
2627 ifa
= ifa
->ifa_next
;
2630 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2631 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2632 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2634 // Now the list is complete, set the McastTxRx setting for each interface.
2635 NetworkInterfaceInfoOSX
*i
;
2636 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2639 mDNSBool txrx
= MulticastInterface(i
);
2640 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2641 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2643 if (i
->ifinfo
.McastTxRx
!= txrx
)
2645 i
->ifinfo
.McastTxRx
= txrx
;
2646 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2651 if (InfoSocket
>= 0) close(InfoSocket
);
2654 // If we haven't set up AutoTunnelHostAddr yet, do it now
2655 if (!mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
2657 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2658 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
2659 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
2660 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
2661 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
2662 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
2663 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
2664 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
2665 m
->AutoTunnelHostAddr
.b
[0x8] = PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
2666 m
->AutoTunnelHostAddr
.b
[0x9] = PrimaryMAC
.b
[1];
2667 m
->AutoTunnelHostAddr
.b
[0xA] = PrimaryMAC
.b
[2];
2668 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
2669 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
2670 m
->AutoTunnelHostAddr
.b
[0xD] = PrimaryMAC
.b
[3];
2671 m
->AutoTunnelHostAddr
.b
[0xE] = PrimaryMAC
.b
[4];
2672 m
->AutoTunnelHostAddr
.b
[0xF] = PrimaryMAC
.b
[5];
2673 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
2674 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
2675 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
2676 LogOperation("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
2679 #ifndef kDefaultLocalHostNamePrefix
2680 #define kDefaultLocalHostNamePrefix "Macintosh"
2682 mDNS_snprintf(defaultname
, sizeof(defaultname
), kDefaultLocalHostNamePrefix
"-%02X%02X%02X%02X%02X%02X",
2683 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2685 // Set up the nice label
2686 domainlabel nicelabel
;
2688 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2689 if (nicelabel
.c
[0] == 0)
2691 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2692 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2695 // Set up the RFC 1034-compliant label
2696 domainlabel hostlabel
;
2698 GetUserSpecifiedLocalHostName(&hostlabel
);
2699 if (hostlabel
.c
[0] == 0)
2701 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2702 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2705 mDNSBool namechange
= mDNSfalse
;
2707 // We use a case-sensitive comparison here because even though changing the capitalization
2708 // of the name alone is not significant to DNS, it's still a change from the user's point of view
2709 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2710 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2713 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2714 LogMsg("User updated Computer Name from %#s to %#s", m
->p
->usernicelabel
.c
, nicelabel
.c
);
2715 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2716 namechange
= mDNStrue
;
2719 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2720 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2723 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2724 LogMsg("User updated Local Hostname from %#s to %#s", m
->p
->userhostlabel
.c
, hostlabel
.c
);
2725 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2727 namechange
= mDNStrue
;
2730 #if APPLE_OSX_mDNSResponder
2731 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
2733 DomainAuthInfo
*info
;
2734 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2735 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPv4AddressIsOnes(info
->AutoTunnelNAT
.ExternalAddress
))
2736 AutoTunnelNATCallback(m
, &info
->AutoTunnelNAT
);
2740 return(mStatus_NoError
);
2743 #if LogAllOperations || MDNS_DEBUGMSGS
2744 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
2745 // Returns -1 if all the one-bits are not contiguous
2746 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2748 int i
= 0, bits
= 0;
2749 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2752 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2753 while (b
& 0x80) { bits
++; b
<<= 1; }
2756 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2761 // returns count of non-link local V4 addresses registered
2762 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2764 NetworkInterfaceInfoOSX
*i
;
2766 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2769 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
2770 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
2771 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2773 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2775 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2776 n
->InterfaceID
= mDNSNULL
;
2779 if (!n
->InterfaceID
)
2781 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2782 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2783 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2784 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2786 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2787 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2788 // 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.
2789 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2791 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
2792 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2793 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2794 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2795 i
->Flashing
? " (Flashing)" : "",
2796 i
->Occulting
? " (Occulting)" : "",
2797 n
->InterfaceActive
? " (Primary)" : "");
2800 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2803 if (i
->sa_family
== AF_INET
)
2806 primary
->ifa_v4addr
.s_addr
= i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
2807 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
2808 imr
.imr_interface
= primary
->ifa_v4addr
;
2810 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
2811 // before trying to join the group, to clear out stale kernel state which may be lingering.
2812 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
2813 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
2814 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
2815 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
2816 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
2817 // because by the time we get the configuration change notification, the interface is already gone,
2818 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
2819 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
2820 if (SearchForInterfaceByName(m
, i
->ifa_name
, AF_INET
) == i
)
2822 LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i
->ifa_name
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
2823 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
2824 if (err
< 0 && (errno
!= EADDRNOTAVAIL
|| LogAllOperations
))
2825 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
2828 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifa_name
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
2829 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
2830 // Joining same group twice can give "Address already in use" error -- no need to report that
2831 if (err
< 0 && (errno
!= EADDRINUSE
|| LogAllOperations
))
2832 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
2835 if (i
->sa_family
== AF_INET6
)
2837 struct ipv6_mreq i6mr
;
2838 i6mr
.ipv6mr_interface
= primary
->scope_id
;
2839 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
2841 if (SearchForInterfaceByName(m
, i
->ifa_name
, AF_INET6
) == i
)
2843 LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i
->ifa_name
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2844 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
2845 if (err
< 0 && (errno
!= EADDRNOTAVAIL
|| LogAllOperations
))
2846 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2849 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifa_name
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2850 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2851 // Joining same group twice can give "Address already in use" error -- no need to report that
2852 if (err
< 0 && (errno
!= EADDRINUSE
|| LogAllOperations
))
2853 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
2862 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2864 NetworkInterfaceInfoOSX
*i
;
2865 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2867 if (i
->Exists
) i
->LastSeen
= utc
;
2868 i
->Exists
= mDNSfalse
;
2872 // returns count of non-link local V4 addresses deregistered
2873 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2876 // If an interface is going away, then deregister this from the mDNSCore.
2877 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2878 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2879 // it refers to has gone away we'll crash.
2880 NetworkInterfaceInfoOSX
*i
;
2882 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2884 // If this interface is no longer active, or its InterfaceID is changing, deregister it
2885 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
2886 if (i
->ifinfo
.InterfaceID
)
2887 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2889 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
2890 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2891 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2892 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
2893 i
->Flashing
? " (Flashing)" : "",
2894 i
->Occulting
? " (Occulting)" : "",
2895 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2896 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
2897 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2898 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2899 // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2900 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2901 // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2903 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
2904 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
2909 // Now that everything that's going to deregister has done so, we can clean up and free the memory
2910 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2914 // If no longer active, delete interface from list and free memory
2917 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2918 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2919 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2920 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2921 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2922 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2926 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2927 freeL("NetworkInterfaceInfoOSX", i
);
2928 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2936 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
2938 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
2939 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
2942 dnle
->next
= mDNSNULL
;
2944 AssignDomainName(&dnle
->name
, name
);
2946 *List
= &dnle
->next
;
2950 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
2953 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
2956 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
2957 if (fqdn
) fqdn
->c
[0] = 0;
2958 if (RegDomains
) *RegDomains
= NULL
;
2959 if (BrowseDomains
) *BrowseDomains
= NULL
;
2961 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
2962 setservers
? " setservers" : "",
2963 setsearch
? " setsearch" : "",
2964 fqdn
? " fqdn" : "",
2965 RegDomains
? " RegDomains" : "",
2966 BrowseDomains
? " BrowseDomains" : "");
2968 // Add the inferred address-based configuration discovery domains
2969 // (should really be in core code I think, not platform-specific)
2972 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2976 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
2978 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
2979 !SetupAddr(&a
, ifa
->ifa_addr
) &&
2980 !SetupAddr(&n
, ifa
->ifa_netmask
) &&
2981 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
2983 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2984 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
2985 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
2986 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
2987 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
2988 mDNS_AddSearchDomain_CString(buf
);
2990 ifa
= ifa
->ifa_next
;
2994 #ifndef MDNS_NO_DNSINFO
2995 if (setservers
|| setsearch
)
2997 dns_config_t
*config
= dns_configuration_copy();
3000 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
3001 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
3002 // Apparently this is expected behaviour -- "not a bug".
3003 // Accordingly, we suppress syslog messages for the first three minutes after boot.
3004 // If we are still getting failures after three minutes, then we log them.
3005 if (mDNSMacOSXSystemBuildNumber(NULL
) > 7 && (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
3006 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
3010 LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
3013 for (i
= 0; i
< config
->n_resolver
; i
++)
3016 dns_resolver_t
*r
= config
->resolver
[i
];
3017 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
3018 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
3019 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
3020 if (r
->port
== 5353) continue;
3021 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
3022 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
3024 for (j
= 0; j
< config
->n_resolver
; j
++) // check if this is the lowest-weighted server for the domain
3026 dns_resolver_t
*p
= config
->resolver
[j
];
3027 if (p
->port
== 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
3028 if (p
->search_order
<= r
->search_order
)
3031 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
3032 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
3033 if (SameDomainName(&d
, &tmp
))
3034 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
3037 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
3038 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
);
3041 mDNSInterfaceID interface
= mDNSInterface_Any
;
3044 // DNS server option parsing
3045 if (r
->options
!= NULL
)
3047 char *nextOption
= r
->options
;
3048 char *currentOption
= NULL
;
3049 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
3051 // The option may be in the form of interface=xxx where xxx is an interface name.
3052 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
3054 NetworkInterfaceInfoOSX
*ni
;
3055 char ifname
[IF_NAMESIZE
+1];
3056 mDNSu32 ifindex
= 0;
3057 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
3058 // This allows us to block these special queries from going out on the wire.
3059 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
3060 ifindex
= if_nametoindex(ifname
);
3061 if (ifindex
== 0) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname
); continue; }
3062 LogOperation("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__
, r
->domain
, ifname
, ifindex
);
3063 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
3064 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
3065 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
3066 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
) break;
3067 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
3068 if (interface
== mDNSNULL
) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex
, ifname
); continue; }
3072 for (n
= 0; n
< r
->n_nameserver
; n
++)
3073 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& (interface
|| disabled
|| !AddrRequiresPPPConnection(r
->nameserver
[n
])))
3076 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
3077 debugf("Adding dns server from slot %d %#a for domain %##s", i
, &saddr
, d
.c
);
3078 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
3081 DNSServer
*s
= mDNS_AddDNSServer(m
, &d
, interface
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
);
3082 if (s
&& disabled
) s
->teststate
= DNSServer_Disabled
;
3090 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3091 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3092 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3093 // instead use the search domain list as the sole authority for what domains to search and in what order
3094 // (and the domain from the "domain" field will also appear somewhere in that list).
3095 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
3096 // search lists for other resolvers in the list need to be ignored.
3097 if (config
->resolver
[0]->n_search
== 0) mDNS_AddSearchDomain_CString(config
->resolver
[0]->domain
);
3098 else for (i
= 0; i
< config
->resolver
[0]->n_search
; i
++) mDNS_AddSearchDomain_CString(config
->resolver
[0]->search
[i
]);
3100 dns_configuration_free(config
);
3101 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
3102 setsearch
= mDNSfalse
;
3105 #endif // MDNS_NO_DNSINFO
3107 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
3110 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
3115 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
3116 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
3118 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
3119 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
3120 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
3122 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
3125 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3126 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
3127 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
3128 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
3136 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
3137 if (regArray
&& CFArrayGetCount(regArray
) > 0)
3139 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
3140 if (regDict
&& DDNSSettingEnabled(regDict
))
3142 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
3145 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3146 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3147 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
3150 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
3151 AppendDNameListElem(&RegDomains
, 0, &d
);
3160 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
3163 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
3165 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
3166 if (browseDict
&& DDNSSettingEnabled(browseDict
))
3168 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
3171 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3172 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3173 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
3176 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
3177 AppendDNameListElem(&BrowseDomains
, 0, &d
);
3184 CFRelease(ddnsdict
);
3189 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
3192 CFIndex size
= CFDictionaryGetCount(btmm
);
3193 const void *key
[size
];
3194 const void *val
[size
];
3195 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
3196 for (i
= 0; i
< size
; i
++)
3198 LogOperation("BackToMyMac %d", i
);
3199 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3200 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
3203 mDNSu32 uid
= atoi(buf
);
3204 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3205 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
3206 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
3208 LogOperation("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
3209 AppendDNameListElem(&RegDomains
, uid
, &d
);
3217 if (setservers
|| setsearch
)
3219 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DNS
);
3224 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
3227 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
3229 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
3230 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
3231 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
3232 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
3233 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
3239 // Add the manual and/or DHCP-dicovered search domains
3240 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
3243 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
3245 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
3246 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3247 mDNS_AddSearchDomain_CString(buf
);
3250 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3252 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3253 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3254 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3255 // instead use the search domain list as the sole authority for what domains to search and in what order
3256 // (and the domain from the "domain" field will also appear somewhere in that list).
3257 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
3258 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3259 mDNS_AddSearchDomain_CString(buf
);
3269 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
3275 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
3276 if (!store
) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed");
3279 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_IPv4
);
3282 r
->type
= mDNSAddrType_IPv4
;
3283 r
->ip
.v4
= zerov4Addr
;
3284 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3287 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
3288 LogMsg("Could not convert router to CString");
3291 struct sockaddr_in saddr
;
3292 saddr
.sin_len
= sizeof(saddr
);
3293 saddr
.sin_family
= AF_INET
;
3295 inet_aton(buf
, &saddr
.sin_addr
);
3297 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) debugf("Ignoring router %s (requires PPP connection)", buf
);
3298 else *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
3302 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3305 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3306 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3308 *v4
= *v6
= zeroAddr
;
3310 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
3312 // find primary interface in list
3313 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
3315 mDNSAddr tmp6
= zeroAddr
;
3316 if (!strcmp(buf
, ifa
->ifa_name
))
3318 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
3320 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
3322 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3324 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3325 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3326 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
3331 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3332 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
3334 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3335 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
3338 ifa
= ifa
->ifa_next
;
3341 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3342 // V4 to communicate w/ our DNS server
3353 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
3355 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
3356 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3357 ConvertDomainNameToCString(dname
, uname
);
3363 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
3367 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3368 // That single entity is a CFDictionary with name "HostNames".
3369 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3370 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3371 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3372 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3373 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3375 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
3376 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
3377 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
3378 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
3381 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
3382 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
3385 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
3388 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
3391 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
3394 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, StateDict
);
3395 CFRelease(StateDict
);
3397 CFRelease(StateVals
[0]);
3399 CFRelease(HostVals
[0]);
3401 CFRelease(StatusVals
[0]);
3403 CFRelease(HostKeys
[0]);
3407 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3408 mDNSexport
void SetDomainSecrets(mDNS
*m
)
3410 #ifdef NO_SECURITYFRAMEWORK
3412 LogMsg("Note: SetDomainSecrets: no keychain support");
3414 mDNSBool haveAutoTunnels
= mDNSfalse
;
3416 LogOperation("SetDomainSecrets");
3418 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3419 // In the case where the user simultaneously removes their DDNS host name and the key
3420 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3421 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3422 // address records behind that we no longer have permission to delete.
3423 DomainAuthInfo
*ptr
;
3424 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3425 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
3427 #if APPLE_OSX_mDNSResponder
3429 // Mark all TunnelClients for deletion
3430 ClientTunnel
*client
;
3431 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3433 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
3434 client
->MarkedForDeletion
= mDNStrue
;
3437 #endif APPLE_OSX_mDNSResponder
3439 // String Array used to write list of private domains to Dynamic Store
3440 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3441 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3443 CFDataRef data
= NULL
;
3444 const int itemsPerEntry
= 3; // domain name, key name, key value
3445 CFArrayRef secrets
= NULL
;
3446 int err
= mDNSKeychainGetSecrets(&secrets
);
3447 if (err
|| !secrets
)
3448 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
3451 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
3452 // Iterate through the secrets
3453 for (i
= 0; i
< ArrayCount
; ++i
)
3456 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
3457 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
3458 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3459 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
3460 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
3461 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3463 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3465 // Get DNS domain this key is for
3466 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
3467 data
= CFArrayGetValueAtIndex(entry
, 0);
3468 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3469 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
3470 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3471 stringbuf
[CFDataGetLength(data
)] = '\0';
3474 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
3477 data
= CFArrayGetValueAtIndex(entry
, 1);
3478 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3479 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
3480 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3481 stringbuf
[CFDataGetLength(data
)] = '\0';
3484 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
3487 data
= CFArrayGetValueAtIndex(entry
, 2);
3488 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3489 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
3490 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3491 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3493 DomainAuthInfo
*FoundInList
;
3494 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
3495 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
3497 #if APPLE_OSX_mDNSResponder
3500 // If any client tunnel destination is in this domain, set deletion flag to false
3501 ClientTunnel
*client
;
3502 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3503 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
3505 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
3506 client
->MarkedForDeletion
= mDNSfalse
;
3507 // If the key has changed, reconfigure the tunnel
3508 if (strncmp(stringbuf
, client
->b64keydata
, sizeof(client
->b64keydata
)))
3510 mDNSBool queryNotInProgress
= client
->q
.ThisQInterval
< 0;
3511 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client
->dstname
.c
, queryNotInProgress
? "reconfiguring" : "query in progress");
3512 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNSfalse
);
3513 mDNS_snprintf(client
->b64keydata
, sizeof(client
->b64keydata
), "%s", stringbuf
);
3514 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNStrue
);
3519 mDNSBool keyChanged
= FoundInList
&& FoundInList
->AutoTunnel
? strncmp(stringbuf
, FoundInList
->b64keydata
, sizeof(FoundInList
->b64keydata
)) : mDNSfalse
;
3521 #endif APPLE_OSX_mDNSResponder
3523 // Uncomment the line below to view the keys as they're read out of the system keychain
3524 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3525 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
3527 // If didn't find desired domain in the list, make a new entry
3529 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
3532 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
3533 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
3536 LogOperation("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
3537 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
3539 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3543 #if APPLE_OSX_mDNSResponder
3544 if (keyChanged
&& AnonymousRacoonConfig
)
3546 LogOperation("SetDomainSecrets: secret changed for %##s", &domain
);
3547 (void)mDNSConfigureServer(kmDNSUp
, stringbuf
);
3549 #endif APPLE_OSX_mDNSResponder
3551 ConvertDomainNameToCString(&domain
, stringbuf
);
3552 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
3553 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
3557 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, sa
);
3560 #if APPLE_OSX_mDNSResponder
3562 // clean up ClientTunnels
3563 ClientTunnel
**pp
= &m
->TunnelClients
;
3566 if ((*pp
)->MarkedForDeletion
)
3568 ClientTunnel
*cur
= *pp
;
3569 LogOperation("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
3570 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
3571 AutoTunnelSetKeys(cur
, mDNSfalse
);
3573 freeL("ClientTunnel", cur
);
3579 DomainAuthInfo
*info
= m
->AuthInfoList
;
3582 if (info
->AutoTunnel
&& info
->deltime
&& info
->AutoTunnelNAT
.clientContext
)
3584 // stop the NAT operation
3585 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
3586 if (info
->AutoTunnelNAT
.clientCallback
)
3588 // Reset port and let the AutoTunnelNATCallback handle cleanup
3589 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
3590 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
3591 info
->AutoTunnelNAT
.Lifetime
= 0;
3592 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
3593 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3594 info
->AutoTunnelNAT
.clientCallback(m
, &info
->AutoTunnelNAT
);
3595 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3597 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
3602 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
3604 // remove interface if no autotunnel servers and no more client tunnels
3605 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3606 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
3607 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
3608 memset(m
->AutoTunnelHostAddr
.b
, 0, sizeof(m
->AutoTunnelHostAddr
.b
));
3611 if (!haveAutoTunnels
&& AnonymousRacoonConfig
)
3613 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3614 AnonymousRacoonConfig
= mDNSfalse
;
3615 (void)mDNSConfigureServer(kmDNSDown
, "");
3618 if (m
->AutoTunnelHostAddr
.b
[0])
3619 if (TunnelClients(m
) || TunnelServers(m
))
3620 SetupLocalAutoTunnelInterface_internal(m
);
3622 #endif APPLE_OSX_mDNSResponder
3624 #endif /* NO_SECURITYFRAMEWORK */
3627 mDNSlocal
void SetLocalDomains(void)
3629 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3630 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3632 CFArrayAppendValue(sa
, CFSTR("local"));
3633 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
3634 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
3635 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
3636 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
3637 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
3639 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, sa
);
3643 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3645 LogOperation("*** Network Configuration Change *** (%d)%s",
3646 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
3647 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
3648 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3649 mDNSs32 utc
= mDNSPlatformUTC();
3650 MarkAllInterfacesInactive(m
, utc
);
3651 UpdateInterfaceList(m
, utc
);
3652 ClearInactiveInterfaces(m
, utc
);
3653 SetupActiveInterfaces(m
, utc
);
3655 #if APPLE_OSX_mDNSResponder
3657 if (m
->AutoTunnelHostAddr
.b
[0])
3660 if (TunnelClients(m
) || TunnelServers(m
))
3661 SetupLocalAutoTunnelInterface_internal(m
);
3665 // Scan to find client tunnels whose questions have completed,
3666 // but whose local inner/outer addresses have changed since the tunnel was set up
3668 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
3669 if (p
->q
.ThisQInterval
< 0)
3671 mDNSAddr tmpSrc
= zeroAddr
;
3672 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
3673 tmpDst
.ip
.v4
= p
->rmt_outer
;
3674 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
3675 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
3676 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
3678 AutoTunnelSetKeys(p
, mDNSfalse
);
3679 p
->loc_inner
= m
->AutoTunnelHostAddr
;
3680 p
->loc_outer
= tmpSrc
.ip
.v4
;
3681 AutoTunnelSetKeys(p
, mDNStrue
);
3685 #endif APPLE_OSX_mDNSResponder
3687 uDNS_SetupDNSConfig(m
);
3689 if (m
->MainCallback
)
3690 m
->MainCallback(m
, mStatus_ConfigChanged
);
3693 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3695 (void)store
; // Parameter not used
3696 (void)changedKeys
; // Parameter not used
3697 mDNS
*const m
= (mDNS
*const)context
;
3701 mDNSs32 delay
= mDNSPlatformOneSecond
; // Start off assuming a one-second delay
3703 int c
= CFArrayGetCount(changedKeys
); // Count changes
3704 CFRange range
= { 0, c
};
3705 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
3706 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
3707 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
3708 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/20; // If these were the only changes, shorten delay
3710 #if LogAllOperations
3715 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
3716 LogOperation("*** NetworkChanged SC key: %s", buf
);
3718 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
3720 c1
? "(Local Hostname) " : "",
3721 c2
? "(Computer Name) " : "",
3722 c3
? "(DynamicDNS) " : "",
3726 if (!m
->p
->NetworkChanged
||
3727 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3728 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3730 // If we have a global DNS change, then disregard delay and reconfigure immediately
3731 if (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0) m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
);
3733 // KeyChain frequently fails to notify clients of change events. To work around this
3734 // we set a timer and periodically poll to detect if any changes have occurred.
3735 // Without this Back To My Mac just does't work for a large number of users.
3736 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
3737 if (c3
|| CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
))
3739 LogOperation("*** NetworkChanged *** starting KeyChainBugTimer");
3740 m
->p
->KeyChainBugTimer
= NonZeroTime(m
->timenow
+ delay
);
3741 m
->p
->KeyChainBugInterval
= mDNSPlatformOneSecond
;
3744 if (!m
->SuppressSending
||
3745 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3746 m
->SuppressSending
= m
->p
->NetworkChanged
;
3749 KQueueUnlock(m
, "NetworkChanged");
3752 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3755 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3756 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3757 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3758 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3759 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3760 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3762 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3763 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3765 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
3766 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
3767 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
3768 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
3769 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
3770 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
3771 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
3772 CFArrayAppendValue(patterns
, pattern1
);
3773 CFArrayAppendValue(patterns
, pattern2
);
3774 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3775 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3776 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3778 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3779 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3781 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3782 m
->p
->Store
= store
;
3787 if (store
) CFRelease(store
);
3790 if (patterns
) CFRelease(patterns
);
3791 if (pattern2
) CFRelease(pattern2
);
3792 if (pattern1
) CFRelease(pattern1
);
3793 if (keys
) CFRelease(keys
);
3798 #ifndef NO_SECURITYFRAMEWORK
3799 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
3801 LogOperation("*** Keychain Changed ***");
3802 mDNS
*const m
= (mDNS
*const)context
;
3804 OSStatus err
= SecKeychainCopyDefault(&skc
);
3807 if (info
->keychain
== skc
)
3809 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
3810 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
3813 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
3814 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
3815 SecKeychainAttributeList
*a
= NULL
;
3816 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
3819 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
3820 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
3821 SecKeychainItemFreeAttributesAndData(a
, NULL
);
3826 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
3828 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
3829 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
3830 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
3831 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
3834 SetDomainSecrets(m
);
3836 KQueueUnlock(m
, "KeychainChanged");
3847 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3849 mDNS
*const m
= (mDNS
*const)refcon
;
3851 (void)service
; // Parameter not used
3852 LogOperation("PowerChanged %X %lX", messageType
, messageArgument
);
3855 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3856 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3857 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3858 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3859 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3860 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3861 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3862 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3863 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3864 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3865 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3866 // Just to be safe, also make sure our interface list is fully up to date, in case we
3867 // haven't yet received the System Configuration Framework "network changed" event that
3868 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3869 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3870 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3871 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3872 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3873 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3874 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3877 if (!m
->p
->SleepLimit
&& messageType
== kIOMessageSystemWillSleep
)
3879 m
->p
->SleepLimit
= NonZeroTime(mDNS_TimeNow(m
) + mDNSPlatformOneSecond
* 5);
3880 m
->p
->SleepCookie
= (long)messageArgument
;
3883 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3885 KQueueUnlock(m
, "Sleep/Wake");
3887 #endif /* NO_IOPOWER */
3889 #if COMPILER_LIKES_PRAGMA_MARK
3891 #pragma mark - Initialization & Teardown
3894 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3895 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3896 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3897 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3899 // Major version 6 is 10.2.x (Jaguar)
3900 // Major version 7 is 10.3.x (Panther)
3901 // Major version 8 is 10.4.x (Tiger)
3902 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3904 int major
= 0, minor
= 0;
3905 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
3906 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3909 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3910 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3911 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3912 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3913 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3914 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3915 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3918 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
3919 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3923 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3924 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3925 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3926 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3929 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3931 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3934 struct sockaddr_in s5353
;
3935 s5353
.sin_family
= AF_INET
;
3936 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3937 s5353
.sin_addr
.s_addr
= 0;
3938 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3942 if (err
) LogMsg("No unicast UDP responses");
3943 else debugf("Unicast UDP responses okay");
3947 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3948 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3949 // (.local manually generated via explicit callback)
3950 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3951 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3952 // 4) result above should generate a callback from question in (1). result added to global list
3953 // 5) global list delivered to client via GetSearchDomainList()
3954 // 6) client calls to enumerate domains now go over LocalOnly interface
3955 // (!!!KRS may add outgoing interface in addition)
3957 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3961 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3962 // 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.
3964 for (i
=0; i
<100; i
++)
3966 domainlabel testlabel
;
3968 GetUserSpecifiedLocalHostName(&testlabel
);
3969 if (testlabel
.c
[0]) break;
3973 m
->hostlabel
.c
[0] = 0;
3975 char *HINFO_HWstring
= "Macintosh";
3976 char HINFO_HWstring_buffer
[256];
3977 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3978 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3979 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3980 HINFO_HWstring
= HINFO_HWstring_buffer
;
3982 char HINFO_SWstring
[256] = "";
3983 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3984 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3986 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3987 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3988 if (hlen
+ slen
< 254)
3990 m
->HIHardware
.c
[0] = hlen
;
3991 m
->HISoftware
.c
[0] = slen
;
3992 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
3993 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
3996 m
->p
->permanentsockets
.m
= m
;
3997 m
->p
->permanentsockets
.sktv4
= m
->p
->permanentsockets
.sktv6
= -1;
3998 m
->p
->permanentsockets
.kqsv4
.KQcallback
= m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
3999 m
->p
->permanentsockets
.kqsv4
.KQcontext
= m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
4000 m
->p
->permanentsockets
.kqsv4
.KQtask
= m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
4002 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
4004 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
4007 struct sockaddr_in s4
;
4008 socklen_t n4
= sizeof(s4
);
4009 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
4010 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
4012 if (m
->p
->permanentsockets
.sktv6
>= 0)
4014 struct sockaddr_in6 s6
;
4015 socklen_t n6
= sizeof(s6
);
4016 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
4017 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
4021 m
->p
->InterfaceList
= mDNSNULL
;
4022 m
->p
->userhostlabel
.c
[0] = 0;
4023 m
->p
->usernicelabel
.c
[0] = 0;
4024 m
->p
->NotifyUser
= 0;
4025 m
->p
->KeyChainBugTimer
= 0;
4026 m
->p
->SleepLimit
= 0;
4028 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
4030 mDNSs32 utc
= mDNSPlatformUTC();
4031 UpdateInterfaceList(m
, utc
);
4032 SetupActiveInterfaces(m
, utc
);
4034 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
4035 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
4036 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
4037 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
4038 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
4039 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
4040 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
4042 err
= WatchForNetworkChanges(m
);
4043 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
4045 // Explicitly ensure that our Keychain operations utilize the system domain.
4046 #ifndef NO_SECURITYFRAMEWORK
4047 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
4051 SetDomainSecrets(m
);
4055 #ifndef NO_SECURITYFRAMEWORK
4056 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
4057 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
4061 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
4062 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
4063 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
4064 #endif /* NO_IOPOWER */
4066 return(mStatus_NoError
);
4069 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
4072 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
4075 mStatus result
= mDNSPlatformInit_setup(m
);
4077 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
4078 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
4079 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
4083 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
4085 if (m
->p
->PowerConnection
)
4087 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
4089 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
4090 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
4091 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
4092 IOServiceClose ( m
->p
->PowerConnection
);
4093 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
4094 #endif /* NO_IOPOWER */
4095 m
->p
->PowerConnection
= 0;
4100 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
4101 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
4102 CFRelease(m
->p
->StoreRLS
);
4103 CFRelease(m
->p
->Store
);
4105 m
->p
->StoreRLS
= NULL
;
4108 mDNSs32 utc
= mDNSPlatformUTC();
4109 MarkAllInterfacesInactive(m
, utc
);
4110 ClearInactiveInterfaces(m
, utc
);
4111 CloseSocketSet(&m
->p
->permanentsockets
);
4113 #if APPLE_OSX_mDNSResponder
4114 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
4116 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
4117 LogMsg("Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
4118 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
4120 #endif // APPLE_OSX_mDNSResponder
4123 #if COMPILER_LIKES_PRAGMA_MARK
4125 #pragma mark - General Platform Support Layer functions
4128 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
4130 return(mach_absolute_time());
4133 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
4135 mDNSexport mStatus
mDNSPlatformTimeInit(void)
4137 // Notes: Typical values for mach_timebase_info:
4138 // tbi.numer = 1000 million
4139 // tbi.denom = 33 million
4140 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
4141 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
4142 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
4143 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
4144 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
4146 // Arithmetic notes:
4147 // tbi.denom is at least 1, and not more than 2^32-1.
4148 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
4149 // tbi.denom is at least 1, and not more than 2^32-1.
4150 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
4151 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
4152 // which is unlikely on any current or future Macintosh.
4153 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
4154 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
4155 struct mach_timebase_info tbi
;
4156 kern_return_t result
= mach_timebase_info(&tbi
);
4157 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
4161 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
4163 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
4165 static uint64_t last_mach_absolute_time
= 0;
4166 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
4167 uint64_t this_mach_absolute_time
= mach_absolute_time();
4168 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
4170 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
4171 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
4172 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
4173 last_mach_absolute_time
= this_mach_absolute_time
;
4174 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4175 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4176 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
4177 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4178 "This error occurs from time to time, often on newly released hardware, "
4179 "and usually the exact cause is different in each instance.\r\r"
4180 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4181 "and assign it to Radar Component “Kernel” Version “X”.");
4183 last_mach_absolute_time
= this_mach_absolute_time
;
4185 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
4188 mDNSexport mDNSs32
mDNSPlatformUTC(void)
4193 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4194 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
4195 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
4196 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
4197 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
4198 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
4199 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
4200 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
4201 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4202 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
4204 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }