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.508 2007/11/02 21:59:37 cheshire
21 Added comment about locking
23 Revision 1.507 2007/11/02 20:18:13 cheshire
24 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
26 Revision 1.506 2007/10/30 20:46:45 cheshire
27 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
29 Revision 1.505 2007/10/29 23:55:10 cheshire
30 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
31 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
32 (and indeed should not, since the result fields will not yet be set up correctly in this case)
34 Revision 1.504 2007/10/26 00:50:37 cheshire
35 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
37 Revision 1.503 2007/10/25 23:11:42 cheshire
38 Ignore IPv6 ULA addresses configured on lo0 loopback interface
40 Revision 1.502 2007/10/22 20:07:07 cheshire
41 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
42 Posix build can share the code (better than just pasting it into mDNSPosix.c)
44 Revision 1.501 2007/10/22 19:40:30 cheshire
45 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
46 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
48 Revision 1.500 2007/10/17 22:49:55 cheshire
49 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
51 Revision 1.499 2007/10/17 19:47:54 cheshire
52 Improved debugging messages
54 Revision 1.498 2007/10/17 18:42:06 cheshire
55 Export SetDomainSecrets so its callable from other files
57 Revision 1.497 2007/10/16 17:03:07 cheshire
58 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
59 Cut SetDomainSecrets stack from 3792 to 1760 bytes
61 Revision 1.496 2007/10/04 20:33:05 mcguire
62 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
64 Revision 1.495 2007/10/02 05:03:38 cheshire
65 Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
67 Revision 1.494 2007/09/29 20:40:19 cheshire
68 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
70 Revision 1.493 2007/09/29 03:16:45 cheshire
71 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
72 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
74 Revision 1.492 2007/09/28 23:58:35 mcguire
75 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
78 Revision 1.491 2007/09/27 23:28:53 mcguire
79 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
81 Revision 1.490 2007/09/26 23:01:21 mcguire
82 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
84 Revision 1.489 2007/09/26 22:58:16 mcguire
85 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
87 Revision 1.488 2007/09/26 00:32:45 cheshire
88 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
90 Revision 1.487 2007/09/21 17:07:41 mcguire
91 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
93 Revision 1.486 2007/09/19 23:17:38 cheshire
94 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
96 Revision 1.485 2007/09/19 21:44:29 cheshire
97 Improved "mDNSKeychainGetSecrets failed" error message
99 Revision 1.484 2007/09/18 21:44:55 cheshire
100 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
101 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
103 Revision 1.483 2007/09/17 22:19:39 mcguire
104 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
105 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
107 Revision 1.482 2007/09/14 21:16:03 cheshire
108 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
110 Revision 1.481 2007/09/14 21:14:56 mcguire
111 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
113 Revision 1.480 2007/09/13 00:16:42 cheshire
114 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
116 Revision 1.479 2007/09/12 19:22:20 cheshire
117 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
118 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
120 Revision 1.478 2007/09/07 22:21:45 vazquez
121 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
123 Revision 1.477 2007/09/07 21:22:30 cheshire
124 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
125 Don't log failures binding to port 5351
127 Revision 1.476 2007/09/06 20:38:08 cheshire
128 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
130 Revision 1.475 2007/09/05 02:24:28 cheshire
131 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
132 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
134 Revision 1.474 2007/09/04 22:32:58 mcguire
135 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
137 Revision 1.473 2007/08/31 19:53:15 cheshire
138 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
139 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
141 Revision 1.472 2007/08/31 18:49:49 vazquez
142 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
144 Revision 1.471 2007/08/31 02:05:46 cheshire
145 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
147 Revision 1.470 2007/08/30 22:50:04 mcguire
148 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
150 Revision 1.469 2007/08/30 19:40:51 cheshire
151 Added syslog messages to report various initialization failures
153 Revision 1.468 2007/08/30 00:12:20 cheshire
154 Check error codes and log failures during AutoTunnel setup
156 Revision 1.467 2007/08/28 00:33:04 jgraessley
157 <rdar://problem/5423932> Selective compilation options
159 Revision 1.466 2007/08/24 23:25:55 cheshire
160 Debugging messages to help track down duplicate items being read from system keychain
162 Revision 1.465 2007/08/24 00:39:12 cheshire
163 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
165 Revision 1.464 2007/08/24 00:15:21 cheshire
166 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
168 Revision 1.463 2007/08/23 21:02:35 cheshire
169 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
171 Revision 1.462 2007/08/18 01:02:03 mcguire
172 <rdar://problem/5415593> No Bonjour services are getting registered at boot
174 Revision 1.461 2007/08/10 22:25:57 mkrochma
175 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
177 Revision 1.460 2007/08/08 22:34:59 mcguire
178 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
180 Revision 1.459 2007/08/08 21:07:48 vazquez
181 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
183 Revision 1.458 2007/08/03 02:18:41 mcguire
184 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
186 Revision 1.457 2007/08/02 16:48:45 mcguire
187 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
189 Revision 1.456 2007/08/02 03:28:30 vazquez
190 Make ExternalAddress and err unused to fix build warnings
192 Revision 1.455 2007/08/01 03:09:22 cheshire
193 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
195 Revision 1.454 2007/07/31 23:08:34 mcguire
196 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
198 Revision 1.453 2007/07/31 19:13:58 mkrochma
199 No longer need to include "btmm" in hostname to avoid name conflicts
201 Revision 1.452 2007/07/27 19:30:41 cheshire
202 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
203 to properly reflect tri-state nature of the possible responses
205 Revision 1.451 2007/07/25 22:25:45 cheshire
206 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
208 Revision 1.450 2007/07/25 21:19:10 cheshire
209 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
211 Revision 1.449 2007/07/25 01:36:09 mcguire
212 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
214 Revision 1.448 2007/07/24 21:30:09 cheshire
215 Added "AutoTunnel server listening for connections..." diagnostic message
217 Revision 1.447 2007/07/24 20:24:18 cheshire
218 Only remove AutoTunnel address if we have created it.
219 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
221 Revision 1.446 2007/07/24 03:00:09 cheshire
222 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
224 Revision 1.445 2007/07/23 20:26:26 cheshire
225 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
226 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
227 for existence of "Setup:/Network/DynamicDNS" settings
229 Revision 1.444 2007/07/21 00:54:49 cheshire
230 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
232 Revision 1.443 2007/07/20 23:23:11 cheshire
233 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
235 Revision 1.442 2007/07/20 20:23:24 cheshire
236 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
237 Fixed errors reading the Setup:/Network/BackToMyMac preferences
239 Revision 1.441 2007/07/20 16:46:45 mcguire
240 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
242 Revision 1.440 2007/07/20 16:22:07 mcguire
243 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
245 Revision 1.439 2007/07/20 01:14:56 cheshire
246 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
247 Cleaned up log messages
249 Revision 1.438 2007/07/20 00:54:21 cheshire
250 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
252 Revision 1.437 2007/07/19 22:01:27 cheshire
253 Added "#pragma mark" sections headings to divide code into related function groups
255 Revision 1.436 2007/07/18 03:25:25 cheshire
256 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
257 Bring up server-side tunnel on demand, when necessary
259 Revision 1.435 2007/07/18 01:05:08 cheshire
260 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
261 Add list of client tunnels so we can automatically reconfigure when local address changes
263 Revision 1.434 2007/07/16 20:16:00 vazquez
264 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
265 Remove unnecessary LNT init code
267 Revision 1.433 2007/07/14 00:36:07 cheshire
268 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
270 Revision 1.432 2007/07/12 23:55:11 cheshire
271 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
272 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
274 Revision 1.431 2007/07/12 23:34:48 cheshire
275 Removed 'LogOperation' message to reduce verbosity in syslog
277 Revision 1.430 2007/07/12 22:16:46 cheshire
278 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
280 Revision 1.429 2007/07/12 02:51:28 cheshire
281 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
283 Revision 1.428 2007/07/11 23:17:31 cheshire
284 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
285 Improve log message to indicate if we're starting or restarting racoon
287 Revision 1.427 2007/07/11 22:50:30 cheshire
288 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
289 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
291 Revision 1.426 2007/07/11 20:40:49 cheshire
292 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
293 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
295 Revision 1.425 2007/07/11 19:24:19 cheshire
296 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
297 Configure internal AutoTunnel address
298 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
299 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
301 Revision 1.424 2007/07/11 19:00:27 cheshire
302 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
304 Revision 1.423 2007/07/11 03:00:59 cheshire
305 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
306 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
308 Revision 1.422 2007/07/10 01:21:20 cheshire
309 Added (commented out) line for displaying key data for debugging
311 Revision 1.421 2007/06/25 20:58:11 cheshire
312 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
313 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
315 Revision 1.420 2007/06/22 21:52:14 cheshire
316 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
318 Revision 1.419 2007/06/22 21:32:00 cheshire
319 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
321 Revision 1.418 2007/06/21 16:37:43 jgraessley
323 Reviewed by: Stuart Cheshire
324 Additional changes to get this compiling on the embedded platform.
326 Revision 1.417 2007/06/20 01:44:00 cheshire
327 More information in "Network Configuration Change" message
329 Revision 1.416 2007/06/20 01:10:12 cheshire
330 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
332 Revision 1.415 2007/06/15 19:23:38 cheshire
333 <rdar://problem/5254053> mDNSResponder renames my host without asking
334 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
336 Revision 1.414 2007/05/17 22:00:59 cheshire
337 <rdar://problem/5210966> Lower network change delay from two seconds to one second
339 Revision 1.413 2007/05/16 16:43:27 cheshire
340 Only log "bind" failures for our shared mDNS port and for binding to zero
341 -- other attempts to bind to a particular port may legitimately fail
343 Revision 1.412 2007/05/15 21:49:21 cheshire
344 Get rid of "#pragma unused"
346 Revision 1.411 2007/05/14 23:54:55 cheshire
347 Instead of sprintf, use safer length-limited mDNS_snprintf
349 Revision 1.410 2007/05/12 01:05:00 cheshire
350 Updated debugging messages
352 Revision 1.409 2007/05/10 22:39:48 cheshire
353 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
354 Only define CountMaskBits for builds with debugging messages
356 Revision 1.408 2007/05/10 22:19:00 cheshire
357 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
358 Don't deliver multicast packets for which we can't find an associated InterfaceID
360 Revision 1.407 2007/05/10 21:40:28 cheshire
361 Don't log unnecessary "Address already in use" errors when joining multicast groups
363 Revision 1.406 2007/05/08 00:56:17 cheshire
364 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
366 Revision 1.405 2007/05/04 20:21:39 cheshire
367 Improve "connect failed" error message
369 Revision 1.404 2007/05/02 19:41:53 cheshire
370 No need to alarm people with "Connection reset by peer" syslog message
372 Revision 1.403 2007/04/28 01:31:59 cheshire
373 Improve debugging support for catching memory corruption problems
375 Revision 1.402 2007/04/26 22:54:57 cheshire
376 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
378 Revision 1.401 2007/04/26 00:35:16 cheshire
379 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
380 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
381 inside the firewall may give answers where a public one gives none, and vice versa.)
383 Revision 1.400 2007/04/24 21:50:27 cheshire
384 Debugging: Show list of changedKeys in NetworkChanged callback
386 Revision 1.399 2007/04/23 22:28:47 cheshire
387 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
389 Revision 1.398 2007/04/23 04:57:00 cheshire
390 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
392 Revision 1.397 2007/04/22 06:02:03 cheshire
393 <rdar://problem/4615977> Query should immediately return failure when no server
395 Revision 1.396 2007/04/21 21:47:47 cheshire
396 <rdar://problem/4376383> Daemon: Add watchdog timer
398 Revision 1.395 2007/04/18 20:58:34 cheshire
399 <rdar://problem/5140339> Domain discovery not working over VPN
400 Needed different code to handle the case where there's only a single search domain
402 Revision 1.394 2007/04/17 23:05:50 cheshire
403 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
405 Revision 1.393 2007/04/17 19:21:29 cheshire
406 <rdar://problem/5140339> Domain discovery not working over VPN
408 Revision 1.392 2007/04/17 17:15:09 cheshire
409 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
411 Revision 1.391 2007/04/07 01:01:48 cheshire
412 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
414 Revision 1.390 2007/04/06 18:45:02 cheshire
415 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
417 Revision 1.389 2007/04/05 21:39:49 cheshire
418 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
420 Revision 1.388 2007/04/05 21:09:52 cheshire
421 Condense sprawling code
423 Revision 1.387 2007/04/05 20:40:37 cheshire
424 Remove unused mDNSPlatformTCPGetFlags()
426 Revision 1.386 2007/04/05 19:50:56 cheshire
427 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
429 Revision 1.385 2007/04/03 19:39:19 cheshire
430 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
432 Revision 1.384 2007/03/31 01:10:53 cheshire
435 Revision 1.383 2007/03/31 00:13:48 cheshire
438 Revision 1.382 2007/03/28 21:01:29 cheshire
439 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
441 Revision 1.381 2007/03/28 15:56:37 cheshire
442 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
444 Revision 1.380 2007/03/26 22:54:46 cheshire
447 Revision 1.379 2007/03/22 18:31:48 cheshire
448 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
450 Revision 1.378 2007/03/22 00:49:20 cheshire
451 <rdar://problem/4848295> Advertise model information via Bonjour
453 Revision 1.377 2007/03/21 00:30:05 cheshire
454 <rdar://problem/4789455> Multiple errors in DNameList-related code
456 Revision 1.376 2007/03/20 17:07:15 cheshire
457 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
459 Revision 1.375 2007/03/20 00:50:57 cheshire
460 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
462 Revision 1.374 2007/03/06 23:29:50 cheshire
463 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
465 Revision 1.373 2007/02/28 01:51:20 cheshire
466 Added comment about reverse-order IP address
468 Revision 1.372 2007/02/28 01:06:48 cheshire
469 Use %#a format code instead of %d.%d.%d.%d
471 Revision 1.371 2007/02/08 21:12:28 cheshire
472 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
474 Revision 1.370 2007/01/16 22:59:58 cheshire
475 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
477 Revision 1.369 2007/01/10 02:09:32 cheshire
478 Better LogOperation record of keys read from System Keychain
480 Revision 1.368 2007/01/10 01:25:31 cheshire
481 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
483 Revision 1.367 2007/01/10 01:22:01 cheshire
484 Make sure c1, c2, c3 are initialized
486 Revision 1.366 2007/01/09 22:37:20 cheshire
487 Provide ten-second grace period for deleted keys, to give mDNSResponder
488 time to delete host name before it gives up access to the required key.
490 Revision 1.365 2007/01/09 21:09:20 cheshire
491 Need locking in KeychainChanged()
493 Revision 1.364 2007/01/09 20:17:04 cheshire
494 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
496 Revision 1.363 2007/01/09 02:41:18 cheshire
497 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
498 moved it to mDNS_Init() in mDNS.c (core code)
500 Revision 1.362 2007/01/08 23:54:01 cheshire
501 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
503 Revision 1.361 2007/01/05 08:30:48 cheshire
504 Trim excessive "$Log" checkin history from before 2006
505 (checkin history still available via "cvs log ..." of course)
507 Revision 1.360 2007/01/04 00:12:24 cheshire
508 <rdar://problem/4742742> Read *all* DNS keys from keychain,
509 not just key for the system-wide default registration domain
511 Revision 1.359 2006/12/22 21:14:37 cheshire
512 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
513 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
515 Revision 1.358 2006/12/22 20:59:50 cheshire
516 <rdar://problem/4742742> Read *all* DNS keys from keychain,
517 not just key for the system-wide default registration domain
519 Revision 1.357 2006/12/21 00:09:45 cheshire
520 Use mDNSPlatformMemZero instead of bzero
522 Revision 1.356 2006/12/20 23:15:53 mkrochma
523 Fix the private domain list code so that it actually works
525 Revision 1.355 2006/12/20 23:04:36 mkrochma
526 Fix crash when adding private domain list to Dynamic Store
528 Revision 1.354 2006/12/19 22:43:55 cheshire
529 Fix compiler warnings
531 Revision 1.353 2006/12/14 22:08:29 cheshire
532 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
533 to release data allocated by SecKeychainItemCopyAttributesAndData()
535 Revision 1.352 2006/12/14 02:33:26 cheshire
536 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
538 Revision 1.351 2006/11/28 21:37:51 mkrochma
539 Tweak where the private DNS data is written
541 Revision 1.350 2006/11/28 07:55:02 herscher
542 <rdar://problem/4742743> dnsextd has a slow memory leak
544 Revision 1.349 2006/11/28 07:45:58 herscher
545 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
547 Revision 1.348 2006/11/16 21:47:20 mkrochma
548 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
550 Revision 1.347 2006/11/10 00:54:16 cheshire
551 <rdar://problem/4816598> Changing case of Computer Name doesn't work
553 Revision 1.346 2006/10/31 02:34:58 cheshire
554 <rdar://problem/4692130> Stop creating HINFO records
556 Revision 1.345 2006/09/21 20:04:38 mkrochma
557 Accidently changed function name while checking in previous fix
559 Revision 1.344 2006/09/21 19:04:13 mkrochma
560 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
562 Revision 1.343 2006/09/15 21:20:16 cheshire
563 Remove uDNS_info substructure from mDNS_struct
565 Revision 1.342 2006/08/16 00:31:50 mkrochma
566 <rdar://problem/4386944> Get rid of NotAnInteger references
568 Revision 1.341 2006/08/14 23:24:40 cheshire
569 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
571 Revision 1.340 2006/07/29 19:11:13 mkrochma
572 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
574 Revision 1.339 2006/07/27 03:24:35 cheshire
575 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
576 Further refinement: Declare KQueueEntry parameter "const"
578 Revision 1.338 2006/07/27 02:59:25 cheshire
579 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
580 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
581 after releasing BigMutex, in case actions it took have resulted in new work for the
582 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
583 add new active interfaces to its list, and consequently schedule queries to be sent).
585 Revision 1.337 2006/07/22 06:11:37 cheshire
586 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
588 Revision 1.336 2006/07/15 02:01:32 cheshire
589 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
590 Fix broken "empty string" browsing
592 Revision 1.335 2006/07/14 05:25:11 cheshire
593 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
594 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
596 Revision 1.334 2006/07/05 23:42:00 cheshire
597 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
599 Revision 1.333 2006/06/29 05:33:30 cheshire
600 <rdar://problem/4607043> mDNSResponder conditional compilation options
602 Revision 1.332 2006/06/28 09:10:36 cheshire
603 Extra debugging messages
605 Revision 1.331 2006/06/21 22:29:42 cheshire
606 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
608 Revision 1.330 2006/06/20 23:06:00 cheshire
609 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
611 Revision 1.329 2006/06/08 23:22:33 cheshire
614 Revision 1.328 2006/03/19 03:27:49 cheshire
615 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
617 Revision 1.327 2006/03/19 02:00:09 cheshire
618 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
620 Revision 1.326 2006/03/08 22:42:23 cheshire
621 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
623 Revision 1.325 2006/01/10 00:39:17 cheshire
624 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
626 Revision 1.324 2006/01/09 19:28:59 cheshire
627 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
629 Revision 1.323 2006/01/05 21:45:27 cheshire
630 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
632 Revision 1.322 2006/01/05 21:41:50 cheshire
633 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
635 Revision 1.321 2006/01/05 21:35:06 cheshire
636 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
640 // ***************************************************************************
642 // Supporting routines to run mDNS on a CFRunLoop platform
643 // ***************************************************************************
645 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
646 // including ones that mDNSResponder chooses not to use.
647 #define LIST_ALL_INTERFACES 0
649 // For enabling AAAA records over IPv4. Setting this to 0 sends only
650 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
651 // AAAA and A records over both IPv4 and IPv6.
652 #define AAAA_OVER_V4 1
654 // 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
655 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
656 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
657 // 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.
658 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
659 // so were willing to make that sacrifice.
660 // In Mac OS X 10.5, in 2007, two things have changed:
661 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
662 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
664 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
666 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
667 #include "DNSCommon.h"
669 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
670 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
671 #include "PlatformCommon.h"
675 #include <stdarg.h> // For va_list support
677 #include <net/if_types.h> // For IFT_ETHER
678 #include <net/if_dl.h>
680 #include <sys/param.h>
681 #include <sys/socket.h>
682 #include <sys/sysctl.h>
683 #include <sys/event.h>
685 #include <sys/ioctl.h>
686 #include <time.h> // platform support for UTC time
687 #include <arpa/inet.h> // for inet_aton
690 #include <netinet/in.h> // For IP_RECVTTL
692 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
695 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
696 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
697 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
698 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
700 #if TARGET_OS_EMBEDDED
701 #define NO_SECURITYFRAMEWORK 1
704 #ifndef NO_SECURITYFRAMEWORK
705 #include <Security/SecureTransport.h>
706 #include <Security/Security.h>
707 #endif /* NO_SECURITYFRAMEWORK */
709 #include <DebugServices.h>
712 // Code contributed by Dave Heller:
713 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
714 // work on Mac OS X 10.1, which does not have the getifaddrs call.
715 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
716 #if RUN_ON_PUMA_WITHOUT_IFADDRS
717 #include "mDNSMacOSXPuma.c"
722 #include <IOKit/IOKitLib.h>
723 #include <IOKit/IOMessage.h>
724 #include <mach/mach_error.h>
725 #include <mach/mach_port.h>
726 #include <mach/mach_time.h>
729 #define kInterfaceSpecificOption "interface="
731 // ***************************************************************************
734 #if COMPILER_LIKES_PRAGMA_MARK
735 #pragma mark - Globals
738 static mDNSu32 clockdivisor
= 0;
740 mDNSexport
int KQueueFD
;
742 #ifndef NO_SECURITYFRAMEWORK
743 static CFArrayRef ServerCerts
;
744 #endif /* NO_SECURITYFRAMEWORK */
746 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
748 CFStringRef NetworkChangedKey_IPv4
;
749 CFStringRef NetworkChangedKey_IPv6
;
750 CFStringRef NetworkChangedKey_Hostnames
;
751 CFStringRef NetworkChangedKey_Computername
;
752 CFStringRef NetworkChangedKey_DNS
;
753 CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
754 CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
756 // ***************************************************************************
759 #if COMPILER_LIKES_PRAGMA_MARK
761 #pragma mark - Utility Functions
764 // We only attempt to send and receive multicast packets on interfaces that are
765 // (a) flagged as multicast-capable
766 // (b) *not* flagged as point-to-point (e.g. modem)
767 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
768 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
769 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
770 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
772 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
774 static int notifyCount
= 0;
775 if (notifyCount
) return;
777 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
778 // To avoid this, we don't try to display alerts in the first three minutes after boot.
779 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
781 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
784 // Determine if we're at Apple (17.*.*.*)
785 extern mDNS mDNSStorage
;
786 NetworkInterfaceInfoOSX
*i
;
787 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
788 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
790 if (!i
) return; // If not at Apple, don't show the alert
796 // Display a notification to the user
799 #ifndef NO_CFUSERNOTIFICATION
800 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.)";
801 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
802 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
803 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
804 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
805 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
806 #endif /* NO_CFUSERNOTIFICATION */
809 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
811 static struct ifaddrs
*ifa
= NULL
;
819 if (ifa
== NULL
) getifaddrs(&ifa
);
824 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
826 NetworkInterfaceInfoOSX
*i
;
827 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
828 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
830 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
831 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
835 mDNSlocal
int myIfIndexToName(u_short index
, char *name
)
838 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
839 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
840 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
841 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
845 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 index
)
847 NetworkInterfaceInfoOSX
*i
;
848 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
849 if (index
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
851 // Don't get tricked by inactive interfaces with no InterfaceID set
852 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
853 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
855 // Not found. Make sure our interface list is up to date, then try again.
856 LogOperation("InterfaceID for interface index %d not found; Updating interface list", index
);
857 mDNSMacOSXNetworkChanged(m
);
858 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
859 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
864 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
866 NetworkInterfaceInfoOSX
*i
;
867 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
868 if (id
== mDNSInterface_Any
) return(0);
870 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
871 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
872 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
874 // Not found. Make sure our interface list is up to date, then try again.
875 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id
);
876 mDNSMacOSXNetworkChanged(m
);
877 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
878 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
883 #if COMPILER_LIKES_PRAGMA_MARK
885 #pragma mark - UDP & TCP send & receive
888 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
890 mDNSBool result
= mDNSfalse
;
891 SCNetworkConnectionFlags flags
;
892 SCNetworkReachabilityRef ReachRef
= NULL
;
894 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
895 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
896 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
897 result
= flags
& kSCNetworkFlagsConnectionRequired
;
900 if (ReachRef
) CFRelease(ReachRef
);
904 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
905 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
906 // OR send via our primary v4 unicast socket
907 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
908 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
910 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
911 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
912 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
913 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
914 char *ifa_name
= info
? info
->ifa_name
: "unicast";
915 struct sockaddr_storage to
;
917 mStatus result
= mStatus_NoError
;
919 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
920 // anonymous socket created for this purpose, so that we'll receive the response.
921 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
922 if (InterfaceID
&& !mDNSAddrIsDNSMulticast(dst
))
924 const DNSMessage
*const m
= (DNSMessage
*)msg
;
925 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
926 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
929 if (dst
->type
== mDNSAddrType_IPv4
)
931 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
932 sin_to
->sin_len
= sizeof(*sin_to
);
933 sin_to
->sin_family
= AF_INET
;
934 sin_to
->sin_port
= dstPort
.NotAnInteger
;
935 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
936 s
= m
->p
->permanentsockets
.sktv4
;
937 if (info
) // Specify outgoing interface
939 if (!mDNSAddrIsDNSMulticast(dst
))
941 #ifdef IP_FORCE_OUT_IFP
942 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, ifa_name
, strlen(ifa_name
) + 1);
945 static int displayed
= 0;
949 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
956 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
957 if (err
< 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
961 else if (dst
->type
== mDNSAddrType_IPv6
)
963 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
964 sin6_to
->sin6_len
= sizeof(*sin6_to
);
965 sin6_to
->sin6_family
= AF_INET6
;
966 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
967 sin6_to
->sin6_flowinfo
= 0;
968 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
969 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
970 s
= m
->p
->permanentsockets
.sktv6
;
971 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
973 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
974 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
));
979 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
983 return mStatus_BadParamErr
;
986 // Don't send if it would cause dial-on-demand connection initiation.
987 // As an optimization, don't bother consulting reachability API / routing
988 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
989 if (!info
&& !mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
991 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
992 return mStatus_NoError
;
996 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
997 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
999 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1000 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
1002 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1003 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1004 if (s
< 0) return(mStatus_Invalid
);
1006 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
1009 static int MessageCount
= 0;
1010 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1011 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
1012 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
1013 // Don't report EHOSTUNREACH in the first three minutes after boot
1014 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1015 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1016 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
1017 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1018 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
1019 if (MessageCount
< 1000)
1022 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1023 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
1025 result
= mStatus_UnknownErr
;
1028 #ifdef IP_FORCE_OUT_IFP
1029 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
1030 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, "", 1);
1036 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
1037 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
1039 static unsigned int numLogMessages
= 0;
1040 struct iovec databuffers
= { (char *)buffer
, max
};
1043 struct cmsghdr
*cmPtr
;
1044 char ancillary
[1024];
1046 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1048 // Set up the message
1049 msg
.msg_name
= (caddr_t
)from
;
1050 msg
.msg_namelen
= *fromlen
;
1051 msg
.msg_iov
= &databuffers
;
1053 msg
.msg_control
= (caddr_t
)&ancillary
;
1054 msg
.msg_controllen
= sizeof(ancillary
);
1058 n
= recvmsg(s
, &msg
, 0);
1061 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1064 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1066 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1067 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1070 if (msg
.msg_flags
& MSG_CTRUNC
)
1072 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1076 *fromlen
= msg
.msg_namelen
;
1078 // Parse each option out of the ancillary data.
1079 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1081 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1082 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1084 dstaddr
->type
= mDNSAddrType_IPv4
;
1085 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1087 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1089 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1090 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1092 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1093 ifname
[sdl
->sdl_nlen
] = 0;
1094 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1097 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1098 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1099 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1101 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1102 dstaddr
->type
= mDNSAddrType_IPv6
;
1103 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1104 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1106 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1107 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1113 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1115 const KQSocketSet
*const ss
= (const KQSocketSet
*)context
;
1116 mDNS
*const m
= ss
->m
;
1119 if (filter
!= EVFILT_READ
)
1120 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1122 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
1124 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1125 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1126 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1131 mDNSAddr senderAddr
, destAddr
;
1132 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1133 struct sockaddr_storage from
;
1134 size_t fromlen
= sizeof(from
);
1135 char packetifname
[IF_NAMESIZE
] = "";
1137 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1141 if (from
.ss_family
== AF_INET
)
1143 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1144 senderAddr
.type
= mDNSAddrType_IPv4
;
1145 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1146 senderPort
.NotAnInteger
= sin
->sin_port
;
1147 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1149 else if (from
.ss_family
== AF_INET6
)
1151 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1152 senderAddr
.type
= mDNSAddrType_IPv6
;
1153 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1154 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1155 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1159 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1163 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1164 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1165 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1166 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1167 // When going to sleep we deregister all our interfaces, but if the machine
1168 // takes a few seconds to sleep we may continue to receive multicasts
1169 // during that time, which would confuse mDNSCoreReceive, because as far
1170 // as it's concerned, we should have no active interfaces any more.
1171 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1172 if (intf
) InterfaceID
= intf
->InterfaceID
;
1173 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1175 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1176 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1178 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1181 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1183 // Something is busted here.
1184 // kqueue says there is a packet, but myrecvfrom says there is not.
1185 // Try calling select() to get another opinion.
1186 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1187 // All of this is racy, as data may have arrived after the call to select()
1188 static unsigned int numLogMessages
= 0;
1189 int save_errno
= errno
;
1193 socklen_t solen
= sizeof(int);
1195 struct timeval timeout
;
1198 FD_SET(s1
, &readfds
);
1200 timeout
.tv_usec
= 0;
1201 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1202 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1203 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1204 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1205 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1206 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1207 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1208 if (numLogMessages
++ < 100)
1209 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1210 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1211 if (numLogMessages
> 5)
1212 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1213 "Congratulations, you've reproduced an elusive bug.\r"
1214 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1215 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1216 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1218 sleep(1); // After logging this error, rate limit so we don't flood syslog
1222 // TCP socket support
1224 struct TCPSocket_struct
1226 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1227 TCPConnectionCallback callback
;
1229 KQueueEntry kqEntry
;
1230 #ifndef NO_SECURITYFRAMEWORK
1231 SSLContextRef tlsContext
;
1232 #endif /* NO_SECURITYFRAMEWORK */
1235 mDNSBool handshakecomplete
;
1239 #ifndef NO_SECURITYFRAMEWORK
1241 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1243 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1244 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1245 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1247 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1248 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1249 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1250 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno
, strerror(errno
));
1251 return(errSSLClosedAbort
);
1254 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1256 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1257 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1258 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1260 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1261 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1262 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1263 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno
, strerror(errno
));
1264 return(errSSLClosedAbort
);
1267 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1269 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1270 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1272 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1273 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1275 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1276 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1281 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1283 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1284 const domainname
*d1
= mDNSNULL
; // TLD
1285 const domainname
*d2
= mDNSNULL
; // SLD
1286 const domainname
*d3
= mDNSNULL
;
1287 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1288 return(d3
&& SameDomainName(d3
, mmc
));
1291 #endif /* NO_SECURITYFRAMEWORK */
1293 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1295 TCPSocket
*sock
= context
;
1296 mStatus err
= mStatus_NoError
;
1298 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1299 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1300 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1301 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, &sock
->kqEntry
);
1303 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1305 #ifndef NO_SECURITYFRAMEWORK
1306 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1307 if (!sock
->handshakecomplete
)
1309 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1310 err
= SSLHandshake(sock
->tlsContext
);
1311 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1312 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1313 else if (err
== errSSLWouldBlock
) return;
1314 else { LogMsg("KQ SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1317 err
= mStatus_UnsupportedErr
;
1318 #endif /* NO_SECURITYFRAMEWORK */
1321 mDNSBool connect
= !sock
->connected
;
1322 sock
->connected
= mDNStrue
;
1323 sock
->callback(sock
, sock
->context
, connect
, err
);
1324 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1327 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1329 struct kevent new_event
;
1330 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1331 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1334 mDNSexport
void KQueueLock(mDNS
*const m
)
1336 pthread_mutex_lock(&m
->p
->BigMutex
);
1337 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1340 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1342 mDNSs32 end
= mDNSPlatformRawTime();
1344 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1345 LogOperation("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1347 pthread_mutex_unlock(&m
->p
->BigMutex
);
1350 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1351 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno
, strerror(errno
));
1354 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1358 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1359 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1361 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1362 sock
->callback
= mDNSNULL
;
1363 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
1364 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1365 sock
->kqEntry
.KQcontext
= sock
;
1366 sock
->kqEntry
.KQtask
= "mDNSPlatformTCPSocket";
1367 sock
->flags
= flags
;
1368 sock
->context
= mDNSNULL
;
1369 sock
->setup
= mDNSfalse
;
1370 sock
->handshakecomplete
= mDNSfalse
;
1371 sock
->connected
= mDNSfalse
;
1375 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1376 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1381 struct sockaddr_in addr
;
1382 memset(&addr
, 0, sizeof(addr
));
1383 addr
.sin_family
= AF_INET
;
1384 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1385 addr
.sin_port
= port
->NotAnInteger
;
1386 if (bind(sock
->fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
1387 { LogMsg("ERROR: bind %s", strerror(errno
)); goto error
; }
1389 // Receive interface identifiers
1390 const int on
= 1; // "on" for setsockopt
1391 if (setsockopt(sock
->fd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1392 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); goto error
; }
1394 memset(&addr
, 0, sizeof(addr
));
1395 socklen_t len
= sizeof(addr
);
1396 if (getsockname(sock
->fd
, (struct sockaddr
*) &addr
, &len
) < 0)
1397 { LogMsg("getsockname - %s", strerror(errno
)); goto error
; }
1399 port
->NotAnInteger
= addr
.sin_port
;
1404 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1408 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1409 TCPConnectionCallback callback
, void *context
)
1411 struct sockaddr_in saddr
;
1412 mStatus err
= mStatus_NoError
;
1414 sock
->callback
= callback
;
1415 sock
->context
= context
;
1416 sock
->setup
= mDNSfalse
;
1417 sock
->handshakecomplete
= mDNSfalse
;
1418 sock
->connected
= mDNSfalse
;
1420 (void) InterfaceID
; //!!!KRS use this if non-zero!!!
1422 if (dst
->type
!= mDNSAddrType_IPv4
)
1424 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1425 return mStatus_UnknownErr
;
1428 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1429 saddr
.sin_family
= AF_INET
;
1430 saddr
.sin_port
= dstport
.NotAnInteger
;
1431 saddr
.sin_len
= sizeof(saddr
);
1432 saddr
.sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1434 // Don't send if it would cause dial-on-demand connection initiation.
1435 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1437 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1438 return mStatus_UnknownErr
;
1441 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1442 sock
->kqEntry
.KQcontext
= sock
;
1443 sock
->kqEntry
.KQtask
= "Outgoing TCP";
1445 // Watch for connect complete (write is ready)
1446 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1447 if (KQueueSet(sock
->fd
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, &sock
->kqEntry
))
1449 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1454 // Watch for incoming data
1455 if (KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
))
1457 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1458 close(sock
->fd
); // Closing the descriptor removes all filters from the kqueue
1462 if (fcntl(sock
->fd
, F_SETFL
, fcntl(sock
->fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1464 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1465 return mStatus_UnknownErr
;
1468 // initiate connection wth peer
1469 if (connect(sock
->fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1471 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1472 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock
->fd
, errno
, strerror(errno
));
1474 return mStatus_ConnFailed
;
1477 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1478 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1482 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1483 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1485 mStatus err
= mStatus_NoError
;
1487 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1488 if (!sock
) return(mDNSNULL
);
1490 memset(sock
, 0, sizeof(*sock
));
1492 sock
->flags
= flags
;
1494 if (flags
& kTCPSocketFlags_UseTLS
)
1496 #ifndef NO_SECURITYFRAMEWORK
1497 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1499 err
= tlsSetupSock(sock
, mDNStrue
);
1500 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1502 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1503 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1505 err
= mStatus_UnsupportedErr
;
1506 #endif /* NO_SECURITYFRAMEWORK */
1508 #ifndef NO_SECURITYFRAMEWORK
1512 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1516 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1520 #ifndef NO_SECURITYFRAMEWORK
1521 if (sock
->tlsContext
)
1523 SSLClose(sock
->tlsContext
);
1524 SSLDisposeContext(sock
->tlsContext
);
1525 sock
->tlsContext
= NULL
;
1527 #endif /* NO_SECURITYFRAMEWORK */
1530 shutdown(sock
->fd
, 2);
1535 freeL("mDNSPlatformTCPCloseConnection", sock
);
1539 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1542 *closed
= mDNSfalse
;
1544 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1546 #ifndef NO_SECURITYFRAMEWORK
1547 if (!sock
->handshakecomplete
)
1549 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1550 mStatus err
= SSLHandshake(sock
->tlsContext
);
1551 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1552 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1553 else if (err
== errSSLWouldBlock
) return(0);
1554 else { LogMsg("Read SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1557 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1558 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t*)&nread
);
1559 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1560 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1561 else if (err
&& err
!= errSSLWouldBlock
)
1562 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1566 #endif /* NO_SECURITYFRAMEWORK */
1570 static int CLOSEDcount
= 0;
1571 static int EAGAINcount
= 0;
1572 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1574 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
1575 else if (nread
== 0)
1578 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
1580 // else nread is negative -- see what kind of error we got
1581 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1582 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno
, strerror(errno
)); nread
= -1; }
1583 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1586 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1593 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1597 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1599 #ifndef NO_SECURITYFRAMEWORK
1601 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1603 if (!err
) nsent
= (int) processed
;
1604 else if (err
== errSSLWouldBlock
) nsent
= 0;
1605 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1608 #endif /* NO_SECURITYFRAMEWORK */
1612 nsent
= send(sock
->fd
, msg
, len
, 0);
1615 if (errno
== EAGAIN
) nsent
= 0;
1616 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1623 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1628 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1629 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1630 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
)
1632 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1633 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1634 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1636 const int twofivefive
= 255;
1637 mStatus err
= mStatus_NoError
;
1638 char *errstr
= mDNSNULL
;
1640 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1641 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1643 // ... with a shared UDP port, if it's for multicast receiving
1644 if (mDNSSameIPPort(port
, MulticastDNSPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1645 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1647 if (sa_family
== AF_INET
)
1649 // We want to receive destination addresses
1650 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1651 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1653 // We want to receive interface identifiers
1654 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1655 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1657 // We want to receive packet TTL value so we can check it
1658 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1659 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1661 // Send unicast packets with TTL 255
1662 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1663 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1665 // And multicast packets with TTL 255 too
1666 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1667 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1669 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1670 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1671 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1673 // And start listening for packets
1674 struct sockaddr_in listening_sockaddr
;
1675 listening_sockaddr
.sin_family
= AF_INET
;
1676 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1677 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1678 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1679 if (err
) { errstr
= "bind"; goto fail
; }
1681 else if (sa_family
== AF_INET6
)
1683 // We want to receive destination addresses and receive interface identifiers
1684 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1685 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1687 // We want to receive packet hop count value so we can check it
1688 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1689 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1691 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1692 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1693 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1694 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1696 // Send unicast packets with TTL 255
1697 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1698 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1700 // And multicast packets with TTL 255 too
1701 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1702 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1704 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1706 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1707 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1708 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1709 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1712 // Want to receive our own packets
1713 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1714 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1716 // And start listening for packets
1717 struct sockaddr_in6 listening_sockaddr6
;
1718 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1719 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1720 listening_sockaddr6
.sin6_family
= AF_INET6
;
1721 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1722 listening_sockaddr6
.sin6_flowinfo
= 0;
1723 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
1724 listening_sockaddr6
.sin6_scope_id
= 0;
1725 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1726 if (err
) { errstr
= "bind"; goto fail
; }
1729 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1730 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
1732 k
->KQcallback
= myKQSocketCallBack
;
1734 k
->KQtask
= "UDP packet reception";
1735 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
1740 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1741 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
1742 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1744 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1745 if (!strcmp(errstr
, "bind") && mDNSSameIPPort(port
, MulticastDNSPort
) && errno
== EADDRINUSE
)
1746 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1747 "Congratulations, you've reproduced an elusive bug.\r"
1748 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1749 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1750 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1756 struct UDPSocket_struct
1761 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort port
)
1764 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
1765 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
1766 memset(p
, 0, sizeof(UDPSocket
));
1770 err
= SetupSocket(&p
->ss
, port
, AF_INET
);
1773 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1774 // of failing to bind to this port when Internet Sharing has already bound to it
1775 if (mDNSSameIPPort(port
, NATPMPPort
))
1776 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1777 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1778 freeL("UDPSocket", p
);
1784 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1786 if (ss
->sktv4
!= -1)
1791 if (ss
->sktv6
!= -1)
1798 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
1800 CloseSocketSet(&sock
->ss
);
1801 freeL("UDPSocket", sock
);
1804 #if COMPILER_LIKES_PRAGMA_MARK
1806 #pragma mark - Key Management
1809 #ifndef NO_SECURITYFRAMEWORK
1810 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
1812 CFMutableArrayRef certChain
= NULL
;
1813 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
1814 SecCertificateRef cert
;
1815 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
1816 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
1819 SecPolicySearchRef searchRef
;
1820 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
1821 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
1824 SecPolicyRef policy
;
1825 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
1826 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
1829 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
1830 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
1834 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
1835 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
1838 err
= SecTrustEvaluate(trust
, NULL
);
1839 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
1842 CFArrayRef rawCertChain
;
1843 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1844 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
1845 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
1848 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
1849 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
1852 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1853 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1854 CFArraySetValueAtIndex(certChain
, 0, identity
);
1855 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1856 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
1858 CFRelease(rawCertChain
);
1859 // Do not free statusChain:
1860 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1861 // certChain: Call the CFRelease function to release this object when you are finished with it.
1862 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1867 CFRelease(wrappedCert
);
1871 CFRelease(searchRef
);
1877 #endif /* NO_SECURITYFRAMEWORK */
1879 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
1881 #ifdef NO_SECURITYFRAMEWORK
1882 return mStatus_UnsupportedErr
;
1884 SecIdentityRef identity
= nil
;
1885 SecIdentitySearchRef srchRef
= nil
;
1888 // search for "any" identity matching specified key use
1889 // In this app, we expect there to be exactly one
1890 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
1891 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
1893 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
1894 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
1896 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
1897 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
1899 // Found one. Call getCertChain to create the correct certificate chain.
1900 ServerCerts
= GetCertChain(identity
);
1901 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
1903 return mStatus_NoError
;
1904 #endif /* NO_SECURITYFRAMEWORK */
1907 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
1909 #ifndef NO_SECURITYFRAMEWORK
1910 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
1911 #endif /* NO_SECURITYFRAMEWORK */
1914 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1915 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1917 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1918 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1921 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1926 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1927 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1929 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1932 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1937 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1940 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1941 if (!state
) return mDNSfalse
;
1942 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1943 return val
? mDNStrue
: mDNSfalse
;
1946 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
1948 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
1950 if (sa
->sa_family
== AF_INET
)
1952 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
1953 ip
->type
= mDNSAddrType_IPv4
;
1954 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
1955 return(mStatus_NoError
);
1958 if (sa
->sa_family
== AF_INET6
)
1960 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
1961 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
1962 // value into the second word of the IPv6 link-local address, so they can just
1963 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
1964 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
1965 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
1966 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1967 ip
->type
= mDNSAddrType_IPv6
;
1968 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
1969 return(mStatus_NoError
);
1972 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
1973 return(mStatus_Invalid
);
1976 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
1978 mDNSEthAddr eth
= zeroEthAddr
;
1979 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
1982 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
1985 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
1988 CFRange range
= { 0, 6 }; // Offset, length
1989 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
1990 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
1993 CFRelease(entityname
);
2000 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2001 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2002 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2003 // (e.g. sa_family not AF_INET or AF_INET6)
2004 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
2006 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
2007 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
2010 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
2011 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
2013 NetworkInterfaceInfoOSX
**p
;
2014 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
2015 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
2017 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
2018 (*p
)->Exists
= mDNStrue
;
2019 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2020 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
2024 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
2025 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
2026 if (!i
) return(mDNSNULL
);
2027 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
2028 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
2029 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
2030 strcpy(i
->ifa_name
, ifa
->ifa_name
); // This is safe because we know we allocated i->ifa_name with sufficient space
2032 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2034 i
->ifinfo
.mask
= mask
;
2035 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
2036 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
2037 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
2038 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
2041 i
->Exists
= mDNStrue
;
2042 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
2044 i
->Flashing
= mDNSfalse
;
2045 i
->Occulting
= mDNSfalse
;
2046 i
->scope_id
= scope_id
;
2048 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2049 i
->ifa_flags
= ifa
->ifa_flags
;
2055 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2056 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2058 NetworkInterfaceInfoOSX
*i
;
2059 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2060 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2061 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
2067 #if APPLE_OSX_mDNSResponder
2069 #if COMPILER_LIKES_PRAGMA_MARK
2071 #pragma mark - AutoTunnel
2074 #define kRacoonPort 4500
2076 static mDNSBool AnonymousRacoonConfig
= mDNSfalse
;
2078 // MUST be called with lock held
2079 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
2081 ServiceRecordSet
*p
;
2082 for (p
= m
->ServiceRegistrations
; p
; p
= p
->uDNS_next
)
2084 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, p
->RR_SRV
.resrec
.name
);
2085 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
2090 // MUST be called with lock held
2091 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
2094 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
2095 if (p
->q
.ThisQInterval
< 0)
2100 mDNSlocal
void RegisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2102 if (info
->AutoTunnelNAT
.clientContext
&& !info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && AutoTunnelUnregistered(info
))
2105 LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info
->domain
.c
, m
->hostlabel
.c
);
2107 // 1. Set up our address record for the internal tunnel address
2108 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2109 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
2110 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
2111 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
2112 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
2113 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2114 err
= mDNS_Register(m
, &info
->AutoTunnelHostRecord
);
2115 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2117 // 2. Set up device info record
2118 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
2119 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
2120 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
2121 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
2122 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
2123 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
2124 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2125 err
= mDNS_Register(m
, &info
->AutoTunnelDeviceInfo
);
2126 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2128 // 3. Set up our address record for the external tunnel address
2129 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2130 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
2131 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
2132 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
2133 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2136 mDNS_AddDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
, mDNSNULL
, info
);
2139 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2140 AssignDomainName (&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2141 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
2142 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
2143 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
2144 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
2145 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
2146 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
2147 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2148 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
2149 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2151 LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2152 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
2153 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
2157 mDNSlocal
void DeregisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2159 LogOperation("DeregisterAutoTunnelRecords %##s", info
->domain
.c
);
2160 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2162 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
2165 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2166 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2170 mDNS_RemoveDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
);
2174 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2176 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
2179 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2180 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2184 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2186 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
2189 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2190 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2195 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2197 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
2198 if (result
== mStatus_MemFree
)
2200 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
2201 RegisterAutoTunnelRecords(m
,info
);
2205 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
2207 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
2208 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
2209 n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), m
->hostlabel
.c
, info
->domain
.c
);
2211 m
->NextSRVUpdate
= m
->timenow
;
2212 DeregisterAutoTunnelRecords(m
,info
);
2213 RegisterAutoTunnelRecords(m
,info
);
2215 // Determine whether we need racoon to accept incoming connections
2216 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2217 if (info
->AutoTunnel
&& !info
->deltime
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
))
2219 mDNSBool needRacoonConfig
= info
!= mDNSNULL
;
2220 if (needRacoonConfig
!= AnonymousRacoonConfig
)
2222 AnonymousRacoonConfig
= needRacoonConfig
;
2223 // Create or revert configuration file, and start (or SIGHUP) Racoon
2224 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, info
? info
->b64keydata
: "");
2228 mDNSlocal
void AbortDeregistration(mDNS
*const m
, AuthRecord
*rr
)
2230 if (rr
->resrec
.RecordType
== kDNSRecordTypeDeregistering
)
2232 LogOperation("Aborting deregistration of %s", ARDisplayString(m
, rr
));
2233 CompleteDeregistration(m
, rr
);
2235 else if (rr
->resrec
.RecordType
!= kDNSRecordTypeUnregistered
)
2236 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m
, rr
));
2239 // Before SetupLocalAutoTunnelInterface_internal is called,
2240 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2241 // Must be called with the lock held
2242 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
)
2244 LogOperation("SetupLocalAutoTunnelInterface");
2246 // 1. Configure the local IPv6 address
2247 if (!m
->AutoTunnelHostAddrActive
)
2249 m
->AutoTunnelHostAddrActive
= mDNStrue
;
2250 LogMsg("Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
2251 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
2254 // 2. If we have at least one server (pending) listening, publish our records
2255 if (TunnelServers(m
))
2257 DomainAuthInfo
*info
;
2258 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2260 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
2262 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
2263 AbortDeregistration(m
, &info
->AutoTunnelHostRecord
);
2264 AbortDeregistration(m
, &info
->AutoTunnelDeviceInfo
);
2265 AbortDeregistration(m
, &info
->AutoTunnelService
);
2267 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2268 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2269 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2270 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2272 // Try to get a NAT port mapping for the AutoTunnelService
2273 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
2274 info
->AutoTunnelNAT
.clientContext
= info
;
2275 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
2276 info
->AutoTunnelNAT
.IntPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2277 info
->AutoTunnelNAT
.RequestedPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2278 info
->AutoTunnelNAT
.NATLease
= 0;
2279 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
2280 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err
);
2286 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
2288 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
));
2291 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2292 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2294 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
2296 DNSQuestion
*q
= m
->Questions
;
2299 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== kDNSType_AAAA
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
2301 LogOperation("Restart %##s", q
->qname
.c
);
2302 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
2303 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2304 mDNS_StopQuery(m
, q
);
2305 mDNS_StartQuery(m
, q
);
2306 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
2307 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
2308 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2309 // In general we have to assume that the question list might have changed in arbitrary ways.
2310 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2311 // already in use. The safest solution is just to go back to the start of the list and start again.
2312 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2313 // just one suspended question, so it's really a 2n algorithm.
2321 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
2323 ClientTunnel
**p
= &m
->TunnelClients
;
2324 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
2325 if (*p
) *p
= tun
->next
;
2326 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
2327 freeL("ClientTunnel", tun
);
2330 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2332 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
2333 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
2335 if (!AddRecord
) return;
2336 mDNS_StopQuery(m
, question
);
2338 if (!answer
->rdlength
)
2340 LogOperation("AutoTunnelCallback NXDOMAIN %##s", question
->qname
.c
);
2341 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
2345 if (question
->qtype
== kDNSType_AAAA
)
2347 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
2349 LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
2350 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
2354 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
2355 LogOperation("AutoTunnelCallback: dst host %.16a", &tun
->rmt_inner
);
2356 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2357 AppendDomainName(&question
->qname
, &tun
->dstname
);
2358 question
->qtype
= kDNSType_SRV
;
2359 mDNS_StartQuery(m
, &tun
->q
);
2361 else if (question
->qtype
== kDNSType_SRV
)
2363 LogOperation("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
2364 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
2365 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
2366 question
->qtype
= kDNSType_A
;
2367 mDNS_StartQuery(m
, &tun
->q
);
2369 else if (question
->qtype
== kDNSType_A
)
2371 ClientTunnel
*old
= mDNSNULL
;
2372 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer
->rdata
->u
.ipv4
);
2373 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
2374 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
2375 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
2376 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
2377 tmpDst
.ip
.v4
= tun
->rmt_outer
;
2378 mDNSAddr tmpSrc
= zeroAddr
;
2379 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
2380 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
2381 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
2383 ClientTunnel
**p
= &tun
->next
;
2384 mDNSBool needSetKeys
= mDNStrue
;
2387 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
2390 LogOperation("Found existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2393 if (old
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &old
->q
);
2394 else if (!mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
2395 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
2396 !mDNSSameIPv6Address(old
->rmt_inner
, tun
->rmt_inner
) ||
2397 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
2398 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
2400 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2401 AutoTunnelSetKeys(old
, mDNSfalse
);
2403 else needSetKeys
= mDNSfalse
;
2405 freeL("ClientTunnel", old
);
2409 if (needSetKeys
) LogOperation("New AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2411 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
); mDNS_Unlock(m
); };
2413 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
2414 // Kick off any questions that were held pending this tunnel setup
2415 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
2418 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
2421 // Must be called with the lock held
2422 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
2424 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
2426 AssignDomainName(&p
->dstname
, &q
->qname
);
2427 p
->markedForDeletion
= mDNSfalse
;
2428 p
->loc_inner
= zerov6Addr
;
2429 p
->loc_outer
= zerov4Addr
;
2430 p
->rmt_inner
= zerov6Addr
;
2431 p
->rmt_outer
= zerov4Addr
;
2432 p
->rmt_outer_port
= zeroIPPort
;
2433 mDNS_snprintf(p
->b64keydata
, sizeof(p
->b64keydata
), "%s", q
->AuthInfo
->b64keydata
);
2434 p
->next
= m
->TunnelClients
;
2435 m
->TunnelClients
= p
; // Intentionally build list in reverse order
2437 p
->q
.InterfaceID
= mDNSInterface_Any
;
2438 p
->q
.Target
= zeroAddr
;
2439 AssignDomainName(&p
->q
.qname
, &q
->qname
);
2440 p
->q
.qtype
= kDNSType_AAAA
;
2441 p
->q
.qclass
= kDNSClass_IN
;
2442 p
->q
.LongLived
= mDNSfalse
;
2443 p
->q
.ExpectUnique
= mDNStrue
;
2444 p
->q
.ForceMCast
= mDNSfalse
;
2445 p
->q
.ReturnIntermed
= mDNStrue
;
2446 p
->q
.QuestionCallback
= AutoTunnelCallback
;
2447 p
->q
.QuestionContext
= p
;
2449 LogOperation("AddNewClientTunnel start %##s (%s)%s", &p
->q
.qname
.c
, DNSTypeName(p
->q
.qtype
), q
->LongLived
? " LongLived" : "");
2450 mDNS_StartQuery_internal(m
, &p
->q
);
2453 #endif // APPLE_OSX_mDNSResponder
2455 #if COMPILER_LIKES_PRAGMA_MARK
2457 #pragma mark - Power State & Configuration Change Management
2460 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2462 mDNSBool foundav4
= mDNSfalse
;
2463 mDNSBool foundav6
= mDNSfalse
;
2464 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2465 struct ifaddrs
*v4Loopback
= NULL
;
2466 struct ifaddrs
*v6Loopback
= NULL
;
2467 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2468 char defaultname
[32];
2470 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2471 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2473 if (m
->SleepState
) ifa
= NULL
;
2477 #if LIST_ALL_INTERFACES
2478 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2479 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2480 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2481 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2482 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2483 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2484 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2485 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2486 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2487 if (!(ifa
->ifa_flags
& IFF_UP
))
2488 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2489 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2490 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2491 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2492 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2493 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2494 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2495 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2496 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2497 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2498 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2501 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2503 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2504 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2505 mDNSPlatformMemCopy(PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
2508 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2509 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2511 if (!ifa
->ifa_netmask
)
2514 SetupAddr(&ip
, ifa
->ifa_addr
);
2515 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2516 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2518 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2521 SetupAddr(&ip
, ifa
->ifa_addr
);
2522 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2523 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2527 int ifru_flags6
= 0;
2529 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2530 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2532 struct in6_ifreq ifr6
;
2533 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
2534 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2535 ifr6
.ifr_addr
= *sin6
;
2536 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2537 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2538 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2541 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2543 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2545 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2547 else if (sin6
->sin6_addr
.s6_addr
[0] != 0xFD) v6Loopback
= ifa
;
2552 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2553 if (i
&& MulticastInterface(i
))
2555 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2556 else foundav6
= mDNStrue
;
2562 ifa
= ifa
->ifa_next
;
2565 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2566 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2567 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2569 // Now the list is complete, set the McastTxRx setting for each interface.
2570 NetworkInterfaceInfoOSX
*i
;
2571 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2574 mDNSBool txrx
= MulticastInterface(i
);
2575 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2576 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2578 if (i
->ifinfo
.McastTxRx
!= txrx
)
2580 i
->ifinfo
.McastTxRx
= txrx
;
2581 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2586 if (InfoSocket
>= 0) close(InfoSocket
);
2589 // If we haven't set up AutoTunnelHostAddr yet, do it now
2590 if (!mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
2592 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2593 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
2594 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
2595 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
2596 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
2597 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
2598 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
2599 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
2600 m
->AutoTunnelHostAddr
.b
[0x8] = PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
2601 m
->AutoTunnelHostAddr
.b
[0x9] = PrimaryMAC
.b
[1];
2602 m
->AutoTunnelHostAddr
.b
[0xA] = PrimaryMAC
.b
[2];
2603 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
2604 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
2605 m
->AutoTunnelHostAddr
.b
[0xD] = PrimaryMAC
.b
[3];
2606 m
->AutoTunnelHostAddr
.b
[0xE] = PrimaryMAC
.b
[4];
2607 m
->AutoTunnelHostAddr
.b
[0xF] = PrimaryMAC
.b
[5];
2608 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
2609 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
2610 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
2611 LogOperation("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
2614 #ifndef kDefaultLocalHostNamePrefix
2615 #define kDefaultLocalHostNamePrefix "Macintosh"
2617 mDNS_snprintf(defaultname
, sizeof(defaultname
), kDefaultLocalHostNamePrefix
"-%02X%02X%02X%02X%02X%02X",
2618 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2620 // Set up the nice label
2621 domainlabel nicelabel
;
2623 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2624 if (nicelabel
.c
[0] == 0)
2626 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2627 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2630 // Set up the RFC 1034-compliant label
2631 domainlabel hostlabel
;
2633 GetUserSpecifiedLocalHostName(&hostlabel
);
2634 if (hostlabel
.c
[0] == 0)
2636 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2637 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2640 mDNSBool namechange
= mDNSfalse
;
2642 // We use a case-sensitive comparison here because even though changing the capitalization
2643 // of the name alone is not significant to DNS, it's still a change from the user's point of view
2644 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2645 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2648 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2649 LogMsg("User updated Computer Name from %#s to %#s", m
->p
->usernicelabel
.c
, nicelabel
.c
);
2650 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2651 namechange
= mDNStrue
;
2654 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2655 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2658 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2659 LogMsg("User updated Local Hostname from %#s to %#s", m
->p
->userhostlabel
.c
, hostlabel
.c
);
2660 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2662 namechange
= mDNStrue
;
2665 #if APPLE_OSX_mDNSResponder
2666 if (namechange
) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
2668 DomainAuthInfo
*info
;
2669 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2670 if (info
->AutoTunnelNAT
.clientContext
&& !mDNSIPv4AddressIsOnes(info
->AutoTunnelNAT
.ExternalAddress
))
2671 AutoTunnelNATCallback(m
, &info
->AutoTunnelNAT
);
2675 return(mStatus_NoError
);
2678 #if LogAllOperations || MDNS_DEBUGMSGS
2679 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
2680 // Returns -1 if all the one-bits are not contiguous
2681 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2683 int i
= 0, bits
= 0;
2684 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2687 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2688 while (b
& 0x80) { bits
++; b
<<= 1; }
2691 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2696 // returns count of non-link local V4 addresses registered
2697 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2699 NetworkInterfaceInfoOSX
*i
;
2701 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2704 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
2705 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2706 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2708 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2710 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2711 n
->InterfaceID
= mDNSNULL
;
2714 if (!n
->InterfaceID
)
2716 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2717 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2718 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2719 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2720 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2721 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2722 // 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.
2723 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2724 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
2725 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2726 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2727 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2728 i
->Flashing
? " (Flashing)" : "",
2729 i
->Occulting
? " (Occulting)" : "",
2730 n
->InterfaceActive
? " (Primary)" : "");
2734 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2737 if (i
->sa_family
== AF_INET
)
2740 primary
->ifa_v4addr
.s_addr
= i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
2741 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
2742 imr
.imr_interface
= primary
->ifa_v4addr
;
2743 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
2744 // Joining same group twice can give "Address already in use" error -- no need to report that
2745 if (err
< 0 && errno
!= EADDRINUSE
)
2746 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
2749 if (i
->sa_family
== AF_INET6
)
2751 struct ipv6_mreq i6mr
;
2752 i6mr
.ipv6mr_interface
= primary
->scope_id
;
2753 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
2754 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2755 // Joining same group twice can give "Address already in use" error -- no need to report that
2756 if (err
< 0 && errno
!= EADDRINUSE
)
2757 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
2765 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2767 NetworkInterfaceInfoOSX
*i
;
2768 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2770 if (i
->Exists
) i
->LastSeen
= utc
;
2771 i
->Exists
= mDNSfalse
;
2775 // returns count of non-link local V4 addresses deregistered
2776 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2779 // If an interface is going away, then deregister this from the mDNSCore.
2780 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2781 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2782 // it refers to has gone away we'll crash.
2783 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2784 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2785 NetworkInterfaceInfoOSX
*i
;
2787 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2789 // If this interface is no longer active, or its InterfaceID is changing, deregister it
2790 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2791 if (i
->ifinfo
.InterfaceID
)
2792 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2794 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
2795 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2796 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2797 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
2798 i
->Flashing
? " (Flashing)" : "",
2799 i
->Occulting
? " (Occulting)" : "",
2800 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2801 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
2802 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2803 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2804 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2805 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2806 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2811 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2812 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2816 // If no longer active, delete interface from list and free memory
2819 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2820 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2821 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2822 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2823 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2824 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2828 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2829 freeL("NetworkInterfaceInfoOSX", i
);
2830 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2838 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
2840 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
2841 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
2844 dnle
->next
= mDNSNULL
;
2846 AssignDomainName(&dnle
->name
, name
);
2848 *List
= &dnle
->next
;
2852 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
2855 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
2858 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
2859 if (fqdn
) fqdn
->c
[0] = 0;
2860 if (RegDomains
) *RegDomains
= NULL
;
2861 if (BrowseDomains
) *BrowseDomains
= NULL
;
2863 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
2864 setservers
? " setservers" : "",
2865 setsearch
? " setsearch" : "",
2866 fqdn
? " fqdn" : "",
2867 RegDomains
? " RegDomains" : "",
2868 BrowseDomains
? " BrowseDomains" : "");
2870 // Add the inferred address-based configuration discovery domains
2871 // (should really be in core code I think, not platform-specific)
2874 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2878 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
2880 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
2881 !SetupAddr(&a
, ifa
->ifa_addr
) &&
2882 !SetupAddr(&n
, ifa
->ifa_netmask
) &&
2883 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
2885 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2886 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
2887 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
2888 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
2889 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
2890 mDNS_AddSearchDomain_CString(buf
);
2892 ifa
= ifa
->ifa_next
;
2896 #ifndef MDNS_NO_DNSINFO
2897 if (setservers
|| setsearch
)
2899 dns_config_t
*config
= dns_configuration_copy();
2902 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2903 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2904 // Apparently this is expected behaviour -- "not a bug".
2905 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2906 // If we are still getting failures after three minutes, then we log them.
2907 if (mDNSMacOSXSystemBuildNumber(NULL
) > 7 && (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
2908 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2912 LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config
->n_resolver
);
2915 for (i
= 0; i
< config
->n_resolver
; i
++)
2918 dns_resolver_t
*r
= config
->resolver
[i
];
2919 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
2920 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
2921 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
2922 if (r
->port
== 5353) continue;
2923 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2924 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2926 for (j
= 0; j
< config
->n_resolver
; j
++) // check if this is the lowest-weighted server for the domain
2928 dns_resolver_t
*p
= config
->resolver
[j
];
2929 if (p
->port
== 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
2930 if (p
->search_order
<= r
->search_order
)
2933 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2934 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2935 if (SameDomainName(&d
, &tmp
))
2936 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2939 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2940 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
);
2943 mDNSInterfaceID interface
= mDNSInterface_Any
;
2946 // DNS server option parsing
2947 if (r
->options
!= NULL
)
2949 char *nextOption
= r
->options
;
2950 char *currentOption
= NULL
;
2951 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
2953 // The option may be in the form of interface=xxx where xxx is an interface name.
2954 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
2956 NetworkInterfaceInfoOSX
*i
;
2957 char ifname
[IF_NAMESIZE
+1];
2958 mDNSu32 ifindex
= 0;
2959 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
2960 // This allows us to block these special queries from going out on the wire.
2961 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
2962 ifindex
= if_nametoindex(ifname
);
2963 if (ifindex
== 0) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname
); continue; }
2964 LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__
, r
->domain
, ifname
, ifindex
);
2965 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
2966 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
2967 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2968 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) break;
2969 if (i
!= NULL
) interface
= i
->ifinfo
.InterfaceID
;
2970 if (interface
== mDNSNULL
) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex
, ifname
); continue; }
2974 for (n
= 0; n
< r
->n_nameserver
; n
++)
2975 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& (interface
|| disabled
|| !AddrRequiresPPPConnection(r
->nameserver
[n
])))
2978 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
2979 debugf("Adding dns server from slot %d %#a for domain %##s", i
, &saddr
, d
.c
);
2980 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
2983 DNSServer
*s
= mDNS_AddDNSServer(m
, &d
, mDNSInterface_Any
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
);
2984 if (s
&& disabled
) s
->teststate
= DNSServer_Disabled
;
2992 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
2993 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
2994 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
2995 // instead use the search domain list as the sole authority for what domains to search and in what order
2996 // (and the domain from the "domain" field will also appear somewhere in that list).
2997 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
2998 // search lists for other resolvers in the list need to be ignored.
2999 if (config
->resolver
[0]->n_search
== 0) mDNS_AddSearchDomain_CString(config
->resolver
[0]->domain
);
3000 else for (i
= 0; i
< config
->resolver
[0]->n_search
; i
++) mDNS_AddSearchDomain_CString(config
->resolver
[0]->search
[i
]);
3002 dns_configuration_free(config
);
3003 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
3004 setsearch
= mDNSfalse
;
3007 #endif // MDNS_NO_DNSINFO
3009 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
3012 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
3017 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("HostNames"));
3018 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
3020 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
3021 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
3022 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
3024 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
3027 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3028 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
3029 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
3030 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
3038 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("RegistrationDomains"));
3039 if (regArray
&& CFArrayGetCount(regArray
) > 0)
3041 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
3042 if (regDict
&& DDNSSettingEnabled(regDict
))
3044 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
3047 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3048 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3049 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
3052 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
3053 AppendDNameListElem(&RegDomains
, 0, &d
);
3062 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("BrowseDomains"));
3065 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
3067 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
3068 if (browseDict
&& DDNSSettingEnabled(browseDict
))
3070 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
3073 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3074 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3075 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
3078 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
3079 AppendDNameListElem(&BrowseDomains
, 0, &d
);
3091 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
3094 CFIndex size
= CFDictionaryGetCount(btmm
);
3095 const void *key
[size
];
3096 const void *val
[size
];
3097 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
3098 for (i
= 0; i
< size
; i
++)
3100 LogOperation("BackToMyMac %d", i
);
3101 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3102 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
3105 mDNSu32 uid
= atoi(buf
);
3106 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3107 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
3108 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
3110 LogOperation("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
3111 AppendDNameListElem(&RegDomains
, uid
, &d
);
3119 if (setservers
|| setsearch
)
3121 CFStringRef key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3124 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, key
);
3129 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
3132 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
3134 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
3136 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
3137 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
3138 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
3139 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
3145 // Add the manual and/or DHCP-dicovered search domains
3146 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
3149 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
3151 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
3152 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3153 mDNS_AddSearchDomain_CString(buf
);
3156 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3158 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3159 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3160 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3161 // instead use the search domain list as the sole authority for what domains to search and in what order
3162 // (and the domain from the "domain" field will also appear somewhere in that list).
3163 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
3164 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3165 mDNS_AddSearchDomain_CString(buf
);
3177 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
3179 SCDynamicStoreRef store
= NULL
;
3180 CFDictionaryRef dict
= NULL
;
3181 CFStringRef key
= NULL
;
3182 CFStringRef string
= NULL
;
3188 // get IPv4 settings
3190 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
3191 require_action(store
, exit
, err
= mStatus_UnknownErr
);
3193 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3194 require_action(key
, exit
, err
= mStatus_UnknownErr
);
3196 dict
= SCDynamicStoreCopyValue(store
, key
);
3197 require_action(dict
, exit
, err
= mStatus_UnknownErr
);
3199 // handle router changes
3201 r
->type
= mDNSAddrType_IPv4
;
3202 r
->ip
.v4
= zerov4Addr
;
3204 string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3208 struct sockaddr_in saddr
;
3210 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
3211 LogMsg("Could not convert router to CString");
3214 saddr
.sin_len
= sizeof(saddr
);
3215 saddr
.sin_family
= AF_INET
;
3217 inet_aton(buf
, &saddr
.sin_addr
);
3219 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) debugf("Ignoring router %s (requires PPP connection)", buf
);
3220 else *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
3224 // handle primary interface changes
3225 // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
3226 if (nAdditions
|| nDeletions
) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3228 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3232 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3233 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3235 *v4
= *v6
= zeroAddr
;
3237 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
3239 // find primary interface in list
3240 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
3242 mDNSAddr tmp6
= zeroAddr
;
3243 if (!strcmp(buf
, ifa
->ifa_name
))
3245 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
3247 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
3249 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3251 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3252 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3253 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
3258 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3259 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
3261 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3262 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
3265 ifa
= ifa
->ifa_next
;
3268 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3269 // V4 to communicate w/ our DNS server
3273 if (dict
) CFRelease(dict
);
3274 if (key
) CFRelease(key
);
3275 if (store
) CFRelease(store
);
3279 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
3281 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
3282 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3283 ConvertDomainNameToCString(dname
, uname
);
3289 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
3293 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3294 // That single entity is a CFDictionary with name "HostNames".
3295 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3296 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3297 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3298 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3299 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3301 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
3302 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
3303 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
3304 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
3307 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
3308 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
3311 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
3314 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
3317 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
3320 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, StateDict
);
3321 CFRelease(StateDict
);
3323 CFRelease(StateVals
[0]);
3325 CFRelease(HostVals
[0]);
3327 CFRelease(StatusVals
[0]);
3329 CFRelease(HostKeys
[0]);
3333 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3334 mDNSexport
void SetDomainSecrets(mDNS
*m
)
3336 #ifdef NO_SECURITYFRAMEWORK
3338 LogMsg("Note: SetDomainSecrets: no keychain support");
3340 mDNSBool haveAutoTunnels
= mDNSfalse
;
3342 LogOperation("SetDomainSecrets");
3344 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3345 // In the case where the user simultaneously removes their DDNS host name and the key
3346 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3347 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3348 // address records behind that we no longer have permission to delete.
3349 DomainAuthInfo
*ptr
;
3350 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3351 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
3353 #if APPLE_OSX_mDNSResponder
3355 // Mark all TunnelClients for deletion
3356 ClientTunnel
*client
;
3357 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3359 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
3360 client
->markedForDeletion
= mDNStrue
;
3363 #endif APPLE_OSX_mDNSResponder
3365 // String Array used to write list of private domains to Dynamic Store
3366 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3367 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3369 CFDataRef data
= NULL
;
3370 const int itemsPerEntry
= 3; // domain name, key name, key value
3371 CFArrayRef secrets
= NULL
;
3372 int err
= mDNSKeychainGetSecrets(&secrets
);
3373 if (err
|| !secrets
)
3374 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
3377 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
3378 // Iterate through the secrets
3379 for (i
= 0; i
< ArrayCount
; ++i
)
3382 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
3383 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
3384 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3385 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
3386 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
3387 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3389 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3391 // Get DNS domain this key is for
3392 char stringbuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal domainname as C-string, including terminating NUL
3393 data
= CFArrayGetValueAtIndex(entry
, 0);
3394 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3395 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
3396 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3397 stringbuf
[CFDataGetLength(data
)] = '\0';
3400 if (!MakeDomainNameFromDNSNameString(&domain
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf
); continue; }
3403 data
= CFArrayGetValueAtIndex(entry
, 1);
3404 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3405 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
3406 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3407 stringbuf
[CFDataGetLength(data
)] = '\0';
3410 if (!MakeDomainNameFromDNSNameString(&keyname
, stringbuf
)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf
); continue; }
3413 data
= CFArrayGetValueAtIndex(entry
, 2);
3414 if (CFDataGetLength(data
) >= (int)sizeof(stringbuf
))
3415 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
3416 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)stringbuf
);
3417 stringbuf
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3419 DomainAuthInfo
*FoundInList
;
3420 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
3421 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
3423 #if APPLE_OSX_mDNSResponder
3426 // If any client tunnel destination is in this domain, set deletion flag to false
3427 ClientTunnel
*client
;
3428 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3429 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
3431 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
3432 client
->markedForDeletion
= mDNSfalse
;
3433 // If the key has changed, reconfigure the tunnel
3434 if (strncmp(stringbuf
, client
->b64keydata
, sizeof(client
->b64keydata
)))
3436 mDNSBool queryNotInProgress
= client
->q
.ThisQInterval
< 0;
3437 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client
->dstname
.c
, queryNotInProgress
? "reconfiguring" : "query in progress");
3438 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNSfalse
);
3439 mDNS_snprintf(client
->b64keydata
, sizeof(client
->b64keydata
), "%s", stringbuf
);
3440 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNStrue
);
3445 mDNSBool keyChanged
= FoundInList
&& FoundInList
->AutoTunnel
? strncmp(stringbuf
, FoundInList
->b64keydata
, sizeof(FoundInList
->b64keydata
)) : mDNSfalse
;
3447 #endif APPLE_OSX_mDNSResponder
3449 // Uncomment the line below to view the keys as they're read out of the system keychain
3450 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3451 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
3453 // If didn't find desired domain in the list, make a new entry
3455 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
3458 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
3459 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
3462 LogOperation("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
3463 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, stringbuf
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
3465 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3469 #if APPLE_OSX_mDNSResponder
3470 if (keyChanged
&& AnonymousRacoonConfig
)
3472 LogOperation("SetDomainSecrets: secret changed for %##s", &domain
);
3473 (void)mDNSConfigureServer(kmDNSUp
, stringbuf
);
3475 #endif APPLE_OSX_mDNSResponder
3477 ConvertDomainNameToCString(&domain
, stringbuf
);
3478 CFStringRef cfs
= CFStringCreateWithCString(NULL
, stringbuf
, kCFStringEncodingUTF8
);
3479 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
3483 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, sa
);
3486 #if APPLE_OSX_mDNSResponder
3488 // clean up ClientTunnels
3489 ClientTunnel
**ptr
= &m
->TunnelClients
;
3492 if ((*ptr
)->markedForDeletion
)
3494 ClientTunnel
*cur
= *ptr
;
3495 LogOperation("SetDomainSecrets: removing client %##s from list", cur
->dstname
.c
);
3496 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
3497 AutoTunnelSetKeys(cur
, mDNSfalse
);
3499 freeL("ClientTunnel", cur
);
3502 ptr
= &(*ptr
)->next
;
3505 DomainAuthInfo
*info
= m
->AuthInfoList
;
3508 if (info
->AutoTunnel
&& info
->deltime
&& info
->AutoTunnelNAT
.clientContext
)
3510 // stop the NAT operation
3511 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
3512 if (info
->AutoTunnelNAT
.clientCallback
)
3514 // Reset port and let the AutoTunnelNATCallback handle cleanup
3515 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
3516 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
3517 info
->AutoTunnelNAT
.Lifetime
= 0;
3518 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
3519 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3520 info
->AutoTunnelNAT
.clientCallback(m
, &info
->AutoTunnelNAT
);
3521 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3523 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
3528 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
3530 // remove interface if no autotunnel servers and no more client tunnels
3531 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3532 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
3533 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
3534 memset(m
->AutoTunnelHostAddr
.b
, 0, sizeof(m
->AutoTunnelHostAddr
.b
));
3537 if (!haveAutoTunnels
&& AnonymousRacoonConfig
)
3539 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3540 AnonymousRacoonConfig
= mDNSfalse
;
3541 (void)mDNSConfigureServer(kmDNSDown
, "");
3544 if (m
->AutoTunnelHostAddr
.b
[0])
3545 if (TunnelClients(m
) || TunnelServers(m
))
3546 SetupLocalAutoTunnelInterface_internal(m
);
3548 #endif APPLE_OSX_mDNSResponder
3550 #endif /* NO_SECURITYFRAMEWORK */
3553 mDNSlocal
void SetLocalDomains(void)
3555 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3556 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3558 CFArrayAppendValue(sa
, CFSTR("local"));
3559 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
3560 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
3561 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
3562 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
3563 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
3565 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, sa
);
3569 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3571 LogOperation("*** Network Configuration Change *** (%d)%s",
3572 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
3573 m
->p
->NetworkChanged
? "" : " (no scheduled configuration change)");
3574 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3575 mDNSs32 utc
= mDNSPlatformUTC();
3576 MarkAllInterfacesInactive(m
, utc
);
3577 UpdateInterfaceList(m
, utc
);
3578 ClearInactiveInterfaces(m
, utc
);
3579 SetupActiveInterfaces(m
, utc
);
3581 #if APPLE_OSX_mDNSResponder
3583 if (m
->AutoTunnelHostAddr
.b
[0])
3586 if (TunnelClients(m
) || TunnelServers(m
))
3587 SetupLocalAutoTunnelInterface_internal(m
);
3591 // Scan to find client tunnels whose questions have completed,
3592 // but whose local inner/outer addresses have changed since the tunnel was set up
3594 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
3595 if (p
->q
.ThisQInterval
< 0)
3597 mDNSAddr tmpSrc
= zeroAddr
;
3598 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
3599 tmpDst
.ip
.v4
= p
->rmt_outer
;
3600 mDNSPlatformSourceAddrForDest(&tmpSrc
, &tmpDst
);
3601 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
3602 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
3604 AutoTunnelSetKeys(p
, mDNSfalse
);
3605 p
->loc_inner
= m
->AutoTunnelHostAddr
;
3606 p
->loc_outer
= tmpSrc
.ip
.v4
;
3607 AutoTunnelSetKeys(p
, mDNStrue
);
3611 #endif APPLE_OSX_mDNSResponder
3613 uDNS_SetupDNSConfig(m
);
3615 if (m
->MainCallback
)
3616 m
->MainCallback(m
, mStatus_ConfigChanged
);
3619 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3621 (void)store
; // Parameter not used
3622 (void)changedKeys
; // Parameter not used
3623 mDNS
*const m
= (mDNS
*const)context
;
3627 mDNSs32 delay
= mDNSPlatformOneSecond
; // Start off assuming a one-second delay
3629 int c
= CFArrayGetCount(changedKeys
); // Count changes
3630 CFRange range
= { 0, c
};
3631 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
3632 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
3633 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
3634 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/20; // If these were the only changes, shorten delay
3636 #if LogAllOperations
3641 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
3642 LogOperation("*** NetworkChanged SC key: %s", buf
);
3644 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
3646 c1
? "(Local Hostname) " : "",
3647 c2
? "(Computer Name) " : "",
3648 c3
? "(DynamicDNS) " : "",
3652 if (!m
->p
->NetworkChanged
||
3653 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3654 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3656 // KeyChain frequently fails to notify clients of change events. To work around this
3657 // we set a timer and periodically poll to detect if any changes have occurred.
3658 // Without this Back To My Mac just does't work for a large number of users.
3659 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
3660 if (c3
|| CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_BackToMyMac
))
3662 LogOperation("*** NetworkChanged *** starting KeyChainBugTimer");
3663 m
->p
->KeyChainBugTimer
= NonZeroTime(m
->timenow
+ delay
);
3664 m
->p
->KeyChainBugInterval
= mDNSPlatformOneSecond
;
3667 if (!m
->SuppressSending
||
3668 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3669 m
->SuppressSending
= m
->p
->NetworkChanged
;
3672 KQueueUnlock(m
, "NetworkChanged");
3675 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3678 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3679 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3680 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3681 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3682 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3683 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3685 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3686 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3688 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
3689 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
3690 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
3691 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
3692 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
3693 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
3694 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
3695 CFArrayAppendValue(patterns
, pattern1
);
3696 CFArrayAppendValue(patterns
, pattern2
);
3697 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3698 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3699 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3701 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3702 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3704 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3705 m
->p
->Store
= store
;
3710 if (store
) CFRelease(store
);
3713 if (patterns
) CFRelease(patterns
);
3714 if (pattern2
) CFRelease(pattern2
);
3715 if (pattern1
) CFRelease(pattern1
);
3716 if (keys
) CFRelease(keys
);
3721 #ifndef NO_SECURITYFRAMEWORK
3722 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
3724 LogOperation("*** Keychain Changed ***");
3725 mDNS
*const m
= (mDNS
*const)context
;
3727 OSStatus err
= SecKeychainCopyDefault(&skc
);
3730 if (info
->keychain
== skc
)
3732 // 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
3733 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
3736 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
3737 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
3738 SecKeychainAttributeList
*a
= NULL
;
3739 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
3742 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
3743 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
3744 SecKeychainItemFreeAttributesAndData(a
, NULL
);
3749 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
3751 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
3752 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
3753 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
3754 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
3757 SetDomainSecrets(m
);
3759 KQueueUnlock(m
, "KeychainChanged");
3770 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3772 mDNS
*const m
= (mDNS
*const)refcon
;
3774 (void)service
; // Parameter not used
3777 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3778 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3779 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3780 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3781 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3782 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3783 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3784 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3785 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3786 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3787 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3788 // Just to be safe, also make sure our interface list is fully up to date, in case we
3789 // haven't yet received the System Configuration Framework "network changed" event that
3790 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3791 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3792 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3793 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3794 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3795 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3796 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3798 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3799 KQueueUnlock(m
, "Sleep/Wake");
3801 #endif /* NO_IOPOWER */
3803 #if COMPILER_LIKES_PRAGMA_MARK
3805 #pragma mark - Initialization & Teardown
3808 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3809 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3810 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3811 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3813 // Major version 6 is 10.2.x (Jaguar)
3814 // Major version 7 is 10.3.x (Panther)
3815 // Major version 8 is 10.4.x (Tiger)
3816 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3818 int major
= 0, minor
= 0;
3819 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
3820 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3823 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3824 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3825 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3826 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3827 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3828 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3829 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3832 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
3833 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3837 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3838 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3839 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3840 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3843 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3845 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3848 struct sockaddr_in s5353
;
3849 s5353
.sin_family
= AF_INET
;
3850 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3851 s5353
.sin_addr
.s_addr
= 0;
3852 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3856 if (err
) LogMsg("No unicast UDP responses");
3857 else debugf("Unicast UDP responses okay");
3861 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3862 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3863 // (.local manually generated via explicit callback)
3864 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3865 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3866 // 4) result above should generate a callback from question in (1). result added to global list
3867 // 5) global list delivered to client via GetSearchDomainList()
3868 // 6) client calls to enumerate domains now go over LocalOnly interface
3869 // (!!!KRS may add outgoing interface in addition)
3871 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3875 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3876 // 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.
3878 for (i
=0; i
<100; i
++)
3880 domainlabel testlabel
;
3882 GetUserSpecifiedLocalHostName(&testlabel
);
3883 if (testlabel
.c
[0]) break;
3887 m
->hostlabel
.c
[0] = 0;
3889 char *HINFO_HWstring
= "Macintosh";
3890 char HINFO_HWstring_buffer
[256];
3891 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3892 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3893 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3894 HINFO_HWstring
= HINFO_HWstring_buffer
;
3896 char HINFO_SWstring
[256] = "";
3897 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3898 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3900 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3901 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3902 if (hlen
+ slen
< 254)
3904 m
->HIHardware
.c
[0] = hlen
;
3905 m
->HISoftware
.c
[0] = slen
;
3906 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
3907 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
3910 m
->p
->permanentsockets
.m
= m
;
3911 m
->p
->permanentsockets
.sktv4
= m
->p
->permanentsockets
.sktv6
= -1;
3912 m
->p
->permanentsockets
.kqsv4
.KQcallback
= m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
3913 m
->p
->permanentsockets
.kqsv4
.KQcontext
= m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
3914 m
->p
->permanentsockets
.kqsv4
.KQtask
= m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
3916 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
);
3918 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
);
3921 struct sockaddr_in s4
;
3922 socklen_t n4
= sizeof(s4
);
3923 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
3924 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
3926 if (m
->p
->permanentsockets
.sktv6
>= 0)
3928 struct sockaddr_in6 s6
;
3929 socklen_t n6
= sizeof(s6
);
3930 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
3931 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
3935 m
->p
->InterfaceList
= mDNSNULL
;
3936 m
->p
->userhostlabel
.c
[0] = 0;
3937 m
->p
->usernicelabel
.c
[0] = 0;
3938 m
->p
->NotifyUser
= 0;
3939 m
->p
->KeyChainBugTimer
= 0;
3941 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
3943 mDNSs32 utc
= mDNSPlatformUTC();
3944 UpdateInterfaceList(m
, utc
);
3945 SetupActiveInterfaces(m
, utc
);
3947 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3948 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
3949 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
3950 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
3951 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3952 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
3953 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
3955 err
= WatchForNetworkChanges(m
);
3956 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
3958 // Explicitly ensure that our Keychain operations utilize the system domain.
3959 #ifndef NO_SECURITYFRAMEWORK
3960 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
3964 SetDomainSecrets(m
);
3968 #ifndef NO_SECURITYFRAMEWORK
3969 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
3970 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
3974 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
3975 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
3976 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
3977 #endif /* NO_IOPOWER */
3979 return(mStatus_NoError
);
3982 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
3985 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
3988 mStatus result
= mDNSPlatformInit_setup(m
);
3990 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3991 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3992 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
3996 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
3998 if (m
->p
->PowerConnection
)
4000 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
4002 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
4003 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
4004 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
4005 IOServiceClose ( m
->p
->PowerConnection
);
4006 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
4007 #endif /* NO_IOPOWER */
4008 m
->p
->PowerConnection
= 0;
4013 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
4014 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
4015 CFRelease(m
->p
->StoreRLS
);
4016 CFRelease(m
->p
->Store
);
4018 m
->p
->StoreRLS
= NULL
;
4021 mDNSs32 utc
= mDNSPlatformUTC();
4022 MarkAllInterfacesInactive(m
, utc
);
4023 ClearInactiveInterfaces(m
, utc
);
4024 CloseSocketSet(&m
->p
->permanentsockets
);
4026 #if APPLE_OSX_mDNSResponder
4027 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
4029 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
4030 LogMsg("Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
4031 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
4033 #endif // APPLE_OSX_mDNSResponder
4036 #if COMPILER_LIKES_PRAGMA_MARK
4038 #pragma mark - General Platform Support Layer functions
4041 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
4043 return(mach_absolute_time());
4046 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
4048 mDNSexport mStatus
mDNSPlatformTimeInit(void)
4050 // Notes: Typical values for mach_timebase_info:
4051 // tbi.numer = 1000 million
4052 // tbi.denom = 33 million
4053 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
4054 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
4055 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
4056 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
4057 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
4059 // Arithmetic notes:
4060 // tbi.denom is at least 1, and not more than 2^32-1.
4061 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
4062 // tbi.denom is at least 1, and not more than 2^32-1.
4063 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
4064 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
4065 // which is unlikely on any current or future Macintosh.
4066 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
4067 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
4068 struct mach_timebase_info tbi
;
4069 kern_return_t result
= mach_timebase_info(&tbi
);
4070 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
4074 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
4076 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
4078 static uint64_t last_mach_absolute_time
= 0;
4079 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
4080 uint64_t this_mach_absolute_time
= mach_absolute_time();
4081 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
4083 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
4084 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
4085 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
4086 last_mach_absolute_time
= this_mach_absolute_time
;
4087 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4088 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4089 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
4090 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4091 "This error occurs from time to time, often on newly released hardware, "
4092 "and usually the exact cause is different in each instance.\r\r"
4093 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4094 "and assign it to Radar Component “Kernel” Version “X”.");
4096 last_mach_absolute_time
= this_mach_absolute_time
;
4098 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
4101 mDNSexport mDNSs32
mDNSPlatformUTC(void)
4106 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4107 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
4108 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
4109 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
4110 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
4111 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
4112 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
4113 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
4114 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4115 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
4117 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }