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.536.2.2 2008/07/30 01:08:17 mcguire
21 <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
22 merge r1.540 from <rdar://problem/3988320>
24 Revision 1.536.2.1 2008/07/29 20:48:10 mcguire
25 <rdar://problem/6090007> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
26 merge r1.539 from <rdar://problem/3988320>
28 Revision 1.536 2008/03/25 01:27:30 mcguire
29 <rdar://problem/5810718> Status sometimes wrong when link goes down
31 Revision 1.535 2008/03/14 22:52:51 mcguire
32 <rdar://problem/5321824> write status to the DS
33 Ignore duplicate queries, which don't get established (since they're duplicates)
35 Revision 1.534 2008/03/12 22:58:15 mcguire
36 <rdar://problem/5321824> write status to the DS
37 Fixes for NO_SECURITYFRAMEWORK
39 Revision 1.533 2008/03/07 00:48:54 mcguire
40 <rdar://problem/5321824> write status to the DS
43 Revision 1.532 2008/03/06 23:44:39 mcguire
44 <rdar://problem/5321824> write status to the DS
45 cleanup function names & log messages
46 add external port numbers to dictionary
47 add defensive code in case CF*Create fails
48 don't output NAT statuses if zero
50 Revision 1.531 2008/03/06 21:27:47 cheshire
51 <rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
52 To save network bandwidth, removed unnecessary redundant information from HINFO record
54 Revision 1.530 2008/03/06 03:15:48 mcguire
55 <rdar://problem/5321824> write status to the DS
56 use mStatus_* instead of kDNSServiceErr_*
58 Revision 1.529 2008/03/06 02:48:35 mcguire
59 <rdar://problem/5321824> write status to the DS
61 Revision 1.528 2008/02/29 01:33:57 mcguire
62 <rdar://problem/5611801> BTMM: Services stay registered after previously successful NAT Port mapping fails
64 Revision 1.527 2008/02/28 03:25:26 mcguire
65 <rdar://problem/5535772> config cleanup on shutdown/reboot
67 Revision 1.526 2008/02/26 21:43:54 cheshire
68 Renamed 'clockdivisor' to 'mDNSPlatformClockDivisor' (LogTimeStamps code needs to be able to access it)
70 Revision 1.525 2008/02/20 00:53:20 cheshire
71 <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
72 Removed overly alarming syslog message
74 Revision 1.524 2008/01/31 22:25:10 jgraessley
75 <rdar://problem/5715434> using default Macintosh-0016CBF62EFD.local
76 Use sysctlbyname to get hardware type for the default name.
78 Revision 1.523 2008/01/15 01:32:56 jgraessley
80 Reviewed by: Stuart Cheshire
81 Additional change to print warning message up to 1000 times to make it more visible
83 Revision 1.522 2008/01/15 01:14:02 mcguire
84 <rdar://problem/5674390> mDNSPlatformSendUDP should allow unicast queries on specific interfaces
85 removed check and log message, as they are no longer relevant
87 Revision 1.521 2007/12/14 00:58:28 cheshire
88 <rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
89 Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
90 until TLS/TCP deregistrations have completed (up to five seconds maximum)
92 Revision 1.520 2007/12/10 23:01:01 cheshire
93 Remove some unnecessary log messages
95 Revision 1.519 2007/12/06 00:22:27 mcguire
96 <rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
98 Revision 1.518 2007/12/05 01:52:30 cheshire
99 <rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
100 Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
102 Revision 1.517 2007/12/03 18:37:26 cheshire
103 Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
104 from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
106 Revision 1.516 2007/12/01 01:21:27 jgraessley
107 <rdar://problem/5623140> mDNSResponder unicast DNS improvements
109 Revision 1.515 2007/12/01 00:40:00 cheshire
110 Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
112 Revision 1.514 2007/12/01 00:38:32 cheshire
113 Fixed compile warning: declaration of 'index' shadows a global declaration
115 Revision 1.513 2007/11/27 00:08:49 jgraessley
116 <rdar://problem/5613538> Interface-specific resolvers not setup correctly
118 Revision 1.512 2007/11/16 22:09:26 cheshire
119 Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
121 Revision 1.511 2007/11/14 23:06:13 cheshire
122 <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
124 Revision 1.510 2007/11/14 22:29:19 cheshire
125 Updated comments and debugging log messages
127 Revision 1.509 2007/11/14 01:07:53 cheshire
130 Revision 1.508 2007/11/02 21:59:37 cheshire
131 Added comment about locking
133 Revision 1.507 2007/11/02 20:18:13 cheshire
134 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
136 Revision 1.506 2007/10/30 20:46:45 cheshire
137 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
139 Revision 1.505 2007/10/29 23:55:10 cheshire
140 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
141 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
142 (and indeed should not, since the result fields will not yet be set up correctly in this case)
144 Revision 1.504 2007/10/26 00:50:37 cheshire
145 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
147 Revision 1.503 2007/10/25 23:11:42 cheshire
148 Ignore IPv6 ULA addresses configured on lo0 loopback interface
150 Revision 1.502 2007/10/22 20:07:07 cheshire
151 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
152 Posix build can share the code (better than just pasting it into mDNSPosix.c)
154 Revision 1.501 2007/10/22 19:40:30 cheshire
155 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
156 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
158 Revision 1.500 2007/10/17 22:49:55 cheshire
159 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
161 Revision 1.499 2007/10/17 19:47:54 cheshire
162 Improved debugging messages
164 Revision 1.498 2007/10/17 18:42:06 cheshire
165 Export SetDomainSecrets so its callable from other files
167 Revision 1.497 2007/10/16 17:03:07 cheshire
168 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
169 Cut SetDomainSecrets stack from 3792 to 1760 bytes
171 Revision 1.496 2007/10/04 20:33:05 mcguire
172 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
174 Revision 1.495 2007/10/02 05:03:38 cheshire
175 Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
177 Revision 1.494 2007/09/29 20:40:19 cheshire
178 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
180 Revision 1.493 2007/09/29 03:16:45 cheshire
181 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
182 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
184 Revision 1.492 2007/09/28 23:58:35 mcguire
185 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
188 Revision 1.491 2007/09/27 23:28:53 mcguire
189 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
191 Revision 1.490 2007/09/26 23:01:21 mcguire
192 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
194 Revision 1.489 2007/09/26 22:58:16 mcguire
195 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
197 Revision 1.488 2007/09/26 00:32:45 cheshire
198 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
200 Revision 1.487 2007/09/21 17:07:41 mcguire
201 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
203 Revision 1.486 2007/09/19 23:17:38 cheshire
204 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
206 Revision 1.485 2007/09/19 21:44:29 cheshire
207 Improved "mDNSKeychainGetSecrets failed" error message
209 Revision 1.484 2007/09/18 21:44:55 cheshire
210 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
211 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
213 Revision 1.483 2007/09/17 22:19:39 mcguire
214 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
215 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
217 Revision 1.482 2007/09/14 21:16:03 cheshire
218 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
220 Revision 1.481 2007/09/14 21:14:56 mcguire
221 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
223 Revision 1.480 2007/09/13 00:16:42 cheshire
224 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
226 Revision 1.479 2007/09/12 19:22:20 cheshire
227 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
228 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
230 Revision 1.478 2007/09/07 22:21:45 vazquez
231 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
233 Revision 1.477 2007/09/07 21:22:30 cheshire
234 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
235 Don't log failures binding to port 5351
237 Revision 1.476 2007/09/06 20:38:08 cheshire
238 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
240 Revision 1.475 2007/09/05 02:24:28 cheshire
241 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
242 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
244 Revision 1.474 2007/09/04 22:32:58 mcguire
245 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
247 Revision 1.473 2007/08/31 19:53:15 cheshire
248 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
249 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
251 Revision 1.472 2007/08/31 18:49:49 vazquez
252 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
254 Revision 1.471 2007/08/31 02:05:46 cheshire
255 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
257 Revision 1.470 2007/08/30 22:50:04 mcguire
258 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
260 Revision 1.469 2007/08/30 19:40:51 cheshire
261 Added syslog messages to report various initialization failures
263 Revision 1.468 2007/08/30 00:12:20 cheshire
264 Check error codes and log failures during AutoTunnel setup
266 Revision 1.467 2007/08/28 00:33:04 jgraessley
267 <rdar://problem/5423932> Selective compilation options
269 Revision 1.466 2007/08/24 23:25:55 cheshire
270 Debugging messages to help track down duplicate items being read from system keychain
272 Revision 1.465 2007/08/24 00:39:12 cheshire
273 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
275 Revision 1.464 2007/08/24 00:15:21 cheshire
276 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
278 Revision 1.463 2007/08/23 21:02:35 cheshire
279 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
281 Revision 1.462 2007/08/18 01:02:03 mcguire
282 <rdar://problem/5415593> No Bonjour services are getting registered at boot
284 Revision 1.461 2007/08/10 22:25:57 mkrochma
285 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
287 Revision 1.460 2007/08/08 22:34:59 mcguire
288 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
290 Revision 1.459 2007/08/08 21:07:48 vazquez
291 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
293 Revision 1.458 2007/08/03 02:18:41 mcguire
294 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
296 Revision 1.457 2007/08/02 16:48:45 mcguire
297 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
299 Revision 1.456 2007/08/02 03:28:30 vazquez
300 Make ExternalAddress and err unused to fix build warnings
302 Revision 1.455 2007/08/01 03:09:22 cheshire
303 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
305 Revision 1.454 2007/07/31 23:08:34 mcguire
306 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
308 Revision 1.453 2007/07/31 19:13:58 mkrochma
309 No longer need to include "btmm" in hostname to avoid name conflicts
311 Revision 1.452 2007/07/27 19:30:41 cheshire
312 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
313 to properly reflect tri-state nature of the possible responses
315 Revision 1.451 2007/07/25 22:25:45 cheshire
316 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
318 Revision 1.450 2007/07/25 21:19:10 cheshire
319 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
321 Revision 1.449 2007/07/25 01:36:09 mcguire
322 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
324 Revision 1.448 2007/07/24 21:30:09 cheshire
325 Added "AutoTunnel server listening for connections..." diagnostic message
327 Revision 1.447 2007/07/24 20:24:18 cheshire
328 Only remove AutoTunnel address if we have created it.
329 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
331 Revision 1.446 2007/07/24 03:00:09 cheshire
332 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
334 Revision 1.445 2007/07/23 20:26:26 cheshire
335 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
336 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
337 for existence of "Setup:/Network/DynamicDNS" settings
339 Revision 1.444 2007/07/21 00:54:49 cheshire
340 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
342 Revision 1.443 2007/07/20 23:23:11 cheshire
343 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
345 Revision 1.442 2007/07/20 20:23:24 cheshire
346 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
347 Fixed errors reading the Setup:/Network/BackToMyMac preferences
349 Revision 1.441 2007/07/20 16:46:45 mcguire
350 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
352 Revision 1.440 2007/07/20 16:22:07 mcguire
353 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
355 Revision 1.439 2007/07/20 01:14:56 cheshire
356 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
357 Cleaned up log messages
359 Revision 1.438 2007/07/20 00:54:21 cheshire
360 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
362 Revision 1.437 2007/07/19 22:01:27 cheshire
363 Added "#pragma mark" sections headings to divide code into related function groups
365 Revision 1.436 2007/07/18 03:25:25 cheshire
366 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
367 Bring up server-side tunnel on demand, when necessary
369 Revision 1.435 2007/07/18 01:05:08 cheshire
370 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
371 Add list of client tunnels so we can automatically reconfigure when local address changes
373 Revision 1.434 2007/07/16 20:16:00 vazquez
374 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
375 Remove unnecessary LNT init code
377 Revision 1.433 2007/07/14 00:36:07 cheshire
378 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
380 Revision 1.432 2007/07/12 23:55:11 cheshire
381 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
382 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
384 Revision 1.431 2007/07/12 23:34:48 cheshire
385 Removed 'LogOperation' message to reduce verbosity in syslog
387 Revision 1.430 2007/07/12 22:16:46 cheshire
388 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
390 Revision 1.429 2007/07/12 02:51:28 cheshire
391 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
393 Revision 1.428 2007/07/11 23:17:31 cheshire
394 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
395 Improve log message to indicate if we're starting or restarting racoon
397 Revision 1.427 2007/07/11 22:50:30 cheshire
398 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
399 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
401 Revision 1.426 2007/07/11 20:40:49 cheshire
402 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
403 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
405 Revision 1.425 2007/07/11 19:24:19 cheshire
406 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
407 Configure internal AutoTunnel address
408 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
409 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
411 Revision 1.424 2007/07/11 19:00:27 cheshire
412 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
414 Revision 1.423 2007/07/11 03:00:59 cheshire
415 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
416 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
418 Revision 1.422 2007/07/10 01:21:20 cheshire
419 Added (commented out) line for displaying key data for debugging
421 Revision 1.421 2007/06/25 20:58:11 cheshire
422 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
423 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
425 Revision 1.420 2007/06/22 21:52:14 cheshire
426 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
428 Revision 1.419 2007/06/22 21:32:00 cheshire
429 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
431 Revision 1.418 2007/06/21 16:37:43 jgraessley
433 Reviewed by: Stuart Cheshire
434 Additional changes to get this compiling on the embedded platform.
436 Revision 1.417 2007/06/20 01:44:00 cheshire
437 More information in "Network Configuration Change" message
439 Revision 1.416 2007/06/20 01:10:12 cheshire
440 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
442 Revision 1.415 2007/06/15 19:23:38 cheshire
443 <rdar://problem/5254053> mDNSResponder renames my host without asking
444 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
446 Revision 1.414 2007/05/17 22:00:59 cheshire
447 <rdar://problem/5210966> Lower network change delay from two seconds to one second
449 Revision 1.413 2007/05/16 16:43:27 cheshire
450 Only log "bind" failures for our shared mDNS port and for binding to zero
451 -- other attempts to bind to a particular port may legitimately fail
453 Revision 1.412 2007/05/15 21:49:21 cheshire
454 Get rid of "#pragma unused"
456 Revision 1.411 2007/05/14 23:54:55 cheshire
457 Instead of sprintf, use safer length-limited mDNS_snprintf
459 Revision 1.410 2007/05/12 01:05:00 cheshire
460 Updated debugging messages
462 Revision 1.409 2007/05/10 22:39:48 cheshire
463 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
464 Only define CountMaskBits for builds with debugging messages
466 Revision 1.408 2007/05/10 22:19:00 cheshire
467 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
468 Don't deliver multicast packets for which we can't find an associated InterfaceID
470 Revision 1.407 2007/05/10 21:40:28 cheshire
471 Don't log unnecessary "Address already in use" errors when joining multicast groups
473 Revision 1.406 2007/05/08 00:56:17 cheshire
474 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
476 Revision 1.405 2007/05/04 20:21:39 cheshire
477 Improve "connect failed" error message
479 Revision 1.404 2007/05/02 19:41:53 cheshire
480 No need to alarm people with "Connection reset by peer" syslog message
482 Revision 1.403 2007/04/28 01:31:59 cheshire
483 Improve debugging support for catching memory corruption problems
485 Revision 1.402 2007/04/26 22:54:57 cheshire
486 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
488 Revision 1.401 2007/04/26 00:35:16 cheshire
489 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
490 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
491 inside the firewall may give answers where a public one gives none, and vice versa.)
493 Revision 1.400 2007/04/24 21:50:27 cheshire
494 Debugging: Show list of changedKeys in NetworkChanged callback
496 Revision 1.399 2007/04/23 22:28:47 cheshire
497 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
499 Revision 1.398 2007/04/23 04:57:00 cheshire
500 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
502 Revision 1.397 2007/04/22 06:02:03 cheshire
503 <rdar://problem/4615977> Query should immediately return failure when no server
505 Revision 1.396 2007/04/21 21:47:47 cheshire
506 <rdar://problem/4376383> Daemon: Add watchdog timer
508 Revision 1.395 2007/04/18 20:58:34 cheshire
509 <rdar://problem/5140339> Domain discovery not working over VPN
510 Needed different code to handle the case where there's only a single search domain
512 Revision 1.394 2007/04/17 23:05:50 cheshire
513 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
515 Revision 1.393 2007/04/17 19:21:29 cheshire
516 <rdar://problem/5140339> Domain discovery not working over VPN
518 Revision 1.392 2007/04/17 17:15:09 cheshire
519 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
521 Revision 1.391 2007/04/07 01:01:48 cheshire
522 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
524 Revision 1.390 2007/04/06 18:45:02 cheshire
525 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
527 Revision 1.389 2007/04/05 21:39:49 cheshire
528 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
530 Revision 1.388 2007/04/05 21:09:52 cheshire
531 Condense sprawling code
533 Revision 1.387 2007/04/05 20:40:37 cheshire
534 Remove unused mDNSPlatformTCPGetFlags()
536 Revision 1.386 2007/04/05 19:50:56 cheshire
537 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
539 Revision 1.385 2007/04/03 19:39:19 cheshire
540 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
542 Revision 1.384 2007/03/31 01:10:53 cheshire
545 Revision 1.383 2007/03/31 00:13:48 cheshire
548 Revision 1.382 2007/03/28 21:01:29 cheshire
549 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
551 Revision 1.381 2007/03/28 15:56:37 cheshire
552 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
554 Revision 1.380 2007/03/26 22:54:46 cheshire
557 Revision 1.379 2007/03/22 18:31:48 cheshire
558 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
560 Revision 1.378 2007/03/22 00:49:20 cheshire
561 <rdar://problem/4848295> Advertise model information via Bonjour
563 Revision 1.377 2007/03/21 00:30:05 cheshire
564 <rdar://problem/4789455> Multiple errors in DNameList-related code
566 Revision 1.376 2007/03/20 17:07:15 cheshire
567 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
569 Revision 1.375 2007/03/20 00:50:57 cheshire
570 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
572 Revision 1.374 2007/03/06 23:29:50 cheshire
573 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
575 Revision 1.373 2007/02/28 01:51:20 cheshire
576 Added comment about reverse-order IP address
578 Revision 1.372 2007/02/28 01:06:48 cheshire
579 Use %#a format code instead of %d.%d.%d.%d
581 Revision 1.371 2007/02/08 21:12:28 cheshire
582 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
584 Revision 1.370 2007/01/16 22:59:58 cheshire
585 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
587 Revision 1.369 2007/01/10 02:09:32 cheshire
588 Better LogOperation record of keys read from System Keychain
590 Revision 1.368 2007/01/10 01:25:31 cheshire
591 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
593 Revision 1.367 2007/01/10 01:22:01 cheshire
594 Make sure c1, c2, c3 are initialized
596 Revision 1.366 2007/01/09 22:37:20 cheshire
597 Provide ten-second grace period for deleted keys, to give mDNSResponder
598 time to delete host name before it gives up access to the required key.
600 Revision 1.365 2007/01/09 21:09:20 cheshire
601 Need locking in KeychainChanged()
603 Revision 1.364 2007/01/09 20:17:04 cheshire
604 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
606 Revision 1.363 2007/01/09 02:41:18 cheshire
607 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
608 moved it to mDNS_Init() in mDNS.c (core code)
610 Revision 1.362 2007/01/08 23:54:01 cheshire
611 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
613 Revision 1.361 2007/01/05 08:30:48 cheshire
614 Trim excessive "$Log" checkin history from before 2006
615 (checkin history still available via "cvs log ..." of course)
617 Revision 1.360 2007/01/04 00:12:24 cheshire
618 <rdar://problem/4742742> Read *all* DNS keys from keychain,
619 not just key for the system-wide default registration domain
621 Revision 1.359 2006/12/22 21:14:37 cheshire
622 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
623 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
625 Revision 1.358 2006/12/22 20:59:50 cheshire
626 <rdar://problem/4742742> Read *all* DNS keys from keychain,
627 not just key for the system-wide default registration domain
629 Revision 1.357 2006/12/21 00:09:45 cheshire
630 Use mDNSPlatformMemZero instead of bzero
632 Revision 1.356 2006/12/20 23:15:53 mkrochma
633 Fix the private domain list code so that it actually works
635 Revision 1.355 2006/12/20 23:04:36 mkrochma
636 Fix crash when adding private domain list to Dynamic Store
638 Revision 1.354 2006/12/19 22:43:55 cheshire
639 Fix compiler warnings
641 Revision 1.353 2006/12/14 22:08:29 cheshire
642 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
643 to release data allocated by SecKeychainItemCopyAttributesAndData()
645 Revision 1.352 2006/12/14 02:33:26 cheshire
646 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
648 Revision 1.351 2006/11/28 21:37:51 mkrochma
649 Tweak where the private DNS data is written
651 Revision 1.350 2006/11/28 07:55:02 herscher
652 <rdar://problem/4742743> dnsextd has a slow memory leak
654 Revision 1.349 2006/11/28 07:45:58 herscher
655 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
657 Revision 1.348 2006/11/16 21:47:20 mkrochma
658 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
660 Revision 1.347 2006/11/10 00:54:16 cheshire
661 <rdar://problem/4816598> Changing case of Computer Name doesn't work
663 Revision 1.346 2006/10/31 02:34:58 cheshire
664 <rdar://problem/4692130> Stop creating HINFO records
666 Revision 1.345 2006/09/21 20:04:38 mkrochma
667 Accidently changed function name while checking in previous fix
669 Revision 1.344 2006/09/21 19:04:13 mkrochma
670 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
672 Revision 1.343 2006/09/15 21:20:16 cheshire
673 Remove uDNS_info substructure from mDNS_struct
675 Revision 1.342 2006/08/16 00:31:50 mkrochma
676 <rdar://problem/4386944> Get rid of NotAnInteger references
678 Revision 1.341 2006/08/14 23:24:40 cheshire
679 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
681 Revision 1.340 2006/07/29 19:11:13 mkrochma
682 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
684 Revision 1.339 2006/07/27 03:24:35 cheshire
685 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
686 Further refinement: Declare KQueueEntry parameter "const"
688 Revision 1.338 2006/07/27 02:59:25 cheshire
689 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
690 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
691 after releasing BigMutex, in case actions it took have resulted in new work for the
692 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
693 add new active interfaces to its list, and consequently schedule queries to be sent).
695 Revision 1.337 2006/07/22 06:11:37 cheshire
696 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
698 Revision 1.336 2006/07/15 02:01:32 cheshire
699 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
700 Fix broken "empty string" browsing
702 Revision 1.335 2006/07/14 05:25:11 cheshire
703 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
704 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
706 Revision 1.334 2006/07/05 23:42:00 cheshire
707 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
709 Revision 1.333 2006/06/29 05:33:30 cheshire
710 <rdar://problem/4607043> mDNSResponder conditional compilation options
712 Revision 1.332 2006/06/28 09:10:36 cheshire
713 Extra debugging messages
715 Revision 1.331 2006/06/21 22:29:42 cheshire
716 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
718 Revision 1.330 2006/06/20 23:06:00 cheshire
719 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
721 Revision 1.329 2006/06/08 23:22:33 cheshire
724 Revision 1.328 2006/03/19 03:27:49 cheshire
725 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
727 Revision 1.327 2006/03/19 02:00:09 cheshire
728 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
730 Revision 1.326 2006/03/08 22:42:23 cheshire
731 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
733 Revision 1.325 2006/01/10 00:39:17 cheshire
734 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
736 Revision 1.324 2006/01/09 19:28:59 cheshire
737 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
739 Revision 1.323 2006/01/05 21:45:27 cheshire
740 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
742 Revision 1.322 2006/01/05 21:41:50 cheshire
743 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
745 Revision 1.321 2006/01/05 21:35:06 cheshire
746 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
750 // ***************************************************************************
752 // Supporting routines to run mDNS on a CFRunLoop platform
753 // ***************************************************************************
755 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
756 // including ones that mDNSResponder chooses not to use.
757 #define LIST_ALL_INTERFACES 0
759 // For enabling AAAA records over IPv4. Setting this to 0 sends only
760 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
761 // AAAA and A records over both IPv4 and IPv6.
762 #define AAAA_OVER_V4 1
764 // 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
765 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
766 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
767 // 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.
768 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
769 // so were willing to make that sacrifice.
770 // In Mac OS X 10.5, in 2007, two things have changed:
771 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
772 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
774 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
776 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
777 #include "DNSCommon.h"
779 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
780 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
781 #include "PlatformCommon.h"
784 #include <stdarg.h> // For va_list support
786 #include <net/if_types.h> // For IFT_ETHER
787 #include <net/if_dl.h>
789 #include <sys/param.h>
790 #include <sys/socket.h>
791 #include <sys/sysctl.h>
792 #include <sys/event.h>
794 #include <sys/ioctl.h>
795 #include <time.h> // platform support for UTC time
796 #include <arpa/inet.h> // for inet_aton
799 #include <netinet/in.h> // For IP_RECVTTL
801 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
804 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
805 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
806 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
807 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
809 #if TARGET_OS_EMBEDDED
810 #define NO_SECURITYFRAMEWORK 1
811 #define NO_CFUSERNOTIFICATION 1
814 #ifndef NO_SECURITYFRAMEWORK
815 #include <Security/SecureTransport.h>
816 #include <Security/Security.h>
817 #endif /* NO_SECURITYFRAMEWORK */
819 #include <DebugServices.h>
822 // Code contributed by Dave Heller:
823 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
824 // work on Mac OS X 10.1, which does not have the getifaddrs call.
825 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
826 #if RUN_ON_PUMA_WITHOUT_IFADDRS
827 #include "mDNSMacOSXPuma.c"
832 #include <IOKit/IOKitLib.h>
833 #include <IOKit/IOMessage.h>
834 #include <mach/mach_error.h>
835 #include <mach/mach_port.h>
836 #include <mach/mach_time.h>
839 #define kInterfaceSpecificOption "interface="
841 // ***************************************************************************
844 #if COMPILER_LIKES_PRAGMA_MARK
845 #pragma mark - Globals
848 mDNSexport
int KQueueFD
;
850 #ifndef NO_SECURITYFRAMEWORK
851 static CFArrayRef ServerCerts
;
852 #endif /* NO_SECURITYFRAMEWORK */
854 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
856 CFStringRef NetworkChangedKey_IPv4
;
857 CFStringRef NetworkChangedKey_IPv6
;
858 CFStringRef NetworkChangedKey_Hostnames
;
859 CFStringRef NetworkChangedKey_Computername
;
860 CFStringRef NetworkChangedKey_DNS
;
861 CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
862 CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
864 // ***************************************************************************
867 #if COMPILER_LIKES_PRAGMA_MARK
869 #pragma mark - Utility Functions
872 // We only attempt to send and receive multicast packets on interfaces that are
873 // (a) flagged as multicast-capable
874 // (b) *not* flagged as point-to-point (e.g. modem)
875 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
876 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
877 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
878 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
880 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
882 static int notifyCount
= 0;
883 if (notifyCount
) return;
885 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
886 // To avoid this, we don't try to display alerts in the first three minutes after boot.
887 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
889 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
892 // Determine if we're at Apple (17.*.*.*)
893 extern mDNS mDNSStorage
;
894 NetworkInterfaceInfoOSX
*i
;
895 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
896 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
898 if (!i
) return; // If not at Apple, don't show the alert
904 // Display a notification to the user
907 #ifndef NO_CFUSERNOTIFICATION
908 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.)";
909 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
910 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
911 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
912 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
913 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
914 #endif /* NO_CFUSERNOTIFICATION */
917 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
919 static struct ifaddrs
*ifa
= NULL
;
927 if (ifa
== NULL
) getifaddrs(&ifa
);
932 // To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
933 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
935 NetworkInterfaceInfoOSX
*i
;
936 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
937 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
938 ((type
== AF_UNSPEC
) ||
939 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
940 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
944 mDNSlocal
int myIfIndexToName(u_short ifindex
, char *name
)
947 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
948 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
949 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== ifindex
)
950 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
954 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 ifindex
)
956 NetworkInterfaceInfoOSX
*i
;
957 if (ifindex
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
958 if (ifindex
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
960 // Don't get tricked by inactive interfaces with no InterfaceID set
961 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
962 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) return(i
->ifinfo
.InterfaceID
);
964 // Not found. Make sure our interface list is up to date, then try again.
965 LogOperation("InterfaceID for interface index %d not found; Updating interface list", ifindex
);
966 mDNSMacOSXNetworkChanged(m
);
967 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
968 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) return(i
->ifinfo
.InterfaceID
);
973 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
975 NetworkInterfaceInfoOSX
*i
;
976 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
977 if (id
== mDNSInterface_Any
) return(0);
979 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
980 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
981 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
983 // Not found. Make sure our interface list is up to date, then try again.
984 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id
);
985 mDNSMacOSXNetworkChanged(m
);
986 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
987 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
992 #if COMPILER_LIKES_PRAGMA_MARK
994 #pragma mark - UDP & TCP send & receive
997 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
999 mDNSBool result
= mDNSfalse
;
1000 SCNetworkConnectionFlags flags
;
1001 SCNetworkReachabilityRef ReachRef
= NULL
;
1003 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
1004 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
1005 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
1006 result
= flags
& kSCNetworkFlagsConnectionRequired
;
1009 if (ReachRef
) CFRelease(ReachRef
);
1013 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
1014 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
1015 // OR send via our primary v4 unicast socket
1016 // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
1017 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
1018 mDNSInterfaceID InterfaceID
, UDPSocket
*src
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
1020 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
1021 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
1022 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
1023 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
1024 char *ifa_name
= info
? info
->ifa_name
: "unicast";
1025 struct sockaddr_storage to
;
1027 mStatus result
= mStatus_NoError
;
1029 if (dst
->type
== mDNSAddrType_IPv4
)
1031 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
1032 sin_to
->sin_len
= sizeof(*sin_to
);
1033 sin_to
->sin_family
= AF_INET
;
1034 sin_to
->sin_port
= dstPort
.NotAnInteger
;
1035 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1036 s
= m
->p
->permanentsockets
.sktv4
;
1038 if (src
) { s
= src
->ss
.sktv4
; debugf("mDNSPlatformSendUDP using port %d %d %d", mDNSVal16(src
->ss
.port
), m
->p
->permanentsockets
.sktv4
, s
); }
1040 if (info
) // Specify outgoing interface
1042 if (!mDNSAddrIsDNSMulticast(dst
))
1044 #ifdef IP_FORCE_OUT_IFP
1045 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, ifa_name
, strlen(ifa_name
) + 1);
1048 static int displayed
= 0;
1049 if (displayed
< 1000)
1052 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
1059 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
1060 if (err
< 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
1064 else if (dst
->type
== mDNSAddrType_IPv6
)
1066 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
1067 sin6_to
->sin6_len
= sizeof(*sin6_to
);
1068 sin6_to
->sin6_family
= AF_INET6
;
1069 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
1070 sin6_to
->sin6_flowinfo
= 0;
1071 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
1072 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
1073 s
= m
->p
->permanentsockets
.sktv6
;
1074 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
1076 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
1077 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
));
1082 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
1086 return mStatus_BadParamErr
;
1089 // Don't send if it would cause dial-on-demand connection initiation.
1090 // As an optimization, don't bother consulting reachability API / routing
1091 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
1092 if (!info
&& !mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
1094 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
1095 return mStatus_NoError
;
1099 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
1100 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
1102 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1103 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1105 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1106 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1107 if (s
< 0) return(mStatus_Invalid
);
1109 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1112 static int MessageCount
= 0;
1113 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1114 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1115 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1116 // Don't report EHOSTUNREACH in the first three minutes after boot
1117 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1118 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1119 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1120 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1121 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1122 if (MessageCount
< 1000)
1125 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1126 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1128 result
= mStatus_UnknownErr
;
1131 #ifdef IP_FORCE_OUT_IFP
1132 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1133 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, "", 1);
1139 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1140 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1142 static unsigned int numLogMessages
= 0;
1143 struct iovec databuffers
= { (char *)buffer
, max
};
1146 struct cmsghdr
*cmPtr
;
1147 char ancillary
[1024];
1149 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1151 // Set up the message
1152 msg
.msg_name
= (caddr_t
)from
;
1153 msg
.msg_namelen
= *fromlen
;
1154 msg
.msg_iov
= &databuffers
;
1156 msg
.msg_control
= (caddr_t
)&ancillary
;
1157 msg
.msg_controllen
= sizeof(ancillary
);
1161 n
= recvmsg(s
, &msg
, 0);
1164 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1167 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1169 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1170 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1173 if (msg
.msg_flags
& MSG_CTRUNC
)
1175 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1179 *fromlen
= msg
.msg_namelen
;
1181 // Parse each option out of the ancillary data.
1182 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1184 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1185 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1187 dstaddr
->type
= mDNSAddrType_IPv4
;
1188 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1189 //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
1191 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1193 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1194 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1196 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1197 ifname
[sdl
->sdl_nlen
] = 0;
1198 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1201 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1202 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1203 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1205 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1206 dstaddr
->type
= mDNSAddrType_IPv6
;
1207 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1208 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1210 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1211 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1217 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1219 KQSocketSet
*const ss
= (KQSocketSet
*)context
;
1220 mDNS
*const m
= ss
->m
;
1221 int err
= 0, count
= 0, closed
= 0;
1223 if (filter
!= EVFILT_READ
)
1224 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1226 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
1228 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1229 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1230 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1235 mDNSAddr senderAddr
, destAddr
;
1236 mDNSIPPort senderPort
;
1237 struct sockaddr_storage from
;
1238 size_t fromlen
= sizeof(from
);
1239 char packetifname
[IF_NAMESIZE
] = "";
1241 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1245 if (from
.ss_family
== AF_INET
)
1247 struct sockaddr_in
*s
= (struct sockaddr_in
*)&from
;
1248 senderAddr
.type
= mDNSAddrType_IPv4
;
1249 senderAddr
.ip
.v4
.NotAnInteger
= s
->sin_addr
.s_addr
;
1250 senderPort
.NotAnInteger
= s
->sin_port
;
1251 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1253 else if (from
.ss_family
== AF_INET6
)
1255 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1256 senderAddr
.type
= mDNSAddrType_IPv6
;
1257 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1258 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1259 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1263 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1267 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1268 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1269 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1270 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1271 // When going to sleep we deregister all our interfaces, but if the machine
1272 // takes a few seconds to sleep we may continue to receive multicasts
1273 // during that time, which would confuse mDNSCoreReceive, because as far
1274 // as it's concerned, we should have no active interfaces any more.
1275 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1276 if (intf
) InterfaceID
= intf
->InterfaceID
;
1277 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1279 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1280 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1282 // mDNSCoreReceive may close the socket we're reading from. We must break out of our
1283 // loop when that happens, or we may try to read from an invalid FD. We do this by
1284 // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
1285 // if it closes the socketset.
1286 ss
->closeFlag
= &closed
;
1288 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, ss
->port
, InterfaceID
);
1290 // if we didn't close, we can safely dereference the socketset, and should to
1291 // reset the closeFlag, since it points to something on the stack
1292 if (!closed
) ss
->closeFlag
= mDNSNULL
;
1295 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1297 // Something is busted here.
1298 // kqueue says there is a packet, but myrecvfrom says there is not.
1299 // Try calling select() to get another opinion.
1300 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1301 // All of this is racy, as data may have arrived after the call to select()
1302 static unsigned int numLogMessages
= 0;
1303 int save_errno
= errno
;
1307 socklen_t solen
= sizeof(int);
1309 struct timeval timeout
;
1312 FD_SET(s1
, &readfds
);
1314 timeout
.tv_usec
= 0;
1315 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1316 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1317 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1318 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1319 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1320 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1321 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1322 if (numLogMessages
++ < 100)
1323 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1324 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1325 if (numLogMessages
> 5)
1326 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1327 "Congratulations, you've reproduced an elusive bug.\r"
1328 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1329 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1330 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1332 sleep(1); // After logging this error, rate limit so we don't flood syslog
1336 // TCP socket support
1338 struct TCPSocket_struct
1340 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1341 TCPConnectionCallback callback
;
1343 KQueueEntry kqEntry
;
1344 #ifndef NO_SECURITYFRAMEWORK
1345 SSLContextRef tlsContext
;
1346 #endif /* NO_SECURITYFRAMEWORK */
1349 mDNSBool handshakecomplete
;
1353 #ifndef NO_SECURITYFRAMEWORK
1355 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1357 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1358 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1359 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1361 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1362 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1363 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1364 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno
, strerror(errno
));
1365 return(errSSLClosedAbort
);
1368 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1370 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1371 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1372 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1374 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1375 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1376 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1377 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno
, strerror(errno
));
1378 return(errSSLClosedAbort
);
1381 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1383 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1384 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1386 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1387 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1389 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1390 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1395 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1397 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1398 const domainname
*d1
= mDNSNULL
; // TLD
1399 const domainname
*d2
= mDNSNULL
; // SLD
1400 const domainname
*d3
= mDNSNULL
;
1401 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1402 return(d3
&& SameDomainName(d3
, mmc
));
1405 #endif /* NO_SECURITYFRAMEWORK */
1407 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1409 TCPSocket
*sock
= context
;
1410 mStatus err
= mStatus_NoError
;
1412 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1413 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1414 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1415 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, &sock
->kqEntry
);
1417 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1419 #ifndef NO_SECURITYFRAMEWORK
1420 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1421 if (!sock
->handshakecomplete
)
1423 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1424 err
= SSLHandshake(sock
->tlsContext
);
1425 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1426 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1427 else if (err
== errSSLWouldBlock
) return;
1428 else { LogMsg("KQ SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1431 err
= mStatus_UnsupportedErr
;
1432 #endif /* NO_SECURITYFRAMEWORK */
1435 mDNSBool c
= !sock
->connected
;
1436 sock
->connected
= mDNStrue
;
1437 sock
->callback(sock
, sock
->context
, c
, err
);
1438 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1441 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1443 struct kevent new_event
;
1444 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1445 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1448 mDNSexport
void KQueueLock(mDNS
*const m
)
1450 pthread_mutex_lock(&m
->p
->BigMutex
);
1451 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1454 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1456 mDNSs32 end
= mDNSPlatformRawTime();
1458 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1459 LogOperation("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1461 pthread_mutex_unlock(&m
->p
->BigMutex
);
1464 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1465 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno
, strerror(errno
));
1468 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1472 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1473 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1475 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1476 sock
->callback
= mDNSNULL
;
1477 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
1478 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1479 sock
->kqEntry
.KQcontext
= sock
;
1480 sock
->kqEntry
.KQtask
= "mDNSPlatformTCPSocket";
1481 sock
->flags
= flags
;
1482 sock
->context
= mDNSNULL
;
1483 sock
->setup
= mDNSfalse
;
1484 sock
->handshakecomplete
= mDNSfalse
;
1485 sock
->connected
= mDNSfalse
;
1489 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1490 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1495 struct sockaddr_in addr
;
1496 memset(&addr
, 0, sizeof(addr
));
1497 addr
.sin_family
= AF_INET
;
1498 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1499 addr
.sin_port
= port
->NotAnInteger
;
1500 if (bind(sock
->fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
1501 { LogMsg("ERROR: bind %s", strerror(errno
)); goto error
; }
1503 // Receive interface identifiers
1504 const int on
= 1; // "on" for setsockopt
1505 if (setsockopt(sock
->fd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1506 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); goto error
; }
1508 memset(&addr
, 0, sizeof(addr
));
1509 socklen_t len
= sizeof(addr
);
1510 if (getsockname(sock
->fd
, (struct sockaddr
*) &addr
, &len
) < 0)
1511 { LogMsg("getsockname - %s", strerror(errno
)); goto error
; }
1513 port
->NotAnInteger
= addr
.sin_port
;
1518 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1522 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1523 TCPConnectionCallback callback
, void *context
)
1525 struct sockaddr_in saddr
;
1526 mStatus err
= mStatus_NoError
;
1528 sock
->callback
= callback
;
1529 sock
->context
= context
;
1530 sock
->setup
= mDNSfalse
;
1531 sock
->handshakecomplete
= mDNSfalse
;
1532 sock
->connected
= mDNSfalse
;
1534 (void) InterfaceID
; //!!!KRS use this if non-zero!!!
1536 if (dst
->type
!= mDNSAddrType_IPv4
)
1538 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1539 return mStatus_UnknownErr
;
1542 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1543 saddr
.sin_family
= AF_INET
;
1544 saddr
.sin_port
= dstport
.NotAnInteger
;
1545 saddr
.sin_len
= sizeof(saddr
);
1546 saddr
.sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1548 // Don't send if it would cause dial-on-demand connection initiation.
1549 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1551 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1552 return mStatus_UnknownErr
;
1555 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1556 sock
->kqEntry
.KQcontext
= sock
;
1557 sock
->kqEntry
.KQtask
= "Outgoing TCP";
1559 // Watch for connect complete (write is ready)
1560 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1561 if (KQueueSet(sock
->fd
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, &sock
->kqEntry
))
1563 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1568 // Watch for incoming data
1569 if (KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
))
1571 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1572 close(sock
->fd
); // Closing the descriptor removes all filters from the kqueue
1576 if (fcntl(sock
->fd
, F_SETFL
, fcntl(sock
->fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1578 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1579 return mStatus_UnknownErr
;
1582 // initiate connection wth peer
1583 if (connect(sock
->fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1585 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1586 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock
->fd
, errno
, strerror(errno
));
1588 return mStatus_ConnFailed
;
1591 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1592 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1596 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1597 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1599 mStatus err
= mStatus_NoError
;
1601 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1602 if (!sock
) return(mDNSNULL
);
1604 memset(sock
, 0, sizeof(*sock
));
1606 sock
->flags
= flags
;
1608 if (flags
& kTCPSocketFlags_UseTLS
)
1610 #ifndef NO_SECURITYFRAMEWORK
1611 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1613 err
= tlsSetupSock(sock
, mDNStrue
);
1614 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1616 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1617 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1619 err
= mStatus_UnsupportedErr
;
1620 #endif /* NO_SECURITYFRAMEWORK */
1622 #ifndef NO_SECURITYFRAMEWORK
1626 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1630 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1634 #ifndef NO_SECURITYFRAMEWORK
1635 if (sock
->tlsContext
)
1637 SSLClose(sock
->tlsContext
);
1638 SSLDisposeContext(sock
->tlsContext
);
1639 sock
->tlsContext
= NULL
;
1641 #endif /* NO_SECURITYFRAMEWORK */
1644 shutdown(sock
->fd
, 2);
1649 freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock
);
1653 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1656 *closed
= mDNSfalse
;
1658 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1660 #ifndef NO_SECURITYFRAMEWORK
1661 if (!sock
->handshakecomplete
)
1663 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1664 mStatus err
= SSLHandshake(sock
->tlsContext
);
1665 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1666 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1667 else if (err
== errSSLWouldBlock
) return(0);
1668 else { LogMsg("Read SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1671 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1672 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t*)&nread
);
1673 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1674 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1675 else if (err
&& err
!= errSSLWouldBlock
)
1676 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1680 #endif /* NO_SECURITYFRAMEWORK */
1684 static int CLOSEDcount
= 0;
1685 static int EAGAINcount
= 0;
1686 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1688 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
1689 else if (nread
== 0)
1692 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
1694 // else nread is negative -- see what kind of error we got
1695 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1696 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno
, strerror(errno
)); nread
= -1; }
1697 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1700 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1707 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1711 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1713 #ifndef NO_SECURITYFRAMEWORK
1715 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1717 if (!err
) nsent
= (int) processed
;
1718 else if (err
== errSSLWouldBlock
) nsent
= 0;
1719 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1722 #endif /* NO_SECURITYFRAMEWORK */
1726 nsent
= send(sock
->fd
, msg
, len
, 0);
1729 if (errno
== EAGAIN
) nsent
= 0;
1730 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1737 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1742 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1743 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1744 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
, mDNSIPPort
*const outport
)
1746 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1747 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1748 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1750 const int twofivefive
= 255;
1751 mStatus err
= mStatus_NoError
;
1752 char *errstr
= mDNSNULL
;
1754 cp
->closeFlag
= mDNSNULL
;
1756 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1757 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1759 // ... with a shared UDP port, if it's for multicast receiving
1760 if (mDNSSameIPPort(port
, MulticastDNSPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1761 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1763 if (sa_family
== AF_INET
)
1765 // We want to receive destination addresses
1766 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1767 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1769 // We want to receive interface identifiers
1770 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1771 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1773 // We want to receive packet TTL value so we can check it
1774 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1775 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1777 // Send unicast packets with TTL 255
1778 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1779 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1781 // And multicast packets with TTL 255 too
1782 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1783 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1785 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1786 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1787 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1789 // And start listening for packets
1790 struct sockaddr_in listening_sockaddr
;
1791 listening_sockaddr
.sin_family
= AF_INET
;
1792 listening_sockaddr
.sin_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
1793 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1794 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1795 if (err
) { errstr
= "bind"; goto fail
; }
1796 if (outport
) outport
->NotAnInteger
= listening_sockaddr
.sin_port
;
1798 else if (sa_family
== AF_INET6
)
1800 // We want to receive destination addresses and receive interface identifiers
1801 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1802 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1804 // We want to receive packet hop count value so we can check it
1805 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1806 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1808 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1809 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1810 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1811 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1813 // Send unicast packets with TTL 255
1814 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1815 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1817 // And multicast packets with TTL 255 too
1818 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1819 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1821 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1823 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1824 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1825 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1826 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1829 // Want to receive our own packets
1830 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1831 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1833 // And start listening for packets
1834 struct sockaddr_in6 listening_sockaddr6
;
1835 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1836 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1837 listening_sockaddr6
.sin6_family
= AF_INET6
;
1838 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
; // Pass in opaque ID without any byte swapping
1839 listening_sockaddr6
.sin6_flowinfo
= 0;
1840 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
1841 listening_sockaddr6
.sin6_scope_id
= 0;
1842 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1843 if (err
) { errstr
= "bind"; goto fail
; }
1844 if (outport
) outport
->NotAnInteger
= listening_sockaddr6
.sin6_port
;
1847 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1848 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
1850 k
->KQcallback
= myKQSocketCallBack
;
1852 k
->KQtask
= "UDP packet reception";
1853 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
1858 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1859 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
1860 LogMsg("%s skt %d port %d error %ld errno %d (%s)", errstr
, skt
, mDNSVal16(port
), err
, errno
, strerror(errno
));
1862 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1863 if (!strcmp(errstr
, "bind") && mDNSSameIPPort(port
, MulticastDNSPort
) && errno
== EADDRINUSE
)
1864 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1865 "Congratulations, you've reproduced an elusive bug.\r"
1866 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1867 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1868 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1874 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort requestedport
)
1878 mDNSIPPort port
= requestedport
;
1879 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
1880 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
1881 memset(p
, 0, sizeof(UDPSocket
));
1882 p
->ss
.port
= zeroIPPort
;
1887 for (i
=0; i
<10000; i
++) // Try at most 10000 times to get a unique random port
1889 // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
1890 if (mDNSIPPortIsZero(requestedport
)) port
= mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
1891 err
= SetupSocket(&p
->ss
, port
, AF_INET
, &p
->ss
.port
);
1896 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1897 // of failing to bind to this port when Internet Sharing has already bound to it
1898 if (mDNSSameIPPort(requestedport
, NATPMPPort
))
1899 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
1900 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport
), err
, errno
, strerror(errno
));
1901 freeL("UDPSocket", p
);
1907 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1909 if (ss
->sktv4
!= -1)
1914 if (ss
->sktv6
!= -1)
1919 if (ss
->closeFlag
) *ss
->closeFlag
= 1;
1922 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
1924 CloseSocketSet(&sock
->ss
);
1925 freeL("UDPSocket", sock
);
1928 #if COMPILER_LIKES_PRAGMA_MARK
1930 #pragma mark - Key Management
1933 #ifndef NO_SECURITYFRAMEWORK
1934 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
1936 CFMutableArrayRef certChain
= NULL
;
1937 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
1938 SecCertificateRef cert
;
1939 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
1940 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
1943 SecPolicySearchRef searchRef
;
1944 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
1945 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
1948 SecPolicyRef policy
;
1949 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
1950 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
1953 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
1954 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
1958 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
1959 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
1962 err
= SecTrustEvaluate(trust
, NULL
);
1963 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
1966 CFArrayRef rawCertChain
;
1967 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1968 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
1969 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
1972 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
1973 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
1976 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1977 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1978 CFArraySetValueAtIndex(certChain
, 0, identity
);
1979 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1980 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
1982 CFRelease(rawCertChain
);
1983 // Do not free statusChain:
1984 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1985 // certChain: Call the CFRelease function to release this object when you are finished with it.
1986 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1991 CFRelease(wrappedCert
);
1995 CFRelease(searchRef
);
2001 #endif /* NO_SECURITYFRAMEWORK */
2003 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
2005 #ifdef NO_SECURITYFRAMEWORK
2006 return mStatus_UnsupportedErr
;
2008 SecIdentityRef identity
= nil
;
2009 SecIdentitySearchRef srchRef
= nil
;
2012 // search for "any" identity matching specified key use
2013 // In this app, we expect there to be exactly one
2014 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
2015 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
2017 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
2018 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
2020 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
2021 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
2023 // Found one. Call getCertChain to create the correct certificate chain.
2024 ServerCerts
= GetCertChain(identity
);
2025 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
2027 return mStatus_NoError
;
2028 #endif /* NO_SECURITYFRAMEWORK */
2031 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
2033 #ifndef NO_SECURITYFRAMEWORK
2034 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
2035 #endif /* NO_SECURITYFRAMEWORK */
2038 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
2039 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
2041 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
2042 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
2045 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2050 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
2051 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
2053 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
2056 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
2061 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
2064 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
2065 if (!state
) return mDNSfalse
;
2066 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
2067 return val
? mDNStrue
: mDNSfalse
;
2070 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
2072 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
2074 if (sa
->sa_family
== AF_INET
)
2076 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
2077 ip
->type
= mDNSAddrType_IPv4
;
2078 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
2079 return(mStatus_NoError
);
2082 if (sa
->sa_family
== AF_INET6
)
2084 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
2085 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
2086 // value into the second word of the IPv6 link-local address, so they can just
2087 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
2088 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
2089 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
2090 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
2091 ip
->type
= mDNSAddrType_IPv6
;
2092 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
2093 return(mStatus_NoError
);
2096 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
2097 return(mStatus_Invalid
);
2100 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
2102 mDNSEthAddr eth
= zeroEthAddr
;
2103 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
2106 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
2109 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
2112 CFRange range
= { 0, 6 }; // Offset, length
2113 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
2114 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
2117 CFRelease(entityname
);
2124 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2125 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2126 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2127 // (e.g. sa_family not AF_INET or AF_INET6)
2128 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2130 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2131 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2134 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2135 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2137 NetworkInterfaceInfoOSX
**p
;
2138 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2139 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2141 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2142 (*p
)->Exists
= mDNStrue
;
2143 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2144 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
2148 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2149 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2150 if (!i
) return(mDNSNULL
);
2151 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
2152 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2153 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2154 strcpy(i
->ifa_name
, ifa
->ifa_name
); // This is safe because we know we allocated i->ifa_name with sufficient space
2156 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2158 i
->ifinfo
.mask
= mask
;
2159 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2160 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2161 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2162 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2165 i
->Exists
= mDNStrue
;
2166 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
2168 i
->Flashing
= mDNSfalse
;
2169 i
->Occulting
= mDNSfalse
;
2170 i
->scope_id
= scope_id
;
2172 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2173 i
->ifa_flags
= ifa
->ifa_flags
;
2179 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2180 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2182 NetworkInterfaceInfoOSX
*i
;
2183 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2184 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2185 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
2191 #if APPLE_OSX_mDNSResponder
2193 #if COMPILER_LIKES_PRAGMA_MARK
2195 #pragma mark - AutoTunnel
2198 #define kRacoonPort 4500
2200 static mDNSBool AnonymousRacoonConfig
= mDNSfalse
;
2202 #ifndef NO_SECURITYFRAMEWORK
2204 static CFMutableDictionaryRef domainStatusDict
= NULL
;
2206 // MUST be called with lock held
2207 mDNSlocal
void RemoveAutoTunnelDomainStatus(const DomainAuthInfo
*const info
)
2212 LogOperation("RemoveAutoTunnelDomainStatus: %##s", info
->domain
.c
);
2214 if (!domainStatusDict
) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; }
2216 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
2217 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
2218 if (!domain
) { LogMsg("RemoveAutoTunnelDomainStatus: Could not create CFString domain"); return; }
2220 if (CFDictionaryContainsKey(domainStatusDict
, domain
))
2222 CFDictionaryRemoveValue(domainStatusDict
, domain
);
2223 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, domainStatusDict
);
2228 #endif // ndef NO_SECURITYFRAMEWORK
2230 // MUST be called with lock held
2231 mDNSlocal
void UpdateAutoTunnelDomainStatus(const mDNS
*const m
, const DomainAuthInfo
*const info
)
2233 #ifdef NO_SECURITYFRAMEWORK
2237 const NATTraversalInfo
*const llq
= m
->LLQNAT
.clientContext
? &m
->LLQNAT
: mDNSNULL
;
2238 const NATTraversalInfo
*const tun
= info
->AutoTunnelNAT
.clientContext
? &info
->AutoTunnelNAT
: mDNSNULL
;
2240 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2241 CFStringRef domain
= NULL
;
2242 CFStringRef tmp
= NULL
;
2243 CFNumberRef num
= NULL
;
2244 mStatus status
= mStatus_NoError
;
2246 if (!domainStatusDict
)
2248 domainStatusDict
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2249 if (!domainStatusDict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
2252 if (!dict
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
2254 buffer
[mDNS_snprintf(buffer
, sizeof(buffer
), "%##s", info
->domain
.c
) - 1] = 0;
2255 domain
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
2256 if (!domain
) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
2258 mDNS_snprintf(buffer
, sizeof(buffer
), "%#a", &m
->Router
);
2259 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
2261 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
2264 CFDictionarySetValue(dict
, CFSTR("RouterAddress"), tmp
);
2268 mDNS_snprintf(buffer
, sizeof(buffer
), "%.4a", &m
->ExternalAddress
);
2269 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
2271 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
2274 CFDictionarySetValue(dict
, CFSTR("ExternalAddress"), tmp
);
2280 mDNSu32 port
= mDNSVal16(llq
->ExternalPort
);
2282 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
2284 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
2287 CFDictionarySetValue(dict
, CFSTR("LLQExternalPort"), num
);
2293 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &llq
->Result
);
2295 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
2298 CFDictionarySetValue(dict
, CFSTR("LLQNPMStatus"), num
);
2306 mDNSu32 port
= mDNSVal16(tun
->ExternalPort
);
2308 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &port
);
2310 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
2313 CFDictionarySetValue(dict
, CFSTR("AutoTunnelExternalPort"), num
);
2319 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &tun
->Result
);
2321 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
2324 CFDictionarySetValue(dict
, CFSTR("AutoTunnelNPMStatus"), num
);
2332 status
= mStatus_NotInitializedErr
;
2333 mDNS_snprintf(buffer
, sizeof(buffer
), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
2335 else if ((llq
&& llq
->Result
== mStatus_DoubleNAT
) || (tun
&& tun
->Result
== mStatus_DoubleNAT
))
2337 status
= mStatus_DoubleNAT
;
2338 mDNS_snprintf(buffer
, sizeof(buffer
), "Double NAT: Router is reporting an external address");
2340 else if ((llq
&& llq
->Result
) || (tun
&& tun
->Result
))
2342 status
= mStatus_NATTraversal
;
2343 mDNS_snprintf(buffer
, sizeof(buffer
), "Error obtaining NAT port mapping from router");
2345 else if (m
->Router
.type
== mDNSAddrType_None
)
2347 status
= mStatus_NoRouter
;
2348 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - none");
2350 else if (m
->Router
.type
== mDNSAddrType_IPv4
&& mDNSIPv4AddressIsZero(m
->Router
.ip
.v4
))
2352 status
= mStatus_NoRouter
;
2353 mDNS_snprintf(buffer
, sizeof(buffer
), "No network connection - v4 zero");
2355 else if ((llq
&& mDNSIPPortIsZero(llq
->ExternalPort
)) || (tun
&& mDNSIPPortIsZero(tun
->ExternalPort
)))
2357 status
= mStatus_NATTraversal
;
2358 mDNS_snprintf(buffer
, sizeof(buffer
), "Unable to obtain NAT port mapping from router");
2363 for (q
= m
->Questions
; q
; q
=q
->next
)
2364 if (q
->LongLived
&& q
->AuthInfo
== info
&& q
->state
== LLQ_Poll
)
2366 status
= mStatus_PollingMode
;
2367 mDNS_snprintf(buffer
, sizeof(buffer
), "Query polling %##s", q
->qname
.c
);
2370 if (status
== mStatus_NoError
)
2371 for (q
= m
->Questions
; q
; q
=q
->next
)
2372 if (q
->LongLived
&& q
->AuthInfo
== info
&& q
->state
!= LLQ_Established
&& !q
->DuplicateOf
)
2374 status
= mStatus_TransientErr
;
2375 mDNS_snprintf(buffer
, sizeof(buffer
), "Query not yet established %##s", q
->qname
.c
);
2378 if (status
== mStatus_NoError
) mDNS_snprintf(buffer
, sizeof(buffer
), "Success");
2381 num
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
);
2383 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
2386 CFDictionarySetValue(dict
, CFSTR("StatusCode"), num
);
2390 tmp
= CFStringCreateWithCString(NULL
, buffer
, kCFStringEncodingUTF8
);
2392 LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
2395 CFDictionarySetValue(dict
, CFSTR("StatusMessage"), tmp
);
2399 if (!CFDictionaryContainsKey(domainStatusDict
, domain
) ||
2400 !CFEqual(dict
, (CFMutableDictionaryRef
)CFDictionaryGetValue(domainStatusDict
, domain
)))
2402 CFDictionarySetValue(domainStatusDict
, domain
, dict
);
2403 mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig
, domainStatusDict
);
2409 LogOperation("UpdateAutoTunnelDomainStatus: %s", buffer
);
2410 #endif // def NO_SECURITYFRAMEWORK
2413 // MUST be called with lock held
2414 mDNSexport
void UpdateAutoTunnelDomainStatuses(const mDNS
*const m
)
2416 #ifdef NO_SECURITYFRAMEWORK
2419 DomainAuthInfo
* info
;
2420 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2421 if (info
->AutoTunnel
&& !info
->deltime
)
2422 UpdateAutoTunnelDomainStatus(m
, info
);
2423 #endif // def NO_SECURITYFRAMEWORK
2426 // MUST be called with lock held
2427 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
2429 ServiceRecordSet
*p
;
2430 for (p
= m
->ServiceRegistrations
; p
; p
= p
->uDNS_next
)
2432 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, p
->RR_SRV
.resrec
.name
);
2433 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
2438 // MUST be called with lock held
2439 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
2442 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
2443 if (p
->q
.ThisQInterval
< 0)
2448 mDNSlocal
void RegisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2450 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && AutoTunnelUnregistered(info
))
2453 LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
2455 // 1. Set up our address record for the internal tunnel address
2456 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2457 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
2458 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
2459 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
2460 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
2461 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2462 err
= mDNS_Register(m
, &info
->AutoTunnelHostRecord
);
2463 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2465 // 2. Set up device info record
2466 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
2467 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
2468 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
2469 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
2470 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
2471 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
2472 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2473 err
= mDNS_Register(m
, &info
->AutoTunnelDeviceInfo
);
2474 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2476 // 3. Set up our address record for the external tunnel address
2477 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2478 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
2479 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
2480 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
2481 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2484 mDNS_AddDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
, mDNSNULL
, info
);
2487 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2488 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2489 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
2490 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
2491 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
2492 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
2493 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
2494 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
2495 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2496 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
2497 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2499 LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2500 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
2501 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
2505 mDNSlocal
void DeregisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2507 LogOperation("DeregisterAutoTunnelRecords %##s", info
->domain
.c
);
2508 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2510 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
2513 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2514 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2518 mDNS_RemoveDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
);
2522 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2524 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
2527 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2528 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2532 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2534 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
2537 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2538 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2543 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2545 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
2546 if (result
== mStatus_MemFree
)
2548 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
2549 // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
2550 if (rr
== &info
->AutoTunnelHostRecord
)
2552 rr
->namestorage
.c
[0] = 0;
2553 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
2555 RegisterAutoTunnelRecords(m
,info
);
2559 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
2561 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
2562 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
2563 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
2565 m
->NextSRVUpdate
= NonZeroTime(m
->timenow
);
2566 DeregisterAutoTunnelRecords(m
,info
);
2567 RegisterAutoTunnelRecords(m
,info
);
2569 // Determine whether we need racoon to accept incoming connections
2570 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2571 if (info
->AutoTunnel
&& !info
->deltime
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
))
2573 mDNSBool needRacoonConfig
= info
!= mDNSNULL
;
2574 if (needRacoonConfig
!= AnonymousRacoonConfig
)
2576 AnonymousRacoonConfig
= needRacoonConfig
;
2577 // Create or revert configuration file, and start (or SIGHUP) Racoon
2578 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, info
? info
->b64keydata
: "");
2581 UpdateAutoTunnelDomainStatus(m
, (DomainAuthInfo
*)n
->clientContext
);
2584 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2586 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2588 LogOperation("Aborting deregistration of %s", ARDisplayString(m
, rr
));
2589 CompleteDeregistration(m
, rr
);
2591 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
2592 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
2595 // Before SetupLocalAutoTunnelInterface_internal is called,
2596 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2597 // Must be called with the lock held
2598 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
)
2600 LogOperation("SetupLocalAutoTunnelInterface");
2602 // 1. Configure the local IPv6 address
2603 if (!m
->AutoTunnelHostAddrActive
)
2605 m
->AutoTunnelHostAddrActive
= mDNStrue
;
2606 LogOperation("Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
2607 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
2610 // 2. If we have at least one server (pending) listening, publish our records
2611 if (TunnelServers(m
))
2613 DomainAuthInfo
*info
;
2614 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2616 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
2618 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
2619 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
2620 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
2621 AbortDeregistration(m
, &info
->AutoTunnelService
);
2623 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2624 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2625 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2626 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2628 // Try to get a NAT port mapping for the AutoTunnelService
2629 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
2630 info
->AutoTunnelNAT
.clientContext
= info
;
2631 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
2632 info
->AutoTunnelNAT
.IntPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2633 info
->AutoTunnelNAT
.RequestedPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2634 info
->AutoTunnelNAT
.NATLease
= 0;
2635 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
2636 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err
);
2642 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
2644 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
));
2647 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2648 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2650 mDNSlocal
void ReissueBlockedQuestionWithType(mDNS
*const m
, domainname
*d
, mDNSBool success
, mDNSu16 qtype
)
2652 DNSQuestion
*q
= m
->Questions
;
2655 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== qtype
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
2657 LogOperation("Restart %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2658 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
2659 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2660 mDNS_StopQuery(m
, q
);
2661 mDNS_StartQuery(m
, q
);
2662 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
2663 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
2664 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2665 // In general we have to assume that the question list might have changed in arbitrary ways.
2666 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2667 // already in use. The safest solution is just to go back to the start of the list and start again.
2668 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2669 // just one suspended question, so it's really a 2n algorithm.
2677 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
2679 // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
2680 // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
2681 // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
2682 // 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.
2683 // 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.
2684 ReissueBlockedQuestionWithType(m
, d
, success
, kDNSType_AAAA
);
2685 ReissueBlockedQuestionWithType(m
, d
, mDNStrue
, kDNSType_A
);
2688 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
2690 ClientTunnel
**p
= &m
->TunnelClients
;
2691 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
2692 if (*p
) *p
= tun
->next
;
2693 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
2694 LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun
);
2695 freeL("ClientTunnel", tun
);
2698 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2700 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
2701 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
2703 if (!AddRecord
) return;
2704 mDNS_StopQuery(m
, question
);
2706 if (!answer
->rdlength
)
2708 LogOperation("AutoTunnelCallback NXDOMAIN %##s (%s)", question
->qname
.c
, DNSTypeName(question
->qtype
));
2709 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
2713 if (question
->qtype
== kDNSType_AAAA
)
2715 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
2717 LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
2718 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
2722 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
2723 LogOperation("AutoTunnelCallback: dst host %.16a", &tun
->rmt_inner
);
2724 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2725 AppendDomainName(&question
->qname
, &tun
->dstname
);
2726 question
->qtype
= kDNSType_SRV
;
2727 mDNS_StartQuery(m
, &tun
->q
);
2729 else if (question
->qtype
== kDNSType_SRV
)
2731 LogOperation("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
2732 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
2733 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
2734 question
->qtype
= kDNSType_A
;
2735 mDNS_StartQuery(m
, &tun
->q
);
2737 else if (question
->qtype
== kDNSType_A
)
2739 ClientTunnel
*old
= mDNSNULL
;
2740 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer
->rdata
->u
.ipv4
);
2741 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
2742 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
2743 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
2744 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
2745 tmpDst
.ip
.v4
= tun
->rmt_outer
;
2746 mDNSAddr tmpSrc
= zeroAddr
;
2747 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
2748 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
2749 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
2751 ClientTunnel
**p
= &tun
->next
;
2752 mDNSBool needSetKeys
= mDNStrue
;
2755 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
2758 LogOperation("Found existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2761 if (old
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &old
->q
);
2762 else if (!mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
2763 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
2764 !mDNSSameIPv6Address(old
->rmt_inner
, tun
->rmt_inner
) ||
2765 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
2766 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
2768 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2769 AutoTunnelSetKeys(old
, mDNSfalse
);
2771 else needSetKeys
= mDNSfalse
;
2773 LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun
);
2774 freeL("ClientTunnel", old
);
2778 if (needSetKeys
) LogOperation("New AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2780 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
); mDNS_Unlock(m
); };
2782 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
2783 // Kick off any questions that were held pending this tunnel setup
2784 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
2787 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
2790 // Must be called with the lock held
2791 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
2793 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
2795 AssignDomainName(&p
->dstname
, &q
->qname
);
2796 p
->MarkedForDeletion
= mDNSfalse
;
2797 p
->loc_inner
= zerov6Addr
;
2798 p
->loc_outer
= zerov4Addr
;
2799 p
->rmt_inner
= zerov6Addr
;
2800 p
->rmt_outer
= zerov4Addr
;
2801 p
->rmt_outer_port
= zeroIPPort
;
2802 mDNS_snprintf(p
->b64keydata
, sizeof(p
->b64keydata
), "%s", q
->AuthInfo
->b64keydata
);
2803 p
->next
= m
->TunnelClients
;
2804 m
->TunnelClients
= p
; // We intentionally build list in reverse order
2806 p
->q
.InterfaceID
= mDNSInterface_Any
;
2807 p
->q
.Target
= zeroAddr
;
2808 AssignDomainName(&p
->q
.qname
, &q
->qname
);
2809 p
->q
.qtype
= kDNSType_AAAA
;
2810 p
->q
.qclass
= kDNSClass_IN
;
2811 p
->q
.LongLived
= mDNSfalse
;
2812 p
->q
.ExpectUnique
= mDNStrue
;
2813 p
->q
.ForceMCast
= mDNSfalse
;
2814 p
->q
.ReturnIntermed
= mDNStrue
;
2815 p
->q
.QuestionCallback
= AutoTunnelCallback
;
2816 p
->q
.QuestionContext
= p
;
2818 LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p
, &q
->qname
.c
, DNSTypeName(q
->qtype
), q
->LongLived
? " LongLived" : "");
2819 mDNS_StartQuery_internal(m
, &p
->q
);
2822 #endif // APPLE_OSX_mDNSResponder
2824 #if COMPILER_LIKES_PRAGMA_MARK
2826 #pragma mark - Power State & Configuration Change Management
2829 mDNSlocal
void GenerateDefaultName(const mDNSEthAddr PrimaryMAC
, char *buffer
, mDNSu32 length
)
2832 size_t hwNameLen
= sizeof(hwName
);
2835 if (sysctlbyname("hw.model", &hwName
, &hwNameLen
, NULL
, 0) == 0)
2837 // hw.model contains a number like iMac6,1. We want the "iMac" part.
2838 hwName
[sizeof(hwName
) - 1] = 0;
2840 for (ptr
= hwName
; *ptr
!= 0; ptr
++)
2842 if (*ptr
>= '0' && *ptr
<= '9') *ptr
= 0;
2843 if (*ptr
== ',') break;
2845 // Prototype model names do not contain commas, do not use prototype names
2846 if (*ptr
!= ',') hwName
[0] = 0;
2849 if (hwName
[0] == 0) strlcpy(hwName
, "Device", sizeof(hwName
));
2851 mDNS_snprintf(buffer
, length
, "%s-%02X%02X%02X%02X%02X%02X", hwName
,
2852 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2855 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2857 mDNSBool foundav4
= mDNSfalse
;
2858 mDNSBool foundav6
= mDNSfalse
;
2859 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2860 struct ifaddrs
*v4Loopback
= NULL
;
2861 struct ifaddrs
*v6Loopback
= NULL
;
2862 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2863 char defaultname
[64];
2865 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2866 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2868 if (m
->SleepState
) ifa
= NULL
;
2872 #if LIST_ALL_INTERFACES
2873 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2874 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2875 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2876 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2877 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2878 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2879 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2880 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2881 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2882 if (!(ifa
->ifa_flags
& IFF_UP
))
2883 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2884 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2885 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2886 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2887 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2888 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2889 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2890 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2891 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2892 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2893 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2896 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2898 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2899 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2900 mDNSPlatformMemCopy(PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
2903 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2904 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2906 if (!ifa
->ifa_netmask
)
2909 SetupAddr(&ip
, ifa
->ifa_addr
);
2910 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2911 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2913 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
2914 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
2915 else if (ifa
->ifa_netmask
->sa_family
!= ifa
->ifa_addr
->sa_family
&& ifa
->ifa_netmask
->sa_family
!= 0)
2918 SetupAddr(&ip
, ifa
->ifa_addr
);
2919 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2920 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2924 // Make sure ifa_netmask->sa_family is set correctly
2925 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
2926 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
;
2927 int ifru_flags6
= 0;
2929 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2930 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2932 struct in6_ifreq ifr6
;
2933 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
2934 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2935 ifr6
.ifr_addr
= *sin6
;
2936 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2937 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2938 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2941 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2943 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2945 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2947 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
2952 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2953 if (i
&& MulticastInterface(i
))
2955 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2956 else foundav6
= mDNStrue
;
2962 ifa
= ifa
->ifa_next
;
2965 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2966 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2967 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2969 // Now the list is complete, set the McastTxRx setting for each interface.
2970 NetworkInterfaceInfoOSX
*i
;
2971 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2974 mDNSBool txrx
= MulticastInterface(i
);
2975 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2976 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2978 if (i
->ifinfo
.McastTxRx
!= txrx
)
2980 i
->ifinfo
.McastTxRx
= txrx
;
2981 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2986 if (InfoSocket
>= 0) close(InfoSocket
);
2989 // If we haven't set up AutoTunnelHostAddr yet, do it now
2990 if (!mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
2992 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2993 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
2994 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
2995 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
2996 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
2997 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
2998 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
2999 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
3000 m
->AutoTunnelHostAddr
.b
[0x8] = PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
3001 m
->AutoTunnelHostAddr
.b
[0x9] = PrimaryMAC
.b
[1];
3002 m
->AutoTunnelHostAddr
.b
[0xA] = PrimaryMAC
.b
[2];
3003 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
3004 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
3005 m
->AutoTunnelHostAddr
.b
[0xD] = PrimaryMAC
.b
[3];
3006 m
->AutoTunnelHostAddr
.b
[0xE] = PrimaryMAC
.b
[4];
3007 m
->AutoTunnelHostAddr
.b
[0xF] = PrimaryMAC
.b
[5];
3008 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
3009 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
3010 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
3011 LogOperation("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
3014 GenerateDefaultName(PrimaryMAC
, defaultname
, sizeof(defaultname
));
3016 // Set up the nice label
3017 domainlabel nicelabel
;
3019 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
3020 if (nicelabel
.c
[0] == 0)
3022 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
3023 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
3026 // Set up the RFC 1034-compliant label
3027 domainlabel hostlabel
;
3029 GetUserSpecifiedLocalHostName(&hostlabel
);
3030 if (hostlabel
.c
[0] == 0)
3032 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
3033 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
3036 mDNSBool namechange
= mDNSfalse
;
3038 // We use a case-sensitive comparison here because even though changing the capitalization
3039 // of the name alone is not significant to DNS, it's still a change from the user's point of view
3040 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
3041 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
3044 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
3045 LogMsg("User updated Computer Name from %#s to %#s", m
->p
->usernicelabel
.c
, nicelabel
.c
);
3046 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
3047 namechange
= mDNStrue
;
3050 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
3051 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
3054 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
3055 LogMsg("User updated Local Hostname from %#s to %#s", m
->p
->userhostlabel
.c
, hostlabel
.c
);
3056 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
3058 namechange
= mDNStrue
;
3061 #if APPLE_OSX_mDNSResponder
3062 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
3064 DomainAuthInfo
*info
;
3065 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
3066 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPv4AddressIsOnes(info
->AutoTunnelNAT
.ExternalAddress
))
3067 AutoTunnelNATCallback(m
, &info
->AutoTunnelNAT
);
3071 return(mStatus_NoError
);
3074 #if LogAllOperations || MDNS_DEBUGMSGS
3075 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
3076 // Returns -1 if all the one-bits are not contiguous
3077 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
3079 int i
= 0, bits
= 0;
3080 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
3083 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
3084 while (b
& 0x80) { bits
++; b
<<= 1; }
3087 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
3092 // returns count of non-link local V4 addresses registered
3093 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
3095 NetworkInterfaceInfoOSX
*i
;
3097 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3100 NetworkInterfaceInfo
*const n
= &i
->ifinfo
;
3101 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
3102 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
3104 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
3106 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
3107 n
->InterfaceID
= mDNSNULL
;
3110 if (!n
->InterfaceID
)
3112 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
3113 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
3114 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
3115 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
3117 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
3118 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
3119 // 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.
3120 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
3122 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
3123 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
3124 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
3125 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
3126 i
->Flashing
? " (Flashing)" : "",
3127 i
->Occulting
? " (Occulting)" : "",
3128 n
->InterfaceActive
? " (Primary)" : "");
3131 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
3134 if (i
->sa_family
== AF_INET
)
3137 primary
->ifa_v4addr
.s_addr
= i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
3138 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
3139 imr
.imr_interface
= primary
->ifa_v4addr
;
3141 // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
3142 // before trying to join the group, to clear out stale kernel state which may be lingering.
3143 // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
3144 // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
3145 // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
3146 // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
3147 // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
3148 // because by the time we get the configuration change notification, the interface is already gone,
3149 // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
3150 // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
3151 if (SearchForInterfaceByName(m
, i
->ifa_name
, AF_INET
) == i
)
3153 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
);
3154 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &imr
, sizeof(imr
));
3155 if (err
< 0 && (errno
!= EADDRNOTAVAIL
|| LogAllOperations
))
3156 LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
3159 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i
->ifa_name
, i
->scope_id
, &imr
.imr_multiaddr
, &imr
.imr_interface
);
3160 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
3161 // Joining same group twice can give "Address already in use" error -- no need to report that
3162 if (err
< 0 && (errno
!= EADDRINUSE
|| LogAllOperations
))
3163 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err
, errno
, strerror(errno
), &imr
.imr_multiaddr
, &imr
.imr_interface
);
3166 if (i
->sa_family
== AF_INET6
)
3168 struct ipv6_mreq i6mr
;
3169 i6mr
.ipv6mr_interface
= primary
->scope_id
;
3170 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
3172 if (SearchForInterfaceByName(m
, i
->ifa_name
, AF_INET6
) == i
)
3174 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
);
3175 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &i6mr
, sizeof(i6mr
));
3176 if (err
< 0 && (errno
!= EADDRNOTAVAIL
|| LogAllOperations
))
3177 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
3180 LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i
->ifa_name
, i
->scope_id
, &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
3181 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
3182 // Joining same group twice can give "Address already in use" error -- no need to report that
3183 if (err
< 0 && (errno
!= EADDRINUSE
|| LogAllOperations
))
3184 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err
, errno
, strerror(errno
), &i6mr
.ipv6mr_multiaddr
, i6mr
.ipv6mr_interface
);
3193 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
3195 NetworkInterfaceInfoOSX
*i
;
3196 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3198 if (i
->Exists
) i
->LastSeen
= utc
;
3199 i
->Exists
= mDNSfalse
;
3203 // returns count of non-link local V4 addresses deregistered
3204 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
3207 // If an interface is going away, then deregister this from the mDNSCore.
3208 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
3209 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
3210 // it refers to has gone away we'll crash.
3211 NetworkInterfaceInfoOSX
*i
;
3213 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
3215 // If this interface is no longer active, or its InterfaceID is changing, deregister it
3216 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, AAAA_OVER_V4
? AF_UNSPEC
: i
->sa_family
);
3217 if (i
->ifinfo
.InterfaceID
)
3218 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
3220 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
3221 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
3222 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
3223 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
3224 i
->Flashing
? " (Flashing)" : "",
3225 i
->Occulting
? " (Occulting)" : "",
3226 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
3227 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
3228 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
3229 i
->ifinfo
.InterfaceID
= mDNSNULL
;
3230 // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
3231 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
3232 // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
3234 // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
3235 // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
3240 // Now that everything that's going to deregister has done so, we can clean up and free the memory
3241 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
3245 // If no longer active, delete interface from list and free memory
3248 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
3249 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
3250 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
3251 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
3252 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
3253 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
3257 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
3258 freeL("NetworkInterfaceInfoOSX", i
);
3259 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
3267 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
3269 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
3270 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
3273 dnle
->next
= mDNSNULL
;
3275 AssignDomainName(&dnle
->name
, name
);
3277 *List
= &dnle
->next
;
3281 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
3284 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3287 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
3288 if (fqdn
) fqdn
->c
[0] = 0;
3289 if (RegDomains
) *RegDomains
= NULL
;
3290 if (BrowseDomains
) *BrowseDomains
= NULL
;
3292 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
3293 setservers
? " setservers" : "",
3294 setsearch
? " setsearch" : "",
3295 fqdn
? " fqdn" : "",
3296 RegDomains
? " RegDomains" : "",
3297 BrowseDomains
? " BrowseDomains" : "");
3299 // Add the inferred address-based configuration discovery domains
3300 // (should really be in core code I think, not platform-specific)
3303 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3307 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
3309 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
3310 !SetupAddr(&a
, ifa
->ifa_addr
) &&
3311 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
3313 // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
3314 // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
3315 ifa
->ifa_netmask
->sa_family
= ifa
->ifa_addr
->sa_family
; // Make sure ifa_netmask->sa_family is set correctly
3316 SetupAddr(&n
, ifa
->ifa_netmask
);
3317 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
3318 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
3319 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
3320 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
3321 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
3322 mDNS_AddSearchDomain_CString(buf
);
3324 ifa
= ifa
->ifa_next
;
3328 #ifndef MDNS_NO_DNSINFO
3329 if (setservers
|| setsearch
)
3331 dns_config_t
*config
= dns_configuration_copy();
3334 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
3335 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
3336 // Apparently this is expected behaviour -- "not a bug".
3337 // Accordingly, we suppress syslog messages for the first three minutes after boot.
3338 // If we are still getting failures after three minutes, then we log them.
3339 if (mDNSMacOSXSystemBuildNumber(NULL
) > 7 && (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
3340 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
3344 LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
3347 for (i
= 0; i
< config
->n_resolver
; i
++)
3350 dns_resolver_t
*r
= config
->resolver
[i
];
3351 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
3352 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
3353 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
3354 if (r
->port
== 5353) continue;
3355 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
3356 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
3358 for (j
= 0; j
< config
->n_resolver
; j
++) // check if this is the lowest-weighted server for the domain
3360 dns_resolver_t
*p
= config
->resolver
[j
];
3361 if (p
->port
== 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
3362 if (p
->search_order
<= r
->search_order
)
3365 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
3366 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
3367 if (SameDomainName(&d
, &tmp
))
3368 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
3371 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
3372 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
);
3375 mDNSInterfaceID interface
= mDNSInterface_Any
;
3378 // DNS server option parsing
3379 if (r
->options
!= NULL
)
3381 char *nextOption
= r
->options
;
3382 char *currentOption
= NULL
;
3383 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
3385 // The option may be in the form of interface=xxx where xxx is an interface name.
3386 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
3388 NetworkInterfaceInfoOSX
*ni
;
3389 char ifname
[IF_NAMESIZE
+1];
3390 mDNSu32 ifindex
= 0;
3391 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
3392 // This allows us to block these special queries from going out on the wire.
3393 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
3394 ifindex
= if_nametoindex(ifname
);
3395 if (ifindex
== 0) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname
); continue; }
3396 LogOperation("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__
, r
->domain
, ifname
, ifindex
);
3397 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
3398 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
3399 for (ni
= m
->p
->InterfaceList
; ni
; ni
= ni
->next
)
3400 if (ni
->ifinfo
.InterfaceID
&& ni
->scope_id
== ifindex
) break;
3401 if (ni
!= NULL
) interface
= ni
->ifinfo
.InterfaceID
;
3402 if (interface
== mDNSNULL
) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex
, ifname
); continue; }
3406 for (n
= 0; n
< r
->n_nameserver
; n
++)
3407 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& (interface
|| disabled
|| !AddrRequiresPPPConnection(r
->nameserver
[n
])))
3410 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
3411 debugf("Adding dns server from slot %d %#a for domain %##s", i
, &saddr
, d
.c
);
3412 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
3415 DNSServer
*s
= mDNS_AddDNSServer(m
, &d
, interface
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
);
3416 if (s
&& disabled
) s
->teststate
= DNSServer_Disabled
;
3424 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3425 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3426 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3427 // instead use the search domain list as the sole authority for what domains to search and in what order
3428 // (and the domain from the "domain" field will also appear somewhere in that list).
3429 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
3430 // search lists for other resolvers in the list need to be ignored.
3431 if (config
->resolver
[0]->n_search
== 0) mDNS_AddSearchDomain_CString(config
->resolver
[0]->domain
);
3432 else for (i
= 0; i
< config
->resolver
[0]->n_search
; i
++) mDNS_AddSearchDomain_CString(config
->resolver
[0]->search
[i
]);
3434 dns_configuration_free(config
);
3435 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
3436 setsearch
= mDNSfalse
;
3439 #endif // MDNS_NO_DNSINFO
3441 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
3444 CFDictionaryRef ddnsdict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
3449 CFArrayRef fqdnArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("HostNames"));
3450 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
3452 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
3453 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
3454 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
3456 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
3459 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3460 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
3461 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
3462 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
3470 CFArrayRef regArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("RegistrationDomains"));
3471 if (regArray
&& CFArrayGetCount(regArray
) > 0)
3473 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
3474 if (regDict
&& DDNSSettingEnabled(regDict
))
3476 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
3479 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3480 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3481 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
3484 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
3485 AppendDNameListElem(&RegDomains
, 0, &d
);
3494 CFArrayRef browseArray
= CFDictionaryGetValue(ddnsdict
, CFSTR("BrowseDomains"));
3497 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
3499 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
3500 if (browseDict
&& DDNSSettingEnabled(browseDict
))
3502 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
3505 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3506 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3507 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
3510 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
3511 AppendDNameListElem(&BrowseDomains
, 0, &d
);
3518 CFRelease(ddnsdict
);
3523 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
3526 CFIndex size
= CFDictionaryGetCount(btmm
);
3527 const void *key
[size
];
3528 const void *val
[size
];
3529 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
3530 for (i
= 0; i
< size
; i
++)
3532 LogOperation("BackToMyMac %d", i
);
3533 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3534 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
3537 mDNSu32 uid
= atoi(buf
);
3538 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3539 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
3540 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
3542 LogOperation("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
3543 AppendDNameListElem(&RegDomains
, uid
, &d
);
3551 if (setservers
|| setsearch
)
3553 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DNS
);
3558 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
3561 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
3563 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
3564 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
3565 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
3566 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
3567 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
3573 // Add the manual and/or DHCP-dicovered search domains
3574 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
3577 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
3579 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
3580 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3581 mDNS_AddSearchDomain_CString(buf
);
3584 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3586 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3587 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3588 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3589 // instead use the search domain list as the sole authority for what domains to search and in what order
3590 // (and the domain from the "domain" field will also appear somewhere in that list).
3591 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
3592 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3593 mDNS_AddSearchDomain_CString(buf
);
3603 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
3609 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
3610 if (!store
) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed");
3613 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_IPv4
);
3616 r
->type
= mDNSAddrType_IPv4
;
3617 r
->ip
.v4
= zerov4Addr
;
3618 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3621 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
3622 LogMsg("Could not convert router to CString");
3625 struct sockaddr_in saddr
;
3626 saddr
.sin_len
= sizeof(saddr
);
3627 saddr
.sin_family
= AF_INET
;
3629 inet_aton(buf
, &saddr
.sin_addr
);
3631 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) debugf("Ignoring router %s (requires PPP connection)", buf
);
3632 else *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
3636 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3639 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3640 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3642 *v4
= *v6
= zeroAddr
;
3644 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
3646 // find primary interface in list
3647 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
3649 mDNSAddr tmp6
= zeroAddr
;
3650 if (!strcmp(buf
, ifa
->ifa_name
))
3652 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
3654 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
3656 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3658 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3659 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3660 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
3665 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3666 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
3668 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3669 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
3672 ifa
= ifa
->ifa_next
;
3675 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3676 // V4 to communicate w/ our DNS server
3687 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
3689 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
3690 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3691 ConvertDomainNameToCString(dname
, uname
);
3697 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
3701 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3702 // That single entity is a CFDictionary with name "HostNames".
3703 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3704 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3705 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3706 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3707 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3709 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
3710 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
3711 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
3712 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
3715 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
3716 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
3719 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
3722 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
3725 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
3728 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, StateDict
);
3729 CFRelease(StateDict
);
3731 CFRelease(StateVals
[0]);
3733 CFRelease(HostVals
[0]);
3735 CFRelease(StatusVals
[0]);
3737 CFRelease(HostKeys
[0]);
3741 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3742 mDNSexport
void SetDomainSecrets(mDNS
*m
)
3744 #ifdef NO_SECURITYFRAMEWORK
3746 LogMsg("Note: SetDomainSecrets: no keychain support");
3748 mDNSBool haveAutoTunnels
= mDNSfalse
;
3750 LogOperation("SetDomainSecrets");
3752 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3753 // In the case where the user simultaneously removes their DDNS host name and the key
3754 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3755 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3756 // address records behind that we no longer have permission to delete.
3757 DomainAuthInfo
*ptr
;
3758 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3759 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
3761 #if APPLE_OSX_mDNSResponder
3763 // Mark all TunnelClients for deletion
3764 ClientTunnel
*client
;
3765 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3767 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
3768 client
->MarkedForDeletion
= mDNStrue
;
3771 #endif APPLE_OSX_mDNSResponder
3773 // String Array used to write list of private domains to Dynamic Store
3774 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3775 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3777 CFDataRef data
= NULL
;
3778 const int itemsPerEntry
= 3; // domain name, key name, key value
3779 CFArrayRef secrets
= NULL
;
3780 int err
= mDNSKeychainGetSecrets(&secrets
);
3781 if (err
|| !secrets
)
3782 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
3785 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
3786 // Iterate through the secrets
3787 for (i
= 0; i
< ArrayCount
; ++i
)
3790 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
3791 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
3792 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3793 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
3794 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
3795 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3797 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3799 // Get DNS domain this key is for
3800 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
3801 data
= CFArrayGetValueAtIndex(entry
, 0);
3802 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3803 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
3804 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3805 stringbuf
[CFDataGetLength(data
)] = '\0';
3808 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
3811 data
= CFArrayGetValueAtIndex(entry
, 1);
3812 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3813 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
3814 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3815 stringbuf
[CFDataGetLength(data
)] = '\0';
3818 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
3821 data
= CFArrayGetValueAtIndex(entry
, 2);
3822 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3823 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
3824 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3825 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3827 DomainAuthInfo
*FoundInList
;
3828 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
3829 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
3831 #if APPLE_OSX_mDNSResponder
3834 // If any client tunnel destination is in this domain, set deletion flag to false
3835 ClientTunnel
*client
;
3836 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3837 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
3839 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
3840 client
->MarkedForDeletion
= mDNSfalse
;
3841 // If the key has changed, reconfigure the tunnel
3842 if (strncmp(stringbuf
, client
->b64keydata
, sizeof(client
->b64keydata
)))
3844 mDNSBool queryNotInProgress
= client
->q
.ThisQInterval
< 0;
3845 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client
->dstname
.c
, queryNotInProgress
? "reconfiguring" : "query in progress");
3846 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNSfalse
);
3847 mDNS_snprintf(client
->b64keydata
, sizeof(client
->b64keydata
), "%s", stringbuf
);
3848 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNStrue
);
3853 mDNSBool keyChanged
= FoundInList
&& FoundInList
->AutoTunnel
? strncmp(stringbuf
, FoundInList
->b64keydata
, sizeof(FoundInList
->b64keydata
)) : mDNSfalse
;
3855 #endif APPLE_OSX_mDNSResponder
3857 // Uncomment the line below to view the keys as they're read out of the system keychain
3858 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3859 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
3861 // If didn't find desired domain in the list, make a new entry
3863 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
3866 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
3867 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
3870 LogOperation("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
3871 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
3873 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3877 #if APPLE_OSX_mDNSResponder
3878 if (keyChanged
&& AnonymousRacoonConfig
)
3880 LogOperation("SetDomainSecrets: secret changed for %##s", &domain
);
3881 (void)mDNSConfigureServer(kmDNSUp
, stringbuf
);
3884 if (ptr
->AutoTunnel
) UpdateAutoTunnelDomainStatus(m
, ptr
);
3885 #endif APPLE_OSX_mDNSResponder
3887 ConvertDomainNameToCString(&domain
, stringbuf
);
3888 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
3889 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
3893 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, sa
);
3896 #if APPLE_OSX_mDNSResponder
3898 // clean up ClientTunnels
3899 ClientTunnel
**pp
= &m
->TunnelClients
;
3902 if ((*pp
)->MarkedForDeletion
)
3904 ClientTunnel
*cur
= *pp
;
3905 LogOperation("SetDomainSecrets: removing client %p %##s from list", cur
, cur
->dstname
.c
);
3906 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
3907 AutoTunnelSetKeys(cur
, mDNSfalse
);
3909 freeL("ClientTunnel", cur
);
3915 DomainAuthInfo
*info
= m
->AuthInfoList
;
3918 if (info
->AutoTunnel
&& info
->deltime
)
3920 if (info
->AutoTunnelNAT
.clientContext
)
3922 // stop the NAT operation
3923 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
3924 if (info
->AutoTunnelNAT
.clientCallback
)
3926 // Reset port and let the AutoTunnelNATCallback handle cleanup
3927 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
3928 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
3929 info
->AutoTunnelNAT
.Lifetime
= 0;
3930 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
3931 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3932 info
->AutoTunnelNAT
.clientCallback(m
, &info
->AutoTunnelNAT
);
3933 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3935 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
3937 RemoveAutoTunnelDomainStatus(info
);
3942 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
3944 // remove interface if no autotunnel servers and no more client tunnels
3945 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3946 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
3947 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
3948 memset(m
->AutoTunnelHostAddr
.b
, 0, sizeof(m
->AutoTunnelHostAddr
.b
));
3951 if (!haveAutoTunnels
&& AnonymousRacoonConfig
)
3953 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3954 AnonymousRacoonConfig
= mDNSfalse
;
3955 (void)mDNSConfigureServer(kmDNSDown
, "");
3958 if (m
->AutoTunnelHostAddr
.b
[0])
3959 if (TunnelClients(m
) || TunnelServers(m
))
3960 SetupLocalAutoTunnelInterface_internal(m
);
3962 #endif APPLE_OSX_mDNSResponder
3964 #endif /* NO_SECURITYFRAMEWORK */
3967 mDNSlocal
void SetLocalDomains(void)
3969 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3970 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3972 CFArrayAppendValue(sa
, CFSTR("local"));
3973 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
3974 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
3975 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
3976 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
3977 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
3979 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, sa
);
3983 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3985 LogOperation("*** Network Configuration Change *** (%d)%s",
3986 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
3987 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
3988 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3989 mDNSs32 utc
= mDNSPlatformUTC();
3990 MarkAllInterfacesInactive(m
, utc
);
3991 UpdateInterfaceList(m
, utc
);
3992 ClearInactiveInterfaces(m
, utc
);
3993 SetupActiveInterfaces(m
, utc
);
3995 #if APPLE_OSX_mDNSResponder
3997 if (m
->AutoTunnelHostAddr
.b
[0])
4000 if (TunnelClients(m
) || TunnelServers(m
))
4001 SetupLocalAutoTunnelInterface_internal(m
);
4005 // Scan to find client tunnels whose questions have completed,
4006 // but whose local inner/outer addresses have changed since the tunnel was set up
4008 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
4009 if (p
->q
.ThisQInterval
< 0)
4011 mDNSAddr tmpSrc
= zeroAddr
;
4012 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
4013 tmpDst
.ip
.v4
= p
->rmt_outer
;
4014 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
4015 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
4016 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
4018 AutoTunnelSetKeys(p
, mDNSfalse
);
4019 p
->loc_inner
= m
->AutoTunnelHostAddr
;
4020 p
->loc_outer
= tmpSrc
.ip
.v4
;
4021 AutoTunnelSetKeys(p
, mDNStrue
);
4025 #endif APPLE_OSX_mDNSResponder
4027 uDNS_SetupDNSConfig(m
);
4029 if (m
->MainCallback
)
4030 m
->MainCallback(m
, mStatus_ConfigChanged
);
4033 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
4035 (void)store
; // Parameter not used
4036 (void)changedKeys
; // Parameter not used
4037 mDNS
*const m
= (mDNS
*const)context
;
4041 mDNSs32 delay
= mDNSPlatformOneSecond
; // Start off assuming a one-second delay
4043 int c
= CFArrayGetCount(changedKeys
); // Count changes
4044 CFRange range
= { 0, c
};
4045 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
4046 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
4047 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
4048 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/20; // If these were the only changes, shorten delay
4050 #if LogAllOperations
4055 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
4056 LogOperation("*** NetworkChanged SC key: %s", buf
);
4058 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
4060 c1
? "(Local Hostname) " : "",
4061 c2
? "(Computer Name) " : "",
4062 c3
? "(DynamicDNS) " : "",
4066 if (!m
->p
->NetworkChanged
||
4067 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
4068 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
4070 // If we have a global DNS change, then disregard delay and reconfigure immediately
4071 if (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DNS
) != 0) m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
);
4073 // KeyChain frequently fails to notify clients of change events. To work around this
4074 // we set a timer and periodically poll to detect if any changes have occurred.
4075 // Without this Back To My Mac just does't work for a large number of users.
4076 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
4077 if (c3
|| CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
))
4079 LogOperation("*** NetworkChanged *** starting KeyChainBugTimer");
4080 m
->p
->KeyChainBugTimer
= NonZeroTime(m
->timenow
+ delay
);
4081 m
->p
->KeyChainBugInterval
= mDNSPlatformOneSecond
;
4084 if (!m
->SuppressSending
||
4085 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
4086 m
->SuppressSending
= m
->p
->NetworkChanged
;
4089 KQueueUnlock(m
, "NetworkChanged");
4092 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
4095 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
4096 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
4097 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
4098 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
4099 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
4100 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
4102 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
4103 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
4105 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
4106 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
4107 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
4108 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
4109 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
4110 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
4111 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
4112 CFArrayAppendValue(patterns
, pattern1
);
4113 CFArrayAppendValue(patterns
, pattern2
);
4114 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
4115 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
4116 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
4118 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
4119 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
4121 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
4122 m
->p
->Store
= store
;
4127 if (store
) CFRelease(store
);
4130 if (patterns
) CFRelease(patterns
);
4131 if (pattern2
) CFRelease(pattern2
);
4132 if (pattern1
) CFRelease(pattern1
);
4133 if (keys
) CFRelease(keys
);
4138 #ifndef NO_SECURITYFRAMEWORK
4139 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
4141 LogOperation("*** Keychain Changed ***");
4142 mDNS
*const m
= (mDNS
*const)context
;
4144 OSStatus err
= SecKeychainCopyDefault(&skc
);
4147 if (info
->keychain
== skc
)
4149 // 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
4150 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
4153 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
4154 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
4155 SecKeychainAttributeList
*a
= NULL
;
4156 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
4159 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
4160 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
4161 SecKeychainItemFreeAttributesAndData(a
, NULL
);
4166 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
4168 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
4169 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
4170 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
4171 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
4174 SetDomainSecrets(m
);
4176 KQueueUnlock(m
, "KeychainChanged");
4187 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
4189 mDNS
*const m
= (mDNS
*const)refcon
;
4191 (void)service
; // Parameter not used
4192 LogOperation("PowerChanged %X %lX", messageType
, messageArgument
);
4195 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
4196 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
4197 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
4198 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
4199 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
4200 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
4201 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
4202 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
4203 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
4204 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
4205 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
4206 // Just to be safe, also make sure our interface list is fully up to date, in case we
4207 // haven't yet received the System Configuration Framework "network changed" event that
4208 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
4209 mDNSMacOSXNetworkChanged(m
); break; // E0000300
4210 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
4211 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
4212 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
4213 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
4214 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
4217 if (!m
->p
->SleepLimit
&& messageType
== kIOMessageSystemWillSleep
)
4219 m
->p
->SleepLimit
= NonZeroTime(mDNS_TimeNow(m
) + mDNSPlatformOneSecond
* 5);
4220 m
->p
->SleepCookie
= (long)messageArgument
;
4223 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
4225 KQueueUnlock(m
, "Sleep/Wake");
4227 #endif /* NO_IOPOWER */
4229 #if COMPILER_LIKES_PRAGMA_MARK
4231 #pragma mark - Initialization & Teardown
4234 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
4235 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
4236 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
4237 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
4239 // Major version 6 is 10.2.x (Jaguar)
4240 // Major version 7 is 10.3.x (Panther)
4241 // Major version 8 is 10.4.x (Tiger)
4242 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
4244 int major
= 0, minor
= 0;
4245 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
4246 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
4249 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
4250 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
4251 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
4252 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
4253 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
4254 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
4255 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
4258 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
4259 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, STRINGIFY(mDNSResponderVersion
));
4263 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
4264 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
4265 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
4266 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
4269 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
4271 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
4274 struct sockaddr_in s5353
;
4275 s5353
.sin_family
= AF_INET
;
4276 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
4277 s5353
.sin_addr
.s_addr
= 0;
4278 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
4282 if (err
) LogMsg("No unicast UDP responses");
4283 else debugf("Unicast UDP responses okay");
4287 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
4288 // 1) query for b._dns-sd._udp.local on LocalOnly interface
4289 // (.local manually generated via explicit callback)
4290 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
4291 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
4292 // 4) result above should generate a callback from question in (1). result added to global list
4293 // 5) global list delivered to client via GetSearchDomainList()
4294 // 6) client calls to enumerate domains now go over LocalOnly interface
4295 // (!!!KRS may add outgoing interface in addition)
4297 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
4301 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
4302 // 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.
4304 for (i
=0; i
<100; i
++)
4306 domainlabel testlabel
;
4308 GetUserSpecifiedLocalHostName(&testlabel
);
4309 if (testlabel
.c
[0]) break;
4313 m
->hostlabel
.c
[0] = 0;
4315 char *HINFO_HWstring
= "Macintosh";
4316 char HINFO_HWstring_buffer
[256];
4317 int get_model
[2] = { CTL_HW
, HW_MODEL
};
4318 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
4319 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
4320 HINFO_HWstring
= HINFO_HWstring_buffer
;
4322 char HINFO_SWstring
[256] = "";
4323 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
4324 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
4326 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
4327 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
4328 if (hlen
+ slen
< 254)
4330 m
->HIHardware
.c
[0] = hlen
;
4331 m
->HISoftware
.c
[0] = slen
;
4332 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
4333 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
4336 m
->p
->permanentsockets
.port
= MulticastDNSPort
;
4337 m
->p
->permanentsockets
.m
= m
;
4338 m
->p
->permanentsockets
.sktv4
= m
->p
->permanentsockets
.sktv6
= -1;
4339 m
->p
->permanentsockets
.kqsv4
.KQcallback
= m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
4340 m
->p
->permanentsockets
.kqsv4
.KQcontext
= m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
4341 m
->p
->permanentsockets
.kqsv4
.KQtask
= m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
4343 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
, mDNSNULL
);
4345 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
, mDNSNULL
);
4348 struct sockaddr_in s4
;
4349 socklen_t n4
= sizeof(s4
);
4350 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
4351 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
4353 if (m
->p
->permanentsockets
.sktv6
>= 0)
4355 struct sockaddr_in6 s6
;
4356 socklen_t n6
= sizeof(s6
);
4357 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
4358 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
4362 m
->p
->InterfaceList
= mDNSNULL
;
4363 m
->p
->userhostlabel
.c
[0] = 0;
4364 m
->p
->usernicelabel
.c
[0] = 0;
4365 m
->p
->NotifyUser
= 0;
4366 m
->p
->KeyChainBugTimer
= 0;
4367 m
->p
->SleepLimit
= 0;
4369 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
4371 mDNSs32 utc
= mDNSPlatformUTC();
4372 UpdateInterfaceList(m
, utc
);
4373 SetupActiveInterfaces(m
, utc
);
4375 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
4376 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
4377 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
4378 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
4379 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
4380 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
4381 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
4383 err
= WatchForNetworkChanges(m
);
4384 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
4386 // Explicitly ensure that our Keychain operations utilize the system domain.
4387 #ifndef NO_SECURITYFRAMEWORK
4388 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
4392 SetDomainSecrets(m
);
4396 #ifndef NO_SECURITYFRAMEWORK
4397 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
4398 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
4402 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
4403 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
4404 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
4405 #endif /* NO_IOPOWER */
4407 return(mStatus_NoError
);
4410 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
4413 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
4416 mStatus result
= mDNSPlatformInit_setup(m
);
4418 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
4419 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
4420 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
4424 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
4426 if (m
->p
->PowerConnection
)
4428 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
4430 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
4431 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
4432 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
4433 IOServiceClose ( m
->p
->PowerConnection
);
4434 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
4435 #endif /* NO_IOPOWER */
4436 m
->p
->PowerConnection
= 0;
4441 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
4442 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
4443 CFRelease(m
->p
->StoreRLS
);
4444 CFRelease(m
->p
->Store
);
4446 m
->p
->StoreRLS
= NULL
;
4449 mDNSs32 utc
= mDNSPlatformUTC();
4450 MarkAllInterfacesInactive(m
, utc
);
4451 ClearInactiveInterfaces(m
, utc
);
4452 CloseSocketSet(&m
->p
->permanentsockets
);
4454 #if APPLE_OSX_mDNSResponder
4456 while (m
->TunnelClients
)
4458 ClientTunnel
*cur
= m
->TunnelClients
;
4459 LogOperation("mDNSPlatformClose: removing client tunnel %p %##s from list", cur
, cur
->dstname
.c
);
4460 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
4461 AutoTunnelSetKeys(cur
, mDNSfalse
);
4462 m
->TunnelClients
= cur
->next
;
4463 freeL("ClientTunnel", cur
);
4466 if (AnonymousRacoonConfig
)
4468 AnonymousRacoonConfig
= mDNSfalse
;
4469 LogOperation("mDNSPlatformClose: Deconfiguring autotunnel");
4470 (void)mDNSConfigureServer(kmDNSDown
, "");
4473 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
4475 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
4476 LogOperation("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
4477 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
4479 #endif // APPLE_OSX_mDNSResponder
4482 #if COMPILER_LIKES_PRAGMA_MARK
4484 #pragma mark - General Platform Support Layer functions
4487 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
4489 return(mach_absolute_time());
4492 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
4493 mDNSexport mDNSu32 mDNSPlatformClockDivisor
= 0;
4495 mDNSexport mStatus
mDNSPlatformTimeInit(void)
4497 // Notes: Typical values for mach_timebase_info:
4498 // tbi.numer = 1000 million
4499 // tbi.denom = 33 million
4500 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
4501 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
4502 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
4503 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
4504 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
4506 // Arithmetic notes:
4507 // tbi.denom is at least 1, and not more than 2^32-1.
4508 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
4509 // tbi.denom is at least 1, and not more than 2^32-1.
4510 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
4511 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
4512 // which is unlikely on any current or future Macintosh.
4513 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
4514 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
4515 struct mach_timebase_info tbi
;
4516 kern_return_t result
= mach_timebase_info(&tbi
);
4517 if (result
== KERN_SUCCESS
) mDNSPlatformClockDivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
4521 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
4523 if (mDNSPlatformClockDivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
4525 static uint64_t last_mach_absolute_time
= 0;
4526 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
4527 uint64_t this_mach_absolute_time
= mach_absolute_time();
4528 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
4530 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
4531 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
4532 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
4533 last_mach_absolute_time
= this_mach_absolute_time
;
4534 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4535 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4536 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
4537 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4538 "This error occurs from time to time, often on newly released hardware, "
4539 "and usually the exact cause is different in each instance.\r\r"
4540 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4541 "and assign it to Radar Component “Kernel” Version “X”.");
4543 last_mach_absolute_time
= this_mach_absolute_time
;
4545 return((mDNSs32
)(this_mach_absolute_time
/ mDNSPlatformClockDivisor
));
4548 mDNSexport mDNSs32
mDNSPlatformUTC(void)
4553 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4554 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
4555 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
4556 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
4557 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
4558 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
4559 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
4560 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
4561 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4562 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
4564 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }