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.496 2007/10/04 20:33:05 mcguire
21 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
23 Revision 1.495 2007/10/02 05:03:38 cheshire
24 Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
26 Revision 1.494 2007/09/29 20:40:19 cheshire
27 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
29 Revision 1.493 2007/09/29 03:16:45 cheshire
30 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
31 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
33 Revision 1.492 2007/09/28 23:58:35 mcguire
34 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
37 Revision 1.491 2007/09/27 23:28:53 mcguire
38 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
40 Revision 1.490 2007/09/26 23:01:21 mcguire
41 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
43 Revision 1.489 2007/09/26 22:58:16 mcguire
44 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
46 Revision 1.488 2007/09/26 00:32:45 cheshire
47 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
49 Revision 1.487 2007/09/21 17:07:41 mcguire
50 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
52 Revision 1.486 2007/09/19 23:17:38 cheshire
53 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
55 Revision 1.485 2007/09/19 21:44:29 cheshire
56 Improved "mDNSKeychainGetSecrets failed" error message
58 Revision 1.484 2007/09/18 21:44:55 cheshire
59 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
60 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
62 Revision 1.483 2007/09/17 22:19:39 mcguire
63 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
64 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
66 Revision 1.482 2007/09/14 21:16:03 cheshire
67 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
69 Revision 1.481 2007/09/14 21:14:56 mcguire
70 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
72 Revision 1.480 2007/09/13 00:16:42 cheshire
73 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
75 Revision 1.479 2007/09/12 19:22:20 cheshire
76 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
77 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
79 Revision 1.478 2007/09/07 22:21:45 vazquez
80 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
82 Revision 1.477 2007/09/07 21:22:30 cheshire
83 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
84 Don't log failures binding to port 5351
86 Revision 1.476 2007/09/06 20:38:08 cheshire
87 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
89 Revision 1.475 2007/09/05 02:24:28 cheshire
90 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
91 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
93 Revision 1.474 2007/09/04 22:32:58 mcguire
94 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
96 Revision 1.473 2007/08/31 19:53:15 cheshire
97 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
98 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
100 Revision 1.472 2007/08/31 18:49:49 vazquez
101 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
103 Revision 1.471 2007/08/31 02:05:46 cheshire
104 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
106 Revision 1.470 2007/08/30 22:50:04 mcguire
107 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
109 Revision 1.469 2007/08/30 19:40:51 cheshire
110 Added syslog messages to report various initialization failures
112 Revision 1.468 2007/08/30 00:12:20 cheshire
113 Check error codes and log failures during AutoTunnel setup
115 Revision 1.467 2007/08/28 00:33:04 jgraessley
116 <rdar://problem/5423932> Selective compilation options
118 Revision 1.466 2007/08/24 23:25:55 cheshire
119 Debugging messages to help track down duplicate items being read from system keychain
121 Revision 1.465 2007/08/24 00:39:12 cheshire
122 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
124 Revision 1.464 2007/08/24 00:15:21 cheshire
125 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
127 Revision 1.463 2007/08/23 21:02:35 cheshire
128 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
130 Revision 1.462 2007/08/18 01:02:03 mcguire
131 <rdar://problem/5415593> No Bonjour services are getting registered at boot
133 Revision 1.461 2007/08/10 22:25:57 mkrochma
134 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
136 Revision 1.460 2007/08/08 22:34:59 mcguire
137 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
139 Revision 1.459 2007/08/08 21:07:48 vazquez
140 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
142 Revision 1.458 2007/08/03 02:18:41 mcguire
143 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
145 Revision 1.457 2007/08/02 16:48:45 mcguire
146 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
148 Revision 1.456 2007/08/02 03:28:30 vazquez
149 Make ExternalAddress and err unused to fix build warnings
151 Revision 1.455 2007/08/01 03:09:22 cheshire
152 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
154 Revision 1.454 2007/07/31 23:08:34 mcguire
155 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
157 Revision 1.453 2007/07/31 19:13:58 mkrochma
158 No longer need to include "btmm" in hostname to avoid name conflicts
160 Revision 1.452 2007/07/27 19:30:41 cheshire
161 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
162 to properly reflect tri-state nature of the possible responses
164 Revision 1.451 2007/07/25 22:25:45 cheshire
165 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
167 Revision 1.450 2007/07/25 21:19:10 cheshire
168 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
170 Revision 1.449 2007/07/25 01:36:09 mcguire
171 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
173 Revision 1.448 2007/07/24 21:30:09 cheshire
174 Added "AutoTunnel server listening for connections..." diagnostic message
176 Revision 1.447 2007/07/24 20:24:18 cheshire
177 Only remove AutoTunnel address if we have created it.
178 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
180 Revision 1.446 2007/07/24 03:00:09 cheshire
181 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
183 Revision 1.445 2007/07/23 20:26:26 cheshire
184 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
185 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
186 for existence of "Setup:/Network/DynamicDNS" settings
188 Revision 1.444 2007/07/21 00:54:49 cheshire
189 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
191 Revision 1.443 2007/07/20 23:23:11 cheshire
192 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
194 Revision 1.442 2007/07/20 20:23:24 cheshire
195 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
196 Fixed errors reading the Setup:/Network/BackToMyMac preferences
198 Revision 1.441 2007/07/20 16:46:45 mcguire
199 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
201 Revision 1.440 2007/07/20 16:22:07 mcguire
202 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
204 Revision 1.439 2007/07/20 01:14:56 cheshire
205 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
206 Cleaned up log messages
208 Revision 1.438 2007/07/20 00:54:21 cheshire
209 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
211 Revision 1.437 2007/07/19 22:01:27 cheshire
212 Added "#pragma mark" sections headings to divide code into related function groups
214 Revision 1.436 2007/07/18 03:25:25 cheshire
215 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
216 Bring up server-side tunnel on demand, when necessary
218 Revision 1.435 2007/07/18 01:05:08 cheshire
219 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
220 Add list of client tunnels so we can automatically reconfigure when local address changes
222 Revision 1.434 2007/07/16 20:16:00 vazquez
223 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
224 Remove unnecessary LNT init code
226 Revision 1.433 2007/07/14 00:36:07 cheshire
227 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
229 Revision 1.432 2007/07/12 23:55:11 cheshire
230 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
231 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
233 Revision 1.431 2007/07/12 23:34:48 cheshire
234 Removed 'LogOperation' message to reduce verbosity in syslog
236 Revision 1.430 2007/07/12 22:16:46 cheshire
237 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
239 Revision 1.429 2007/07/12 02:51:28 cheshire
240 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
242 Revision 1.428 2007/07/11 23:17:31 cheshire
243 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
244 Improve log message to indicate if we're starting or restarting racoon
246 Revision 1.427 2007/07/11 22:50:30 cheshire
247 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
248 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
250 Revision 1.426 2007/07/11 20:40:49 cheshire
251 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
252 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
254 Revision 1.425 2007/07/11 19:24:19 cheshire
255 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
256 Configure internal AutoTunnel address
257 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
258 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
260 Revision 1.424 2007/07/11 19:00:27 cheshire
261 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
263 Revision 1.423 2007/07/11 03:00:59 cheshire
264 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
265 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
267 Revision 1.422 2007/07/10 01:21:20 cheshire
268 Added (commented out) line for displaying key data for debugging
270 Revision 1.421 2007/06/25 20:58:11 cheshire
271 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
272 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
274 Revision 1.420 2007/06/22 21:52:14 cheshire
275 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
277 Revision 1.419 2007/06/22 21:32:00 cheshire
278 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
280 Revision 1.418 2007/06/21 16:37:43 jgraessley
282 Reviewed by: Stuart Cheshire
283 Additional changes to get this compiling on the embedded platform.
285 Revision 1.417 2007/06/20 01:44:00 cheshire
286 More information in "Network Configuration Change" message
288 Revision 1.416 2007/06/20 01:10:12 cheshire
289 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
291 Revision 1.415 2007/06/15 19:23:38 cheshire
292 <rdar://problem/5254053> mDNSResponder renames my host without asking
293 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
295 Revision 1.414 2007/05/17 22:00:59 cheshire
296 <rdar://problem/5210966> Lower network change delay from two seconds to one second
298 Revision 1.413 2007/05/16 16:43:27 cheshire
299 Only log "bind" failures for our shared mDNS port and for binding to zero
300 -- other attempts to bind to a particular port may legitimately fail
302 Revision 1.412 2007/05/15 21:49:21 cheshire
303 Get rid of "#pragma unused"
305 Revision 1.411 2007/05/14 23:54:55 cheshire
306 Instead of sprintf, use safer length-limited mDNS_snprintf
308 Revision 1.410 2007/05/12 01:05:00 cheshire
309 Updated debugging messages
311 Revision 1.409 2007/05/10 22:39:48 cheshire
312 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
313 Only define CountMaskBits for builds with debugging messages
315 Revision 1.408 2007/05/10 22:19:00 cheshire
316 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
317 Don't deliver multicast packets for which we can't find an associated InterfaceID
319 Revision 1.407 2007/05/10 21:40:28 cheshire
320 Don't log unnecessary "Address already in use" errors when joining multicast groups
322 Revision 1.406 2007/05/08 00:56:17 cheshire
323 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
325 Revision 1.405 2007/05/04 20:21:39 cheshire
326 Improve "connect failed" error message
328 Revision 1.404 2007/05/02 19:41:53 cheshire
329 No need to alarm people with "Connection reset by peer" syslog message
331 Revision 1.403 2007/04/28 01:31:59 cheshire
332 Improve debugging support for catching memory corruption problems
334 Revision 1.402 2007/04/26 22:54:57 cheshire
335 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
337 Revision 1.401 2007/04/26 00:35:16 cheshire
338 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
339 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
340 inside the firewall may give answers where a public one gives none, and vice versa.)
342 Revision 1.400 2007/04/24 21:50:27 cheshire
343 Debugging: Show list of changedKeys in NetworkChanged callback
345 Revision 1.399 2007/04/23 22:28:47 cheshire
346 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
348 Revision 1.398 2007/04/23 04:57:00 cheshire
349 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
351 Revision 1.397 2007/04/22 06:02:03 cheshire
352 <rdar://problem/4615977> Query should immediately return failure when no server
354 Revision 1.396 2007/04/21 21:47:47 cheshire
355 <rdar://problem/4376383> Daemon: Add watchdog timer
357 Revision 1.395 2007/04/18 20:58:34 cheshire
358 <rdar://problem/5140339> Domain discovery not working over VPN
359 Needed different code to handle the case where there's only a single search domain
361 Revision 1.394 2007/04/17 23:05:50 cheshire
362 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
364 Revision 1.393 2007/04/17 19:21:29 cheshire
365 <rdar://problem/5140339> Domain discovery not working over VPN
367 Revision 1.392 2007/04/17 17:15:09 cheshire
368 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
370 Revision 1.391 2007/04/07 01:01:48 cheshire
371 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
373 Revision 1.390 2007/04/06 18:45:02 cheshire
374 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
376 Revision 1.389 2007/04/05 21:39:49 cheshire
377 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
379 Revision 1.388 2007/04/05 21:09:52 cheshire
380 Condense sprawling code
382 Revision 1.387 2007/04/05 20:40:37 cheshire
383 Remove unused mDNSPlatformTCPGetFlags()
385 Revision 1.386 2007/04/05 19:50:56 cheshire
386 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
388 Revision 1.385 2007/04/03 19:39:19 cheshire
389 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
391 Revision 1.384 2007/03/31 01:10:53 cheshire
394 Revision 1.383 2007/03/31 00:13:48 cheshire
397 Revision 1.382 2007/03/28 21:01:29 cheshire
398 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
400 Revision 1.381 2007/03/28 15:56:37 cheshire
401 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
403 Revision 1.380 2007/03/26 22:54:46 cheshire
406 Revision 1.379 2007/03/22 18:31:48 cheshire
407 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
409 Revision 1.378 2007/03/22 00:49:20 cheshire
410 <rdar://problem/4848295> Advertise model information via Bonjour
412 Revision 1.377 2007/03/21 00:30:05 cheshire
413 <rdar://problem/4789455> Multiple errors in DNameList-related code
415 Revision 1.376 2007/03/20 17:07:15 cheshire
416 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
418 Revision 1.375 2007/03/20 00:50:57 cheshire
419 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
421 Revision 1.374 2007/03/06 23:29:50 cheshire
422 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
424 Revision 1.373 2007/02/28 01:51:20 cheshire
425 Added comment about reverse-order IP address
427 Revision 1.372 2007/02/28 01:06:48 cheshire
428 Use %#a format code instead of %d.%d.%d.%d
430 Revision 1.371 2007/02/08 21:12:28 cheshire
431 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
433 Revision 1.370 2007/01/16 22:59:58 cheshire
434 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
436 Revision 1.369 2007/01/10 02:09:32 cheshire
437 Better LogOperation record of keys read from System Keychain
439 Revision 1.368 2007/01/10 01:25:31 cheshire
440 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
442 Revision 1.367 2007/01/10 01:22:01 cheshire
443 Make sure c1, c2, c3 are initialized
445 Revision 1.366 2007/01/09 22:37:20 cheshire
446 Provide ten-second grace period for deleted keys, to give mDNSResponder
447 time to delete host name before it gives up access to the required key.
449 Revision 1.365 2007/01/09 21:09:20 cheshire
450 Need locking in KeychainChanged()
452 Revision 1.364 2007/01/09 20:17:04 cheshire
453 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
455 Revision 1.363 2007/01/09 02:41:18 cheshire
456 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
457 moved it to mDNS_Init() in mDNS.c (core code)
459 Revision 1.362 2007/01/08 23:54:01 cheshire
460 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
462 Revision 1.361 2007/01/05 08:30:48 cheshire
463 Trim excessive "$Log" checkin history from before 2006
464 (checkin history still available via "cvs log ..." of course)
466 Revision 1.360 2007/01/04 00:12:24 cheshire
467 <rdar://problem/4742742> Read *all* DNS keys from keychain,
468 not just key for the system-wide default registration domain
470 Revision 1.359 2006/12/22 21:14:37 cheshire
471 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
472 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
474 Revision 1.358 2006/12/22 20:59:50 cheshire
475 <rdar://problem/4742742> Read *all* DNS keys from keychain,
476 not just key for the system-wide default registration domain
478 Revision 1.357 2006/12/21 00:09:45 cheshire
479 Use mDNSPlatformMemZero instead of bzero
481 Revision 1.356 2006/12/20 23:15:53 mkrochma
482 Fix the private domain list code so that it actually works
484 Revision 1.355 2006/12/20 23:04:36 mkrochma
485 Fix crash when adding private domain list to Dynamic Store
487 Revision 1.354 2006/12/19 22:43:55 cheshire
488 Fix compiler warnings
490 Revision 1.353 2006/12/14 22:08:29 cheshire
491 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
492 to release data allocated by SecKeychainItemCopyAttributesAndData()
494 Revision 1.352 2006/12/14 02:33:26 cheshire
495 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
497 Revision 1.351 2006/11/28 21:37:51 mkrochma
498 Tweak where the private DNS data is written
500 Revision 1.350 2006/11/28 07:55:02 herscher
501 <rdar://problem/4742743> dnsextd has a slow memory leak
503 Revision 1.349 2006/11/28 07:45:58 herscher
504 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
506 Revision 1.348 2006/11/16 21:47:20 mkrochma
507 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
509 Revision 1.347 2006/11/10 00:54:16 cheshire
510 <rdar://problem/4816598> Changing case of Computer Name doesn't work
512 Revision 1.346 2006/10/31 02:34:58 cheshire
513 <rdar://problem/4692130> Stop creating HINFO records
515 Revision 1.345 2006/09/21 20:04:38 mkrochma
516 Accidently changed function name while checking in previous fix
518 Revision 1.344 2006/09/21 19:04:13 mkrochma
519 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
521 Revision 1.343 2006/09/15 21:20:16 cheshire
522 Remove uDNS_info substructure from mDNS_struct
524 Revision 1.342 2006/08/16 00:31:50 mkrochma
525 <rdar://problem/4386944> Get rid of NotAnInteger references
527 Revision 1.341 2006/08/14 23:24:40 cheshire
528 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
530 Revision 1.340 2006/07/29 19:11:13 mkrochma
531 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
533 Revision 1.339 2006/07/27 03:24:35 cheshire
534 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
535 Further refinement: Declare KQueueEntry parameter "const"
537 Revision 1.338 2006/07/27 02:59:25 cheshire
538 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
539 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
540 after releasing BigMutex, in case actions it took have resulted in new work for the
541 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
542 add new active interfaces to its list, and consequently schedule queries to be sent).
544 Revision 1.337 2006/07/22 06:11:37 cheshire
545 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
547 Revision 1.336 2006/07/15 02:01:32 cheshire
548 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
549 Fix broken "empty string" browsing
551 Revision 1.335 2006/07/14 05:25:11 cheshire
552 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
553 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
555 Revision 1.334 2006/07/05 23:42:00 cheshire
556 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
558 Revision 1.333 2006/06/29 05:33:30 cheshire
559 <rdar://problem/4607043> mDNSResponder conditional compilation options
561 Revision 1.332 2006/06/28 09:10:36 cheshire
562 Extra debugging messages
564 Revision 1.331 2006/06/21 22:29:42 cheshire
565 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
567 Revision 1.330 2006/06/20 23:06:00 cheshire
568 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
570 Revision 1.329 2006/06/08 23:22:33 cheshire
573 Revision 1.328 2006/03/19 03:27:49 cheshire
574 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
576 Revision 1.327 2006/03/19 02:00:09 cheshire
577 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
579 Revision 1.326 2006/03/08 22:42:23 cheshire
580 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
582 Revision 1.325 2006/01/10 00:39:17 cheshire
583 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
585 Revision 1.324 2006/01/09 19:28:59 cheshire
586 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
588 Revision 1.323 2006/01/05 21:45:27 cheshire
589 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
591 Revision 1.322 2006/01/05 21:41:50 cheshire
592 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
594 Revision 1.321 2006/01/05 21:35:06 cheshire
595 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
599 // ***************************************************************************
601 // Supporting routines to run mDNS on a CFRunLoop platform
602 // ***************************************************************************
604 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
605 // including ones that mDNSResponder chooses not to use.
606 #define LIST_ALL_INTERFACES 0
608 // For enabling AAAA records over IPv4. Setting this to 0 sends only
609 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
610 // AAAA and A records over both IPv4 and IPv6.
611 #define AAAA_OVER_V4 1
613 // 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
614 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
615 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
616 // 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.
617 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
618 // so were willing to make that sacrifice.
619 // In Mac OS X 10.5, in 2007, two things have changed:
620 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
621 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
623 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
625 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
626 #include "DNSCommon.h"
628 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
629 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
630 #include "PlatformCommon.h"
634 #include <stdarg.h> // For va_list support
636 #include <net/if_types.h> // For IFT_ETHER
637 #include <net/if_dl.h>
639 #include <sys/param.h>
640 #include <sys/socket.h>
641 #include <sys/sysctl.h>
642 #include <sys/event.h>
644 #include <sys/ioctl.h>
645 #include <time.h> // platform support for UTC time
646 #include <arpa/inet.h> // for inet_aton
649 #include <netinet/in.h> // For IP_RECVTTL
651 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
654 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
655 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
656 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
657 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
659 #if TARGET_OS_EMBEDDED
660 #define NO_SECURITYFRAMEWORK 1
663 #ifndef NO_SECURITYFRAMEWORK
664 #include <Security/SecureTransport.h>
665 #include <Security/Security.h>
666 #endif /* NO_SECURITYFRAMEWORK */
668 #include <DebugServices.h>
671 // Code contributed by Dave Heller:
672 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
673 // work on Mac OS X 10.1, which does not have the getifaddrs call.
674 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
675 #if RUN_ON_PUMA_WITHOUT_IFADDRS
676 #include "mDNSMacOSXPuma.c"
681 #include <IOKit/IOKitLib.h>
682 #include <IOKit/IOMessage.h>
683 #include <mach/mach_error.h>
684 #include <mach/mach_port.h>
685 #include <mach/mach_time.h>
688 #define kInterfaceSpecificOption "interface="
690 // ***************************************************************************
693 #if COMPILER_LIKES_PRAGMA_MARK
694 #pragma mark - Globals
697 static mDNSu32 clockdivisor
= 0;
699 mDNSexport
int KQueueFD
;
701 #ifndef NO_SECURITYFRAMEWORK
702 static CFArrayRef ServerCerts
;
703 #endif /* NO_SECURITYFRAMEWORK */
705 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
707 CFStringRef NetworkChangedKey_IPv4
;
708 CFStringRef NetworkChangedKey_IPv6
;
709 CFStringRef NetworkChangedKey_Hostnames
;
710 CFStringRef NetworkChangedKey_Computername
;
711 CFStringRef NetworkChangedKey_DNS
;
712 CFStringRef NetworkChangedKey_DynamicDNS
= CFSTR("Setup:/Network/DynamicDNS");
713 CFStringRef NetworkChangedKey_BackToMyMac
= CFSTR("Setup:/Network/BackToMyMac");
715 // ***************************************************************************
718 #if COMPILER_LIKES_PRAGMA_MARK
720 #pragma mark - Utility Functions
723 // We only attempt to send and receive multicast packets on interfaces that are
724 // (a) flagged as multicast-capable
725 // (b) *not* flagged as point-to-point (e.g. modem)
726 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
727 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
728 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
729 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
731 mDNSexport
void NotifyOfElusiveBug(const char *title
, const char *msg
) // Both strings are UTF-8 text
733 static int notifyCount
= 0;
734 if (notifyCount
) return;
736 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
737 // To avoid this, we don't try to display alerts in the first three minutes after boot.
738 if ((mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return;
740 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
743 // Determine if we're at Apple (17.*.*.*)
744 extern mDNS mDNSStorage
;
745 NetworkInterfaceInfoOSX
*i
;
746 for (i
= mDNSStorage
.p
->InterfaceList
; i
; i
= i
->next
)
747 if (i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
&& i
->ifinfo
.ip
.ip
.v4
.b
[0] == 17)
749 if (!i
) return; // If not at Apple, don't show the alert
755 // Display a notification to the user
758 #ifndef NO_CFUSERNOTIFICATION
759 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.)";
760 CFStringRef alertHeader
= CFStringCreateWithCString(NULL
, title
, kCFStringEncodingUTF8
);
761 CFStringRef alertBody
= CFStringCreateWithCString(NULL
, msg
, kCFStringEncodingUTF8
);
762 CFStringRef alertFooter
= CFStringCreateWithCString(NULL
, footer
, kCFStringEncodingUTF8
);
763 CFStringRef alertMessage
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\r\r%@"), alertBody
, alertFooter
);
764 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel
, NULL
, NULL
, NULL
, alertHeader
, alertMessage
, NULL
);
765 #endif /* NO_CFUSERNOTIFICATION */
768 mDNSlocal
struct ifaddrs
*myGetIfAddrs(int refresh
)
770 static struct ifaddrs
*ifa
= NULL
;
778 if (ifa
== NULL
) getifaddrs(&ifa
);
783 mDNSlocal NetworkInterfaceInfoOSX
*SearchForInterfaceByName(mDNS
*const m
, const char *ifname
, int type
)
785 NetworkInterfaceInfoOSX
*i
;
786 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
787 if (i
->Exists
&& !strcmp(i
->ifa_name
, ifname
) &&
789 (type
== AF_INET
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ||
790 (type
== AF_INET6
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
))) return(i
);
794 mDNSlocal
int myIfIndexToName(u_short index
, char *name
)
797 for (ifa
= myGetIfAddrs(0); ifa
; ifa
= ifa
->ifa_next
)
798 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
799 if (((struct sockaddr_dl
*)ifa
->ifa_addr
)->sdl_index
== index
)
800 { strlcpy(name
, ifa
->ifa_name
, IF_NAMESIZE
); return 0; }
804 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS
*const m
, mDNSu32 index
)
806 NetworkInterfaceInfoOSX
*i
;
807 if (index
== kDNSServiceInterfaceIndexLocalOnly
) return(mDNSInterface_LocalOnly
);
808 if (index
== kDNSServiceInterfaceIndexAny
) return(mDNSNULL
);
810 // Don't get tricked by inactive interfaces with no InterfaceID set
811 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
812 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
814 // Not found. Make sure our interface list is up to date, then try again.
815 LogOperation("InterfaceID for interface index %d not found; Updating interface list", index
);
816 mDNSMacOSXNetworkChanged(m
);
817 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
818 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== index
) return(i
->ifinfo
.InterfaceID
);
823 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID(mDNS
*const m
, mDNSInterfaceID id
)
825 NetworkInterfaceInfoOSX
*i
;
826 if (id
== mDNSInterface_LocalOnly
) return(kDNSServiceInterfaceIndexLocalOnly
);
827 if (id
== mDNSInterface_Any
) return(0);
829 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
830 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
831 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
833 // Not found. Make sure our interface list is up to date, then try again.
834 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id
);
835 mDNSMacOSXNetworkChanged(m
);
836 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
837 if ((mDNSInterfaceID
)i
== id
) return(i
->scope_id
);
842 #if COMPILER_LIKES_PRAGMA_MARK
844 #pragma mark - UDP & TCP send & receive
847 mDNSlocal mDNSBool
AddrRequiresPPPConnection(const struct sockaddr
*addr
)
849 mDNSBool result
= mDNSfalse
;
850 SCNetworkConnectionFlags flags
;
851 SCNetworkReachabilityRef ReachRef
= NULL
;
853 ReachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, addr
);
854 if (!ReachRef
) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end
; }
855 if (!SCNetworkReachabilityGetFlags(ReachRef
, &flags
)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end
; }
856 result
= flags
& kSCNetworkFlagsConnectionRequired
;
859 if (ReachRef
) CFRelease(ReachRef
);
863 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
864 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
865 // OR send via our primary v4 unicast socket
866 mDNSexport mStatus
mDNSPlatformSendUDP(const mDNS
*const m
, const void *const msg
, const mDNSu8
*const end
,
867 mDNSInterfaceID InterfaceID
, const mDNSAddr
*dst
, mDNSIPPort dstPort
)
869 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
870 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
871 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
872 NetworkInterfaceInfoOSX
*info
= (NetworkInterfaceInfoOSX
*)InterfaceID
;
873 char *ifa_name
= info
? info
->ifa_name
: "unicast";
874 struct sockaddr_storage to
;
876 mStatus result
= mStatus_NoError
;
878 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
879 // anonymous socket created for this purpose, so that we'll receive the response.
880 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
881 if (InterfaceID
&& !mDNSAddrIsDNSMulticast(dst
))
883 const DNSMessage
*const m
= (DNSMessage
*)msg
;
884 if ((m
->h
.flags
.b
[0] & kDNSFlag0_QR_Mask
) == kDNSFlag0_QR_Query
)
885 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst
, mDNSVal16(dstPort
));
888 if (dst
->type
== mDNSAddrType_IPv4
)
890 struct sockaddr_in
*sin_to
= (struct sockaddr_in
*)&to
;
891 sin_to
->sin_len
= sizeof(*sin_to
);
892 sin_to
->sin_family
= AF_INET
;
893 sin_to
->sin_port
= dstPort
.NotAnInteger
;
894 sin_to
->sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
895 s
= m
->p
->permanentsockets
.sktv4
;
896 if (info
) // Specify outgoing interface
898 if (!mDNSAddrIsDNSMulticast(dst
))
900 #ifdef IP_FORCE_OUT_IFP
901 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, ifa_name
, strlen(ifa_name
) + 1);
904 static int displayed
= 0;
908 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
915 err
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &info
->ifa_v4addr
, sizeof(info
->ifa_v4addr
));
916 if (err
< 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info
->ifa_v4addr
, err
, errno
, strerror(errno
));
920 else if (dst
->type
== mDNSAddrType_IPv6
)
922 struct sockaddr_in6
*sin6_to
= (struct sockaddr_in6
*)&to
;
923 sin6_to
->sin6_len
= sizeof(*sin6_to
);
924 sin6_to
->sin6_family
= AF_INET6
;
925 sin6_to
->sin6_port
= dstPort
.NotAnInteger
;
926 sin6_to
->sin6_flowinfo
= 0;
927 sin6_to
->sin6_addr
= *(struct in6_addr
*)&dst
->ip
.v6
;
928 sin6_to
->sin6_scope_id
= info
? info
->scope_id
: 0;
929 s
= m
->p
->permanentsockets
.sktv6
;
930 if (info
&& mDNSAddrIsDNSMulticast(dst
)) // Specify outgoing interface
932 err
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &info
->scope_id
, sizeof(info
->scope_id
));
933 if (err
< 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err
, errno
, strerror(errno
));
938 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
939 return mStatus_BadParamErr
;
942 // Don't send if it would cause dial-on-demand connection initiation.
943 // As an optimization, don't bother consulting reachability API / routing
944 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
945 if (!info
&& !mDNSAddrIsDNSMulticast(dst
) && AddrRequiresPPPConnection((struct sockaddr
*)&to
))
947 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
948 return mStatus_NoError
;
952 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
953 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
);
955 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
956 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
));
958 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
959 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
960 if (s
< 0) return(mStatus_Invalid
);
962 err
= sendto(s
, msg
, (UInt8
*)end
- (UInt8
*)msg
, 0, (struct sockaddr
*)&to
, to
.ss_len
);
965 static int MessageCount
= 0;
966 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
967 if (!mDNSAddressIsAllDNSLinkGroup(dst
))
968 if (errno
== EHOSTDOWN
|| errno
== ENETDOWN
|| errno
== EHOSTUNREACH
|| errno
== ENETUNREACH
) return(mStatus_TransientErr
);
969 // Don't report EHOSTUNREACH in the first three minutes after boot
970 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
971 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
972 if (errno
== EHOSTUNREACH
&& (mDNSu32
)(mDNSPlatformRawTime()) < (mDNSu32
)(mDNSPlatformOneSecond
* 180)) return(mStatus_TransientErr
);
973 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
974 if (errno
== EADDRNOTAVAIL
&& m
->p
->NetworkChanged
) return(mStatus_TransientErr
);
975 if (MessageCount
< 1000)
978 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
979 InterfaceID
, ifa_name
, dst
->type
, dst
, mDNSVal16(dstPort
), s
, err
, errno
, strerror(errno
), (mDNSu32
)(m
->timenow
));
981 result
= mStatus_UnknownErr
;
984 #ifdef IP_FORCE_OUT_IFP
985 if (dst
->type
== mDNSAddrType_IPv4
&& info
&& !mDNSAddrIsDNSMulticast(dst
))
986 setsockopt(s
, IPPROTO_IP
, IP_FORCE_OUT_IFP
, "", 1);
992 mDNSlocal ssize_t
myrecvfrom(const int s
, void *const buffer
, const size_t max
,
993 struct sockaddr
*const from
, size_t *const fromlen
, mDNSAddr
*dstaddr
, char ifname
[IF_NAMESIZE
], mDNSu8
*ttl
)
995 static unsigned int numLogMessages
= 0;
996 struct iovec databuffers
= { (char *)buffer
, max
};
999 struct cmsghdr
*cmPtr
;
1000 char ancillary
[1024];
1002 *ttl
= 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1004 // Set up the message
1005 msg
.msg_name
= (caddr_t
)from
;
1006 msg
.msg_namelen
= *fromlen
;
1007 msg
.msg_iov
= &databuffers
;
1009 msg
.msg_control
= (caddr_t
)&ancillary
;
1010 msg
.msg_controllen
= sizeof(ancillary
);
1014 n
= recvmsg(s
, &msg
, 0);
1017 if (errno
!= EWOULDBLOCK
&& numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s
, n
, errno
);
1020 if (msg
.msg_controllen
< (int)sizeof(struct cmsghdr
))
1022 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1023 s
, n
, msg
.msg_controllen
, sizeof(struct cmsghdr
));
1026 if (msg
.msg_flags
& MSG_CTRUNC
)
1028 if (numLogMessages
++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s
);
1032 *fromlen
= msg
.msg_namelen
;
1034 // Parse each option out of the ancillary data.
1035 for (cmPtr
= CMSG_FIRSTHDR(&msg
); cmPtr
; cmPtr
= CMSG_NXTHDR(&msg
, cmPtr
))
1037 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1038 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVDSTADDR
)
1040 dstaddr
->type
= mDNSAddrType_IPv4
;
1041 dstaddr
->ip
.v4
= *(mDNSv4Addr
*)CMSG_DATA(cmPtr
);
1043 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVIF
)
1045 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmPtr
);
1046 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1048 mDNSPlatformMemCopy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1049 ifname
[sdl
->sdl_nlen
] = 0;
1050 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1053 if (cmPtr
->cmsg_level
== IPPROTO_IP
&& cmPtr
->cmsg_type
== IP_RECVTTL
)
1054 *ttl
= *(u_char
*)CMSG_DATA(cmPtr
);
1055 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_PKTINFO
)
1057 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmPtr
);
1058 dstaddr
->type
= mDNSAddrType_IPv6
;
1059 dstaddr
->ip
.v6
= *(mDNSv6Addr
*)&ip6_info
->ipi6_addr
;
1060 myIfIndexToName(ip6_info
->ipi6_ifindex
, ifname
);
1062 if (cmPtr
->cmsg_level
== IPPROTO_IPV6
&& cmPtr
->cmsg_type
== IPV6_HOPLIMIT
)
1063 *ttl
= *(int*)CMSG_DATA(cmPtr
);
1069 mDNSlocal
void myKQSocketCallBack(int s1
, short filter
, void *context
)
1071 const KQSocketSet
*const ss
= (const KQSocketSet
*)context
;
1072 mDNS
*const m
= ss
->m
;
1075 if (filter
!= EVFILT_READ
)
1076 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter
, EVFILT_READ
);
1078 if (s1
!= ss
->sktv4
&& s1
!= ss
->sktv6
)
1080 LogMsg("myKQSocketCallBack: native socket %d", s1
);
1081 LogMsg("myKQSocketCallBack: sktv4 %d", ss
->sktv4
);
1082 LogMsg("myKQSocketCallBack: sktv6 %d", ss
->sktv6
);
1087 mDNSAddr senderAddr
, destAddr
;
1088 mDNSIPPort senderPort
, destPort
= MulticastDNSPort
;
1089 struct sockaddr_storage from
;
1090 size_t fromlen
= sizeof(from
);
1091 char packetifname
[IF_NAMESIZE
] = "";
1093 err
= myrecvfrom(s1
, &m
->imsg
, sizeof(m
->imsg
), (struct sockaddr
*)&from
, &fromlen
, &destAddr
, packetifname
, &ttl
);
1097 if (from
.ss_family
== AF_INET
)
1099 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&from
;
1100 senderAddr
.type
= mDNSAddrType_IPv4
;
1101 senderAddr
.ip
.v4
.NotAnInteger
= sin
->sin_addr
.s_addr
;
1102 senderPort
.NotAnInteger
= sin
->sin_port
;
1103 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1105 else if (from
.ss_family
== AF_INET6
)
1107 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&from
;
1108 senderAddr
.type
= mDNSAddrType_IPv6
;
1109 senderAddr
.ip
.v6
= *(mDNSv6Addr
*)&sin6
->sin6_addr
;
1110 senderPort
.NotAnInteger
= sin6
->sin6_port
;
1111 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1115 LogMsg("myKQSocketCallBack from is unknown address family %d", from
.ss_family
);
1119 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1120 mDNSInterfaceID InterfaceID
= mDNSNULL
;
1121 NetworkInterfaceInfo
*intf
= m
->HostInterfaces
;
1122 while (intf
&& strcmp(intf
->ifname
, packetifname
)) intf
= intf
->next
;
1123 // When going to sleep we deregister all our interfaces, but if the machine
1124 // takes a few seconds to sleep we may continue to receive multicasts
1125 // during that time, which would confuse mDNSCoreReceive, because as far
1126 // as it's concerned, we should have no active interfaces any more.
1127 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1128 if (intf
) InterfaceID
= intf
->InterfaceID
;
1129 else if (mDNSAddrIsDNSMulticast(&destAddr
)) continue;
1131 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1132 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1134 mDNSCoreReceive(m
, &m
->imsg
, (unsigned char*)&m
->imsg
+ err
, &senderAddr
, senderPort
, &destAddr
, destPort
, InterfaceID
);
1137 if (err
< 0 && (errno
!= EWOULDBLOCK
|| count
== 0))
1139 // Something is busted here.
1140 // kqueue says there is a packet, but myrecvfrom says there is not.
1141 // Try calling select() to get another opinion.
1142 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1143 // All of this is racy, as data may have arrived after the call to select()
1144 static unsigned int numLogMessages
= 0;
1145 int save_errno
= errno
;
1149 socklen_t solen
= sizeof(int);
1151 struct timeval timeout
;
1154 FD_SET(s1
, &readfds
);
1156 timeout
.tv_usec
= 0;
1157 selectresult
= select(s1
+1, &readfds
, NULL
, NULL
, &timeout
);
1158 if (getsockopt(s1
, SOL_SOCKET
, SO_ERROR
, &so_error
, &solen
) == -1)
1159 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno
);
1160 if (getsockopt(s1
, SOL_SOCKET
, SO_NREAD
, &so_nread
, &solen
) == -1)
1161 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno
);
1162 if (ioctl(s1
, FIONREAD
, &fionread
) == -1)
1163 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno
);
1164 if (numLogMessages
++ < 100)
1165 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1166 s1
, err
, save_errno
, strerror(save_errno
), selectresult
, FD_ISSET(s1
, &readfds
) ? "" : "*NO* ", so_error
, so_nread
, fionread
, count
);
1167 if (numLogMessages
> 5)
1168 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1169 "Congratulations, you've reproduced an elusive bug.\r"
1170 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1171 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1172 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1174 sleep(1); // After logging this error, rate limit so we don't flood syslog
1178 // TCP socket support
1180 struct TCPSocket_struct
1182 TCPSocketFlags flags
; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1183 TCPConnectionCallback callback
;
1185 KQueueEntry kqEntry
;
1186 #ifndef NO_SECURITYFRAMEWORK
1187 SSLContextRef tlsContext
;
1188 #endif /* NO_SECURITYFRAMEWORK */
1191 mDNSBool handshakecomplete
;
1195 #ifndef NO_SECURITYFRAMEWORK
1197 mDNSlocal OSStatus
tlsWriteSock(SSLConnectionRef connection
, const void *data
, size_t *dataLength
)
1199 int ret
= send(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1200 if (ret
>= 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1201 if (ret
>= 0) { *dataLength
= ret
; return(noErr
); }
1203 if (errno
== EAGAIN
) return(errSSLWouldBlock
);
1204 if (errno
== ENOENT
) return(errSSLClosedGraceful
);
1205 if (errno
== EPIPE
|| errno
== ECONNRESET
) return(errSSLClosedAbort
);
1206 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno
, strerror(errno
));
1207 return(errSSLClosedAbort
);
1210 mDNSlocal OSStatus
tlsReadSock(SSLConnectionRef connection
, void *data
, size_t *dataLength
)
1212 int ret
= recv(((TCPSocket
*)connection
)->fd
, data
, *dataLength
, 0);
1213 if (ret
> 0 && (size_t)ret
< *dataLength
) { *dataLength
= ret
; return(errSSLWouldBlock
); }
1214 if (ret
> 0) { *dataLength
= ret
; return(noErr
); }
1216 if (ret
== 0 || errno
== ENOENT
) return(errSSLClosedGraceful
);
1217 if ( errno
== EAGAIN
) return(errSSLWouldBlock
);
1218 if ( errno
== ECONNRESET
) return(errSSLClosedAbort
);
1219 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno
, strerror(errno
));
1220 return(errSSLClosedAbort
);
1223 mDNSlocal OSStatus
tlsSetupSock(TCPSocket
*sock
, mDNSBool server
)
1225 mStatus err
= SSLNewContext(server
, &sock
->tlsContext
);
1226 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err
); return(err
); }
1228 err
= SSLSetIOFuncs(sock
->tlsContext
, tlsReadSock
, tlsWriteSock
);
1229 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err
); return(err
); }
1231 err
= SSLSetConnection(sock
->tlsContext
, (SSLConnectionRef
) sock
);
1232 if (err
) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err
); return(err
); }
1237 mDNSlocal mDNSBool
IsTunnelModeDomain(const domainname
*d
)
1239 static const domainname
*mmc
= (const domainname
*) "\x7" "members" "\x3" "mac" "\x3" "com";
1240 const domainname
*d1
= mDNSNULL
; // TLD
1241 const domainname
*d2
= mDNSNULL
; // SLD
1242 const domainname
*d3
= mDNSNULL
;
1243 while (d
->c
[0]) { d3
= d2
; d2
= d1
; d1
= d
; d
= (const domainname
*)(d
->c
+ 1 + d
->c
[0]); }
1244 return(d3
&& SameDomainName(d3
, mmc
));
1247 #endif /* NO_SECURITYFRAMEWORK */
1249 mDNSlocal
void tcpKQSocketCallback(__unused
int fd
, short filter
, void *context
)
1251 TCPSocket
*sock
= context
;
1252 mStatus err
= mStatus_NoError
;
1254 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1255 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1256 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1257 if (filter
== EVFILT_WRITE
) KQueueSet(sock
->fd
, EV_DELETE
, EVFILT_WRITE
, &sock
->kqEntry
);
1259 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1261 #ifndef NO_SECURITYFRAMEWORK
1262 if (!sock
->setup
) { sock
->setup
= mDNStrue
; tlsSetupSock(sock
, mDNSfalse
); }
1263 if (!sock
->handshakecomplete
)
1265 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1266 err
= SSLHandshake(sock
->tlsContext
);
1267 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1268 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1269 else if (err
== errSSLWouldBlock
) return;
1270 else { LogMsg("KQ SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1273 err
= mStatus_UnsupportedErr
;
1274 #endif /* NO_SECURITYFRAMEWORK */
1277 mDNSBool connect
= !sock
->connected
;
1278 sock
->connected
= mDNStrue
;
1279 sock
->callback(sock
, sock
->context
, connect
, err
);
1280 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1283 mDNSexport
int KQueueSet(int fd
, u_short flags
, short filter
, const KQueueEntry
*const entryRef
)
1285 struct kevent new_event
;
1286 EV_SET(&new_event
, fd
, filter
, flags
, 0, 0, (void*)entryRef
);
1287 return (kevent(KQueueFD
, &new_event
, 1, NULL
, 0, NULL
) < 0) ? errno
: 0;
1290 mDNSexport
void KQueueLock(mDNS
*const m
)
1292 pthread_mutex_lock(&m
->p
->BigMutex
);
1293 m
->p
->BigMutexStartTime
= mDNSPlatformRawTime();
1296 mDNSexport
void KQueueUnlock(mDNS
*const m
, const char const *task
)
1298 mDNSs32 end
= mDNSPlatformRawTime();
1300 if (end
- m
->p
->BigMutexStartTime
>= WatchDogReportingThreshold
)
1301 LogOperation("WARNING: %s took %dms to complete", task
, end
- m
->p
->BigMutexStartTime
);
1303 pthread_mutex_unlock(&m
->p
->BigMutex
);
1306 if (send(m
->p
->WakeKQueueLoopFD
, &wake
, sizeof(wake
), 0) == -1)
1307 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno
, strerror(errno
));
1310 mDNSexport TCPSocket
*mDNSPlatformTCPSocket(mDNS
*const m
, TCPSocketFlags flags
, mDNSIPPort
*port
)
1314 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket
));
1315 if (!sock
) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL
); }
1317 mDNSPlatformMemZero(sock
, sizeof(TCPSocket
));
1318 sock
->callback
= mDNSNULL
;
1319 sock
->fd
= socket(AF_INET
, SOCK_STREAM
, 0);
1320 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1321 sock
->kqEntry
.KQcontext
= sock
;
1322 sock
->kqEntry
.KQtask
= "mDNSPlatformTCPSocket";
1323 sock
->flags
= flags
;
1324 sock
->context
= mDNSNULL
;
1325 sock
->setup
= mDNSfalse
;
1326 sock
->handshakecomplete
= mDNSfalse
;
1327 sock
->connected
= mDNSfalse
;
1331 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock
->fd
, errno
, strerror(errno
));
1332 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1337 struct sockaddr_in addr
;
1338 memset(&addr
, 0, sizeof(addr
));
1339 addr
.sin_family
= AF_INET
;
1340 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1341 addr
.sin_port
= port
->NotAnInteger
;
1342 if (bind(sock
->fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
1343 { LogMsg("ERROR: bind %s", strerror(errno
)); goto error
; }
1345 // Receive interface identifiers
1346 const int on
= 1; // "on" for setsockopt
1347 if (setsockopt(sock
->fd
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
)) < 0)
1348 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno
)); goto error
; }
1350 memset(&addr
, 0, sizeof(addr
));
1351 socklen_t len
= sizeof(addr
);
1352 if (getsockname(sock
->fd
, (struct sockaddr
*) &addr
, &len
) < 0)
1353 { LogMsg("getsockname - %s", strerror(errno
)); goto error
; }
1355 port
->NotAnInteger
= addr
.sin_port
;
1360 freeL("TCPSocket/mDNSPlatformTCPSocket", sock
);
1364 mDNSexport mStatus
mDNSPlatformTCPConnect(TCPSocket
*sock
, const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
1365 TCPConnectionCallback callback
, void *context
)
1367 struct sockaddr_in saddr
;
1368 mStatus err
= mStatus_NoError
;
1370 sock
->callback
= callback
;
1371 sock
->context
= context
;
1372 sock
->setup
= mDNSfalse
;
1373 sock
->handshakecomplete
= mDNSfalse
;
1374 sock
->connected
= mDNSfalse
;
1376 (void) InterfaceID
; //!!!KRS use this if non-zero!!!
1378 if (dst
->type
!= mDNSAddrType_IPv4
)
1380 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1381 return mStatus_UnknownErr
;
1384 mDNSPlatformMemZero(&saddr
, sizeof(saddr
));
1385 saddr
.sin_family
= AF_INET
;
1386 saddr
.sin_port
= dstport
.NotAnInteger
;
1387 saddr
.sin_len
= sizeof(saddr
);
1388 saddr
.sin_addr
.s_addr
= dst
->ip
.v4
.NotAnInteger
;
1390 // Don't send if it would cause dial-on-demand connection initiation.
1391 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
))
1393 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1394 return mStatus_UnknownErr
;
1397 sock
->kqEntry
.KQcallback
= tcpKQSocketCallback
;
1398 sock
->kqEntry
.KQcontext
= sock
;
1399 sock
->kqEntry
.KQtask
= "Outgoing TCP";
1401 // Watch for connect complete (write is ready)
1402 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1403 if (KQueueSet(sock
->fd
, EV_ADD
/* | EV_ONESHOT */, EVFILT_WRITE
, &sock
->kqEntry
))
1405 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1410 // Watch for incoming data
1411 if (KQueueSet(sock
->fd
, EV_ADD
, EVFILT_READ
, &sock
->kqEntry
))
1413 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1414 close(sock
->fd
); // Closing the descriptor removes all filters from the kqueue
1418 if (fcntl(sock
->fd
, F_SETFL
, fcntl(sock
->fd
, F_GETFL
, 0) | O_NONBLOCK
) < 0) // set non-blocking
1420 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno
));
1421 return mStatus_UnknownErr
;
1424 // initiate connection wth peer
1425 if (connect(sock
->fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0)
1427 if (errno
== EINPROGRESS
) return mStatus_ConnPending
;
1428 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock
->fd
, errno
, strerror(errno
));
1430 return mStatus_ConnFailed
;
1433 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1434 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1438 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1439 mDNSexport TCPSocket
*mDNSPlatformTCPAccept(TCPSocketFlags flags
, int fd
)
1441 mStatus err
= mStatus_NoError
;
1443 TCPSocket
*sock
= mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket
));
1444 if (!sock
) return(mDNSNULL
);
1446 memset(sock
, 0, sizeof(*sock
));
1448 sock
->flags
= flags
;
1450 if (flags
& kTCPSocketFlags_UseTLS
)
1452 #ifndef NO_SECURITYFRAMEWORK
1453 if (!ServerCerts
) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err
= mStatus_UnknownErr
; goto exit
; }
1455 err
= tlsSetupSock(sock
, mDNStrue
);
1456 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err
); goto exit
; }
1458 err
= SSLSetCertificate(sock
->tlsContext
, ServerCerts
);
1459 if (err
) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err
); goto exit
; }
1461 err
= mStatus_UnsupportedErr
;
1462 #endif /* NO_SECURITYFRAMEWORK */
1464 #ifndef NO_SECURITYFRAMEWORK
1468 if (err
) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock
); return(mDNSNULL
); }
1472 mDNSexport
void mDNSPlatformTCPCloseConnection(TCPSocket
*sock
)
1476 #ifndef NO_SECURITYFRAMEWORK
1477 if (sock
->tlsContext
)
1479 SSLClose(sock
->tlsContext
);
1480 SSLDisposeContext(sock
->tlsContext
);
1481 sock
->tlsContext
= NULL
;
1483 #endif /* NO_SECURITYFRAMEWORK */
1486 shutdown(sock
->fd
, 2);
1491 freeL("mDNSPlatformTCPCloseConnection", sock
);
1495 mDNSexport
long mDNSPlatformReadTCP(TCPSocket
*sock
, void *buf
, unsigned long buflen
, mDNSBool
*closed
)
1498 *closed
= mDNSfalse
;
1500 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1502 #ifndef NO_SECURITYFRAMEWORK
1503 if (!sock
->handshakecomplete
)
1505 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1506 mStatus err
= SSLHandshake(sock
->tlsContext
);
1507 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1508 if (!err
) sock
->handshakecomplete
= mDNStrue
;
1509 else if (err
== errSSLWouldBlock
) return(0);
1510 else { LogMsg("Read SSLHandshake failed: %d", err
); SSLDisposeContext(sock
->tlsContext
); sock
->tlsContext
= NULL
; }
1513 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1514 mStatus err
= SSLRead(sock
->tlsContext
, buf
, buflen
, (size_t*)&nread
);
1515 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1516 if (err
== errSSLClosedGraceful
) { nread
= 0; *closed
= mDNStrue
; }
1517 else if (err
&& err
!= errSSLWouldBlock
)
1518 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err
); nread
= -1; *closed
= mDNStrue
; }
1522 #endif /* NO_SECURITYFRAMEWORK */
1526 static int CLOSEDcount
= 0;
1527 static int EAGAINcount
= 0;
1528 nread
= recv(sock
->fd
, buf
, buflen
, 0);
1530 if (nread
> 0) { CLOSEDcount
= 0; EAGAINcount
= 0; } // On success, clear our error counters
1531 else if (nread
== 0)
1534 if ((++CLOSEDcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock
->fd
, CLOSEDcount
); sleep(1); }
1536 // else nread is negative -- see what kind of error we got
1537 else if (errno
== ECONNRESET
) { nread
= 0; *closed
= mDNStrue
; }
1538 else if (errno
!= EAGAIN
) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno
, strerror(errno
)); nread
= -1; }
1539 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1542 if ((++EAGAINcount
% 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock
->fd
, EAGAINcount
); sleep(1); }
1549 mDNSexport
long mDNSPlatformWriteTCP(TCPSocket
*sock
, const char *msg
, unsigned long len
)
1553 if (sock
->flags
& kTCPSocketFlags_UseTLS
)
1555 #ifndef NO_SECURITYFRAMEWORK
1557 mStatus err
= SSLWrite(sock
->tlsContext
, msg
, len
, &processed
);
1559 if (!err
) nsent
= (int) processed
;
1560 else if (err
== errSSLWouldBlock
) nsent
= 0;
1561 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err
); nsent
= -1; }
1564 #endif /* NO_SECURITYFRAMEWORK */
1568 nsent
= send(sock
->fd
, msg
, len
, 0);
1571 if (errno
== EAGAIN
) nsent
= 0;
1572 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno
)); nsent
= -1; }
1579 mDNSexport
int mDNSPlatformTCPGetFD(TCPSocket
*sock
)
1584 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1585 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1586 mDNSlocal mStatus
SetupSocket(KQSocketSet
*cp
, const mDNSIPPort port
, u_short sa_family
)
1588 const int ip_tosbits
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
;
1589 int *s
= (sa_family
== AF_INET
) ? &cp
->sktv4
: &cp
->sktv6
;
1590 KQueueEntry
*k
= (sa_family
== AF_INET
) ? &cp
->kqsv4
: &cp
->kqsv6
;
1592 const int twofivefive
= 255;
1593 mStatus err
= mStatus_NoError
;
1594 char *errstr
= mDNSNULL
;
1596 int skt
= socket(sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1597 if (skt
< 3) { if (errno
!= EAFNOSUPPORT
) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt
, errno
, strerror(errno
)); return(skt
); }
1599 // ... with a shared UDP port, if it's for multicast receiving
1600 if (mDNSSameIPPort(port
, MulticastDNSPort
)) err
= setsockopt(skt
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof(on
));
1601 if (err
< 0) { errstr
= "setsockopt - SO_REUSEPORT"; goto fail
; }
1603 if (sa_family
== AF_INET
)
1605 // We want to receive destination addresses
1606 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVDSTADDR
, &on
, sizeof(on
));
1607 if (err
< 0) { errstr
= "setsockopt - IP_RECVDSTADDR"; goto fail
; }
1609 // We want to receive interface identifiers
1610 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVIF
, &on
, sizeof(on
));
1611 if (err
< 0) { errstr
= "setsockopt - IP_RECVIF"; goto fail
; }
1613 // We want to receive packet TTL value so we can check it
1614 err
= setsockopt(skt
, IPPROTO_IP
, IP_RECVTTL
, &on
, sizeof(on
));
1615 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1617 // Send unicast packets with TTL 255
1618 err
= setsockopt(skt
, IPPROTO_IP
, IP_TTL
, &twofivefive
, sizeof(twofivefive
));
1619 if (err
< 0) { errstr
= "setsockopt - IP_TTL"; goto fail
; }
1621 // And multicast packets with TTL 255 too
1622 err
= setsockopt(skt
, IPPROTO_IP
, IP_MULTICAST_TTL
, &twofivefive
, sizeof(twofivefive
));
1623 if (err
< 0) { errstr
= "setsockopt - IP_MULTICAST_TTL"; goto fail
; }
1625 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1626 err
= setsockopt(skt
, IPPROTO_IP
, IP_TOS
, &ip_tosbits
, sizeof(ip_tosbits
));
1627 if (err
< 0) { errstr
= "setsockopt - IP_TOS"; goto fail
; }
1629 // And start listening for packets
1630 struct sockaddr_in listening_sockaddr
;
1631 listening_sockaddr
.sin_family
= AF_INET
;
1632 listening_sockaddr
.sin_port
= port
.NotAnInteger
;
1633 listening_sockaddr
.sin_addr
.s_addr
= 0; // Want to receive multicasts AND unicasts on this socket
1634 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr
, sizeof(listening_sockaddr
));
1635 if (err
) { errstr
= "bind"; goto fail
; }
1637 else if (sa_family
== AF_INET6
)
1639 // We want to receive destination addresses and receive interface identifiers
1640 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_PKTINFO
, &on
, sizeof(on
));
1641 if (err
< 0) { errstr
= "setsockopt - IPV6_PKTINFO"; goto fail
; }
1643 // We want to receive packet hop count value so we can check it
1644 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_HOPLIMIT
, &on
, sizeof(on
));
1645 if (err
< 0) { errstr
= "setsockopt - IPV6_HOPLIMIT"; goto fail
; }
1647 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1648 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1649 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
1650 if (err
< 0) { errstr
= "setsockopt - IPV6_V6ONLY"; goto fail
; }
1652 // Send unicast packets with TTL 255
1653 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1654 if (err
< 0) { errstr
= "setsockopt - IPV6_UNICAST_HOPS"; goto fail
; }
1656 // And multicast packets with TTL 255 too
1657 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &twofivefive
, sizeof(twofivefive
));
1658 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_HOPS"; goto fail
; }
1660 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1662 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1663 int tclass
= IPTOS_LOWDELAY
| IPTOS_THROUGHPUT
; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1664 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_TCLASS
, &tclass
, sizeof(tclass
));
1665 if (err
< 0) { errstr
= "setsockopt - IPV6_TCLASS"; goto fail
; }
1668 // Want to receive our own packets
1669 err
= setsockopt(skt
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &on
, sizeof(on
));
1670 if (err
< 0) { errstr
= "setsockopt - IPV6_MULTICAST_LOOP"; goto fail
; }
1672 // And start listening for packets
1673 struct sockaddr_in6 listening_sockaddr6
;
1674 mDNSPlatformMemZero(&listening_sockaddr6
, sizeof(listening_sockaddr6
));
1675 listening_sockaddr6
.sin6_len
= sizeof(listening_sockaddr6
);
1676 listening_sockaddr6
.sin6_family
= AF_INET6
;
1677 listening_sockaddr6
.sin6_port
= port
.NotAnInteger
;
1678 listening_sockaddr6
.sin6_flowinfo
= 0;
1679 listening_sockaddr6
.sin6_addr
= in6addr_any
; // Want to receive multicasts AND unicasts on this socket
1680 listening_sockaddr6
.sin6_scope_id
= 0;
1681 err
= bind(skt
, (struct sockaddr
*) &listening_sockaddr6
, sizeof(listening_sockaddr6
));
1682 if (err
) { errstr
= "bind"; goto fail
; }
1685 fcntl(skt
, F_SETFL
, fcntl(skt
, F_GETFL
, 0) | O_NONBLOCK
); // set non-blocking
1686 fcntl(skt
, F_SETFD
, 1); // set close-on-exec
1688 k
->KQcallback
= myKQSocketCallBack
;
1690 k
->KQtask
= "UDP packet reception";
1691 KQueueSet(*s
, EV_ADD
, EVFILT_READ
, k
);
1696 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1697 if (strcmp(errstr
, "bind") || mDNSSameIPPort(port
, MulticastDNSPort
) || mDNSIPPortIsZero(port
))
1698 LogMsg("%s error %ld errno %d (%s)", errstr
, err
, errno
, strerror(errno
));
1700 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1701 if (!strcmp(errstr
, "bind") && mDNSSameIPPort(port
, MulticastDNSPort
) && errno
== EADDRINUSE
)
1702 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1703 "Congratulations, you've reproduced an elusive bug.\r"
1704 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1705 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1706 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1712 struct UDPSocket_struct
1717 mDNSexport UDPSocket
*mDNSPlatformUDPSocket(mDNS
*const m
, const mDNSIPPort port
)
1720 UDPSocket
*p
= mallocL("UDPSocket", sizeof(UDPSocket
));
1721 if (!p
) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL
); }
1722 memset(p
, 0, sizeof(UDPSocket
));
1726 err
= SetupSocket(&p
->ss
, port
, AF_INET
);
1729 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1730 // of failing to bind to this port when Internet Sharing has already bound to it
1731 if (mDNSSameIPPort(port
, NATPMPPort
))
1732 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1733 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port
));
1734 freeL("UDPSocket", p
);
1740 mDNSlocal
void CloseSocketSet(KQSocketSet
*ss
)
1742 if (ss
->sktv4
!= -1)
1747 if (ss
->sktv6
!= -1)
1754 mDNSexport
void mDNSPlatformUDPClose(UDPSocket
*sock
)
1756 CloseSocketSet(&sock
->ss
);
1757 freeL("UDPSocket", sock
);
1760 #if COMPILER_LIKES_PRAGMA_MARK
1762 #pragma mark - Key Management
1765 #ifndef NO_SECURITYFRAMEWORK
1766 mDNSlocal CFArrayRef
GetCertChain(SecIdentityRef identity
)
1768 CFMutableArrayRef certChain
= NULL
;
1769 if (!identity
) { LogMsg("getCertChain: identity is NULL"); return(NULL
); }
1770 SecCertificateRef cert
;
1771 OSStatus err
= SecIdentityCopyCertificate(identity
, &cert
);
1772 if (err
|| !cert
) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err
);
1775 SecPolicySearchRef searchRef
;
1776 err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
1777 if (err
|| !searchRef
) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err
);
1780 SecPolicyRef policy
;
1781 err
= SecPolicySearchCopyNext(searchRef
, &policy
);
1782 if (err
|| !policy
) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err
);
1785 CFArrayRef wrappedCert
= CFArrayCreate(NULL
, (const void**) &cert
, 1, &kCFTypeArrayCallBacks
);
1786 if (!wrappedCert
) LogMsg("getCertChain: wrappedCert is NULL");
1790 err
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
1791 if (err
|| !trust
) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err
);
1794 err
= SecTrustEvaluate(trust
, NULL
);
1795 if (err
) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err
);
1798 CFArrayRef rawCertChain
;
1799 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1800 err
= SecTrustGetResult(trust
, NULL
, &rawCertChain
, &statusChain
);
1801 if (err
|| !rawCertChain
|| !statusChain
) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err
);
1804 certChain
= CFArrayCreateMutableCopy(NULL
, 0, rawCertChain
);
1805 if (!certChain
) LogMsg("getCertChain: certChain is NULL");
1808 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1809 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1810 CFArraySetValueAtIndex(certChain
, 0, identity
);
1811 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1812 if (CFArrayGetCount(certChain
) > 1) CFArrayRemoveValueAtIndex(certChain
, CFArrayGetCount(certChain
) - 1);
1814 CFRelease(rawCertChain
);
1815 // Do not free statusChain:
1816 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1817 // certChain: Call the CFRelease function to release this object when you are finished with it.
1818 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1823 CFRelease(wrappedCert
);
1827 CFRelease(searchRef
);
1833 #endif /* NO_SECURITYFRAMEWORK */
1835 mDNSexport mStatus
mDNSPlatformTLSSetupCerts(void)
1837 #ifdef NO_SECURITYFRAMEWORK
1838 return mStatus_UnsupportedErr
;
1840 SecIdentityRef identity
= nil
;
1841 SecIdentitySearchRef srchRef
= nil
;
1844 // search for "any" identity matching specified key use
1845 // In this app, we expect there to be exactly one
1846 err
= SecIdentitySearchCreate(NULL
, CSSM_KEYUSE_DECRYPT
, &srchRef
);
1847 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err
); return err
; }
1849 err
= SecIdentitySearchCopyNext(srchRef
, &identity
);
1850 if (err
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err
); return err
; }
1852 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
1853 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr
; }
1855 // Found one. Call getCertChain to create the correct certificate chain.
1856 ServerCerts
= GetCertChain(identity
);
1857 if (ServerCerts
== nil
) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr
; }
1859 return mStatus_NoError
;
1860 #endif /* NO_SECURITYFRAMEWORK */
1863 mDNSexport
void mDNSPlatformTLSTearDownCerts(void)
1865 #ifndef NO_SECURITYFRAMEWORK
1866 if (ServerCerts
) { CFRelease(ServerCerts
); ServerCerts
= NULL
; }
1867 #endif /* NO_SECURITYFRAMEWORK */
1870 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1871 mDNSlocal
void GetUserSpecifiedFriendlyComputerName(domainlabel
*const namelabel
)
1873 CFStringEncoding encoding
= kCFStringEncodingUTF8
;
1874 CFStringRef cfs
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
1877 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1882 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1883 mDNSlocal
void GetUserSpecifiedLocalHostName(domainlabel
*const namelabel
)
1885 CFStringRef cfs
= SCDynamicStoreCopyLocalHostName(NULL
);
1888 CFStringGetPascalString(cfs
, namelabel
->c
, sizeof(*namelabel
), kCFStringEncodingUTF8
);
1893 mDNSlocal mDNSBool
DDNSSettingEnabled(CFDictionaryRef dict
)
1896 CFNumberRef state
= CFDictionaryGetValue(dict
, CFSTR("Enabled"));
1897 if (!state
) return mDNSfalse
;
1898 if (!CFNumberGetValue(state
, kCFNumberSInt32Type
, &val
)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse
; }
1899 return val
? mDNStrue
: mDNSfalse
;
1902 mDNSlocal mStatus
SetupAddr(mDNSAddr
*ip
, const struct sockaddr
*const sa
)
1904 if (!sa
) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid
); }
1906 if (sa
->sa_family
== AF_INET
)
1908 struct sockaddr_in
*ifa_addr
= (struct sockaddr_in
*)sa
;
1909 ip
->type
= mDNSAddrType_IPv4
;
1910 ip
->ip
.v4
.NotAnInteger
= ifa_addr
->sin_addr
.s_addr
;
1911 return(mStatus_NoError
);
1914 if (sa
->sa_family
== AF_INET6
)
1916 struct sockaddr_in6
*ifa_addr
= (struct sockaddr_in6
*)sa
;
1917 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
1918 // value into the second word of the IPv6 link-local address, so they can just
1919 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
1920 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
1921 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
1922 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr
->sin6_addr
)) ifa_addr
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1923 ip
->type
= mDNSAddrType_IPv6
;
1924 ip
->ip
.v6
= *(mDNSv6Addr
*)&ifa_addr
->sin6_addr
;
1925 return(mStatus_NoError
);
1928 LogMsg("SetupAddr invalid sa_family %d", sa
->sa_family
);
1929 return(mStatus_Invalid
);
1932 mDNSlocal mDNSEthAddr
GetBSSID(char *ifa_name
)
1934 mDNSEthAddr eth
= zeroEthAddr
;
1935 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:GetBSSID"), NULL
, NULL
);
1938 CFStringRef entityname
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name
);
1941 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, entityname
);
1944 CFRange range
= { 0, 6 }; // Offset, length
1945 CFDataRef data
= CFDictionaryGetValue(dict
, CFSTR("BSSID"));
1946 if (data
&& CFDataGetLength(data
) == 6) CFDataGetBytes(data
, range
, eth
.b
);
1949 CFRelease(entityname
);
1956 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
1957 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
1958 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
1959 // (e.g. sa_family not AF_INET or AF_INET6)
1960 mDNSlocal NetworkInterfaceInfoOSX
*AddInterfaceToList(mDNS
*const m
, struct ifaddrs
*ifa
, mDNSs32 utc
)
1962 mDNSu32 scope_id
= if_nametoindex(ifa
->ifa_name
);
1963 mDNSEthAddr bssid
= GetBSSID(ifa
->ifa_name
);
1966 if (SetupAddr(&ip
, ifa
->ifa_addr
) != mStatus_NoError
) return(NULL
);
1967 if (SetupAddr(&mask
, ifa
->ifa_netmask
) != mStatus_NoError
) return(NULL
);
1969 NetworkInterfaceInfoOSX
**p
;
1970 for (p
= &m
->p
->InterfaceList
; *p
; p
= &(*p
)->next
)
1971 if (scope_id
== (*p
)->scope_id
&& mDNSSameAddress(&ip
, &(*p
)->ifinfo
.ip
) && mDNSSameEthAddress(&bssid
, &(*p
)->BSSID
))
1973 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, *p
);
1974 (*p
)->Exists
= mDNStrue
;
1975 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
1976 if ((*p
)->LastSeen
!= utc
) (*p
)->AppearanceTime
= utc
;
1980 NetworkInterfaceInfoOSX
*i
= (NetworkInterfaceInfoOSX
*)mallocL("NetworkInterfaceInfoOSX", sizeof(*i
));
1981 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id
, &bssid
, &ip
, i
);
1982 if (!i
) return(mDNSNULL
);
1983 mDNSPlatformMemZero(i
, sizeof(NetworkInterfaceInfoOSX
));
1984 i
->ifa_name
= (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa
->ifa_name
) + 1);
1985 if (!i
->ifa_name
) { freeL("NetworkInterfaceInfoOSX", i
); return(mDNSNULL
); }
1986 strcpy(i
->ifa_name
, ifa
->ifa_name
); // This is safe because we know we allocated i->ifa_name with sufficient space
1988 i
->ifinfo
.InterfaceID
= mDNSNULL
;
1990 i
->ifinfo
.mask
= mask
;
1991 strlcpy(i
->ifinfo
.ifname
, ifa
->ifa_name
, sizeof(i
->ifinfo
.ifname
));
1992 i
->ifinfo
.ifname
[sizeof(i
->ifinfo
.ifname
)-1] = 0;
1993 i
->ifinfo
.Advertise
= m
->AdvertiseLocalAddresses
;
1994 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList
1997 i
->Exists
= mDNStrue
;
1998 i
->AppearanceTime
= utc
; // Brand new interface; AppearanceTime is now
2000 i
->Flashing
= mDNSfalse
;
2001 i
->Occulting
= mDNSfalse
;
2002 i
->scope_id
= scope_id
;
2004 i
->sa_family
= ifa
->ifa_addr
->sa_family
;
2005 i
->ifa_flags
= ifa
->ifa_flags
;
2011 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2012 mDNSlocal NetworkInterfaceInfoOSX
*FindRoutableIPv4(mDNS
*const m
, mDNSu32 scope_id
)
2014 NetworkInterfaceInfoOSX
*i
;
2015 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2016 if (i
->Exists
&& i
->scope_id
== scope_id
&& i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
)
2017 if (!mDNSv4AddressIsLinkLocal(&i
->ifinfo
.ip
.ip
.v4
))
2023 #if APPLE_OSX_mDNSResponder
2025 #if COMPILER_LIKES_PRAGMA_MARK
2027 #pragma mark - AutoTunnel
2030 #define kRacoonPort 4500
2032 static mDNSBool AnonymousRacoonConfig
= mDNSfalse
;
2034 // MUST be called with lock held
2035 mDNSlocal mDNSBool
TunnelServers(mDNS
*const m
)
2037 ServiceRecordSet
*p
;
2038 for (p
= m
->ServiceRegistrations
; p
; p
= p
->uDNS_next
)
2040 DomainAuthInfo
*AuthInfo
= GetAuthInfoForName_internal(m
, p
->RR_SRV
.resrec
.name
);
2041 if (AuthInfo
&& AuthInfo
->AutoTunnel
&& !AuthInfo
->deltime
) return(mDNStrue
);
2046 // MUST be called with lock held
2047 mDNSlocal mDNSBool
TunnelClients(mDNS
*const m
)
2050 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
2051 if (p
->q
.ThisQInterval
< 0)
2056 mDNSlocal
void RegisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2058 if (!info
->AutoTunnelNAT
.Result
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
) && AutoTunnelUnregistered(info
))
2060 LogOperation("RegisterAutoTunnelRecords %##s", info
->AutoTunnelService
.namestorage
.c
);
2062 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.port
= info
->AutoTunnelNAT
.ExternalPort
;
2063 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2064 err
= mDNS_Register(m
, &info
->AutoTunnelService
);
2065 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2067 info
->AutoTunnelTarget
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2069 mDNS_AddDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
, mDNSNULL
, info
);
2072 if (info
->AutoTunnelHostRecord
.namestorage
.c
[0] == 0)
2074 AppendDomainLabel(&info
->AutoTunnelHostRecord
.namestorage
, &m
->hostlabel
);
2075 AppendDomainName (&info
->AutoTunnelHostRecord
.namestorage
, &info
->domain
);
2077 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2078 err
= mDNS_Register(m
, &info
->AutoTunnelHostRecord
);
2079 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2081 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeKnownUnique
;
2082 err
= mDNS_Register(m
, &info
->AutoTunnelDeviceInfo
);
2083 if (err
) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2085 LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2086 info
->AutoTunnelTarget
.namestorage
.c
, &m
->AdvertisedV4
.ip
.v4
, mDNSVal16(info
->AutoTunnelNAT
.IntPort
),
2087 info
->AutoTunnelHostRecord
.namestorage
.c
, &m
->AutoTunnelHostAddr
);
2091 mDNSlocal
void DeregisterAutoTunnelRecords(mDNS
*m
, DomainAuthInfo
*info
)
2093 LogOperation("DeregisterAutoTunnelRecords %##s", info
->AutoTunnelService
.namestorage
.c
);
2094 if (info
->AutoTunnelService
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2096 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelService
);
2099 info
->AutoTunnelService
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2100 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err
, info
->AutoTunnelService
.namestorage
.c
);
2104 mDNS_RemoveDynDNSHostName(m
, &info
->AutoTunnelTarget
.namestorage
);
2108 if (info
->AutoTunnelHostRecord
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2110 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelHostRecord
);
2113 info
->AutoTunnelHostRecord
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2114 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err
, info
->AutoTunnelHostRecord
.namestorage
.c
);
2116 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
2119 if (info
->AutoTunnelDeviceInfo
.resrec
.RecordType
> kDNSRecordTypeDeregistering
)
2121 mStatus err
= mDNS_Deregister(m
, &info
->AutoTunnelDeviceInfo
);
2124 info
->AutoTunnelDeviceInfo
.resrec
.RecordType
= kDNSRecordTypeUnregistered
;
2125 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err
, info
->AutoTunnelDeviceInfo
.namestorage
.c
);
2130 mDNSlocal
void AutoTunnelRecordCallback(mDNS
*const m
, AuthRecord
*const rr
, mStatus result
)
2132 DomainAuthInfo
*info
= (DomainAuthInfo
*)rr
->RecordContext
;
2133 if (result
== mStatus_MemFree
)
2135 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m
, rr
));
2136 RegisterAutoTunnelRecords(m
,info
);
2140 mDNSlocal
void AutoTunnelNATCallback(mDNS
*m
, NATTraversalInfo
*n
)
2142 DomainAuthInfo
*info
= (DomainAuthInfo
*)n
->clientContext
;
2143 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %##s", n
->Result
, &n
->ExternalAddress
, mDNSVal16(n
->IntPort
), mDNSVal16(n
->ExternalPort
), info
->AutoTunnelService
.namestorage
.c
);
2145 m
->NextSRVUpdate
= m
->timenow
;
2146 DeregisterAutoTunnelRecords(m
,info
);
2147 RegisterAutoTunnelRecords(m
,info
);
2149 // Determine whether we need racoon to accept incoming connections
2150 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2151 if (info
->AutoTunnel
&& !info
->deltime
&& !mDNSIPPortIsZero(info
->AutoTunnelNAT
.ExternalPort
))
2153 mDNSBool needRacoonConfig
= info
!= mDNSNULL
;
2154 if (needRacoonConfig
!= AnonymousRacoonConfig
)
2156 AnonymousRacoonConfig
= needRacoonConfig
;
2157 // Create or revert configuration file, and start (or SIGHUP) Racoon
2158 (void)mDNSConfigureServer(AnonymousRacoonConfig
? kmDNSUp
: kmDNSDown
, info
? info
->b64keydata
: "");
2162 // Before SetupLocalAutoTunnelInterface_internal is called,
2163 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2164 // Must be called with the lock held
2165 mDNSexport
void SetupLocalAutoTunnelInterface_internal(mDNS
*const m
)
2167 LogOperation("SetupLocalAutoTunnelInterface");
2169 // 1. Configure the local IPv6 address
2170 if (!m
->AutoTunnelHostAddrActive
)
2172 m
->AutoTunnelHostAddrActive
= mDNStrue
;
2173 LogMsg("Setting up AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
2174 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp
, m
->AutoTunnelHostAddr
.b
);
2177 // 2. If we have at least one server (pending) listening, publish our records
2178 if (TunnelServers(m
))
2180 DomainAuthInfo
*info
;
2181 for (info
= m
->AuthInfoList
; info
; info
= info
->next
)
2183 if (info
->AutoTunnel
&& !info
->deltime
&& !info
->AutoTunnelNAT
.clientContext
)
2185 // 1. Set up our address record for the internal tunnel address
2186 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2187 mDNS_SetupResourceRecord(&info
->AutoTunnelHostRecord
, mDNSNULL
, mDNSInterface_Any
, kDNSType_AAAA
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2188 info
->AutoTunnelHostRecord
.namestorage
.c
[0] = 0;
2189 info
->AutoTunnelHostRecord
.resrec
.rdata
->u
.ipv6
= m
->AutoTunnelHostAddr
;
2191 // 2. Set up device info record
2192 mDNSu8 len
= m
->HIHardware
.c
[0] < 255 - 6 ? m
->HIHardware
.c
[0] : 255 - 6;
2193 mDNS_SetupResourceRecord(&info
->AutoTunnelDeviceInfo
, mDNSNULL
, mDNSInterface_Any
, kDNSType_TXT
, kStandardTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2194 ConstructServiceName(&info
->AutoTunnelDeviceInfo
.namestorage
, &m
->nicelabel
, &DeviceInfoName
, &info
->domain
);
2195 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 1, "model=", 6);
2196 mDNSPlatformMemCopy(info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
+ 7, m
->HIHardware
.c
+ 1, len
);
2197 info
->AutoTunnelDeviceInfo
.resrec
.rdata
->u
.data
[0] = 6 + len
; // "model=" plus the device string
2198 info
->AutoTunnelDeviceInfo
.resrec
.rdlength
= 7 + len
; // One extra for the length byte at the start of the string
2200 // 3. Set up our address record for the external tunnel address
2201 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2202 mDNS_SetupResourceRecord(&info
->AutoTunnelTarget
, mDNSNULL
, mDNSInterface_Any
, kDNSType_A
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2203 info
->AutoTunnelTarget
.namestorage
.c
[0] = 0;
2204 AppendDomainLabel(&info
->AutoTunnelTarget
.namestorage
, &m
->AutoTunnelLabel
);
2205 AppendDomainName (&info
->AutoTunnelTarget
.namestorage
, &info
->domain
);
2207 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2208 mDNS_SetupResourceRecord(&info
->AutoTunnelService
, mDNSNULL
, mDNSInterface_Any
, kDNSType_SRV
, kHostNameTTL
, kDNSRecordTypeUnregistered
, AutoTunnelRecordCallback
, info
);
2209 AssignDomainName(&info
->AutoTunnelService
.namestorage
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2210 AppendDomainLabel(&info
->AutoTunnelService
.namestorage
, &m
->hostlabel
);
2211 AppendDomainName (&info
->AutoTunnelService
.namestorage
, &info
->domain
);
2212 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.priority
= 0;
2213 info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.weight
= 0;
2214 AssignDomainName(&info
->AutoTunnelService
.resrec
.rdata
->u
.srv
.target
, &info
->AutoTunnelTarget
.namestorage
);
2216 // Try to get a NAT port mapping for the AutoTunnelService
2217 info
->AutoTunnelNAT
.clientCallback
= AutoTunnelNATCallback
;
2218 info
->AutoTunnelNAT
.clientContext
= info
;
2219 info
->AutoTunnelNAT
.Protocol
= NATOp_MapUDP
;
2220 info
->AutoTunnelNAT
.IntPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2221 info
->AutoTunnelNAT
.RequestedPort
= mDNSOpaque16fromIntVal(kRacoonPort
);
2222 info
->AutoTunnelNAT
.NATLease
= 0;
2223 mStatus err
= mDNS_StartNATOperation_internal(m
, &info
->AutoTunnelNAT
);
2224 if (err
) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err
);
2230 mDNSlocal mStatus
AutoTunnelSetKeys(ClientTunnel
*tun
, mDNSBool AddNew
)
2232 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
));
2235 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2236 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2238 mDNSlocal
void ReissueBlockedQuestions(mDNS
*const m
, domainname
*d
, mDNSBool success
)
2240 DNSQuestion
*q
= m
->Questions
;
2243 if (q
->NoAnswer
== NoAnswer_Suspended
&& q
->qtype
== kDNSType_AAAA
&& q
->AuthInfo
&& q
->AuthInfo
->AutoTunnel
&& SameDomainName(&q
->qname
, d
))
2245 LogOperation("Restart %##s", q
->qname
.c
);
2246 mDNSQuestionCallback
*tmp
= q
->QuestionCallback
;
2247 q
->QuestionCallback
= AutoTunnelCallback
; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2248 mDNS_StopQuery(m
, q
);
2249 mDNS_StartQuery(m
, q
);
2250 q
->QuestionCallback
= tmp
; // Restore QuestionCallback back to the real value
2251 if (!success
) q
->NoAnswer
= NoAnswer_Fail
;
2252 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2253 // In general we have to assume that the question list might have changed in arbitrary ways.
2254 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2255 // already in use. The safest solution is just to go back to the start of the list and start again.
2256 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2257 // just one suspended question, so it's really a 2n algorithm.
2265 mDNSlocal
void UnlinkAndReissueBlockedQuestions(mDNS
*const m
, ClientTunnel
*tun
, mDNSBool success
)
2267 ClientTunnel
**p
= &m
->TunnelClients
;
2268 while (*p
!= tun
&& *p
) p
= &(*p
)->next
;
2269 if (*p
) *p
= tun
->next
;
2270 ReissueBlockedQuestions(m
, &tun
->dstname
, success
);
2271 freeL("ClientTunnel", tun
);
2274 mDNSexport
void AutoTunnelCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2276 ClientTunnel
*tun
= (ClientTunnel
*)question
->QuestionContext
;
2277 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun
, AddRecord
, answer
->rdlength
, question
->qtype
);
2279 if (!AddRecord
) return;
2280 mDNS_StopQuery(m
, question
);
2282 if (!answer
->rdlength
)
2284 LogOperation("AutoTunnelCallback NXDOMAIN %##s", question
->qname
.c
);
2285 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNSfalse
);
2289 if (question
->qtype
== kDNSType_AAAA
)
2291 if (mDNSSameIPv6Address(answer
->rdata
->u
.ipv6
, m
->AutoTunnelHostAddr
))
2293 LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer
->rdata
->u
.ipv6
);
2294 UnlinkAndReissueBlockedQuestions(m
, tun
, mDNStrue
);
2298 tun
->rmt_inner
= answer
->rdata
->u
.ipv6
;
2299 LogOperation("AutoTunnelCallback: dst host %.16a", &tun
->rmt_inner
);
2300 AssignDomainName(&question
->qname
, (const domainname
*) "\x0B" "_autotunnel" "\x04" "_udp");
2301 AppendDomainName(&question
->qname
, &tun
->dstname
);
2302 question
->qtype
= kDNSType_SRV
;
2303 mDNS_StartQuery(m
, &tun
->q
);
2305 else if (question
->qtype
== kDNSType_SRV
)
2307 LogOperation("AutoTunnelCallback: SRV target name %##s", answer
->rdata
->u
.srv
.target
.c
);
2308 AssignDomainName(&tun
->q
.qname
, &answer
->rdata
->u
.srv
.target
);
2309 tun
->rmt_outer_port
= answer
->rdata
->u
.srv
.port
;
2310 question
->qtype
= kDNSType_A
;
2311 mDNS_StartQuery(m
, &tun
->q
);
2313 else if (question
->qtype
== kDNSType_A
)
2315 ClientTunnel
*old
= mDNSNULL
;
2316 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer
->rdata
->u
.ipv4
);
2317 question
->ThisQInterval
= -1; // So we know this tunnel setup has completed
2318 tun
->rmt_outer
= answer
->rdata
->u
.ipv4
;
2319 tun
->loc_inner
= m
->AutoTunnelHostAddr
;
2320 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
2321 tmpDst
.ip
.v4
= tun
->rmt_outer
;
2322 mDNSAddr tmpSrc
= zeroAddr
;
2323 FindSourceAddrForIP(&tmpDst
, &tmpSrc
);
2324 if (tmpSrc
.type
== mDNSAddrType_IPv4
) tun
->loc_outer
= tmpSrc
.ip
.v4
;
2325 else tun
->loc_outer
= m
->AdvertisedV4
.ip
.v4
;
2327 ClientTunnel
**p
= &tun
->next
;
2328 mDNSBool needSetKeys
= mDNStrue
;
2331 if (!mDNSSameClientTunnel(&(*p
)->rmt_inner
, &tun
->rmt_inner
)) p
= &(*p
)->next
;
2334 LogOperation("Found existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2337 if (old
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &old
->q
);
2338 else if (!mDNSSameIPv6Address(old
->loc_inner
, tun
->loc_inner
) ||
2339 !mDNSSameIPv4Address(old
->loc_outer
, tun
->loc_outer
) ||
2340 !mDNSSameIPv6Address(old
->rmt_inner
, tun
->rmt_inner
) ||
2341 !mDNSSameIPv4Address(old
->rmt_outer
, tun
->rmt_outer
) ||
2342 !mDNSSameIPPort(old
->rmt_outer_port
, tun
->rmt_outer_port
))
2344 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2345 AutoTunnelSetKeys(old
, mDNSfalse
);
2347 else needSetKeys
= mDNSfalse
;
2349 freeL("ClientTunnel", old
);
2353 if (needSetKeys
) LogOperation("New AutoTunnel for %##s %.16a", tun
->dstname
.c
, &tun
->rmt_inner
);
2355 if (m
->AutoTunnelHostAddr
.b
[0]) { mDNS_Lock(m
); SetupLocalAutoTunnelInterface_internal(m
); mDNS_Unlock(m
); };
2357 mStatus result
= needSetKeys
? AutoTunnelSetKeys(tun
, mDNStrue
) : mStatus_NoError
;
2358 // Kick off any questions that were held pending this tunnel setup
2359 ReissueBlockedQuestions(m
, &tun
->dstname
, (result
== mStatus_NoError
) ? mDNStrue
: mDNSfalse
);
2362 LogMsg("AutoTunnelCallback: Unknown question %p", question
);
2365 // Must be called with the lock held
2366 mDNSexport
void AddNewClientTunnel(mDNS
*const m
, DNSQuestion
*const q
)
2368 ClientTunnel
*p
= mallocL("ClientTunnel", sizeof(ClientTunnel
));
2370 AssignDomainName(&p
->dstname
, &q
->qname
);
2371 p
->markedForDeletion
= mDNSfalse
;
2372 p
->loc_inner
= zerov6Addr
;
2373 p
->loc_outer
= zerov4Addr
;
2374 p
->rmt_inner
= zerov6Addr
;
2375 p
->rmt_outer
= zerov4Addr
;
2376 p
->rmt_outer_port
= zeroIPPort
;
2377 mDNS_snprintf(p
->b64keydata
, sizeof(p
->b64keydata
), "%s", q
->AuthInfo
->b64keydata
);
2378 p
->next
= m
->TunnelClients
;
2379 m
->TunnelClients
= p
; // Intentionally build list in reverse order
2381 p
->q
.InterfaceID
= mDNSInterface_Any
;
2382 p
->q
.Target
= zeroAddr
;
2383 AssignDomainName(&p
->q
.qname
, &q
->qname
);
2384 p
->q
.qtype
= kDNSType_AAAA
;
2385 p
->q
.qclass
= kDNSClass_IN
;
2386 p
->q
.LongLived
= mDNSfalse
;
2387 p
->q
.ExpectUnique
= mDNStrue
;
2388 p
->q
.ForceMCast
= mDNSfalse
;
2389 p
->q
.ReturnIntermed
= mDNStrue
;
2390 p
->q
.QuestionCallback
= AutoTunnelCallback
;
2391 p
->q
.QuestionContext
= p
;
2393 LogOperation("AddNewClientTunnel start %##s (%s)%s", &p
->q
.qname
.c
, DNSTypeName(p
->q
.qtype
), q
->LongLived
? " LongLived" : "");
2394 mDNS_StartQuery_internal(m
, &p
->q
);
2397 #endif // APPLE_OSX_mDNSResponder
2399 #if COMPILER_LIKES_PRAGMA_MARK
2401 #pragma mark - Power State & Configuration Change Management
2404 mDNSlocal mStatus
UpdateInterfaceList(mDNS
*const m
, mDNSs32 utc
)
2406 mDNSBool foundav4
= mDNSfalse
;
2407 mDNSBool foundav6
= mDNSfalse
;
2408 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2409 struct ifaddrs
*v4Loopback
= NULL
;
2410 struct ifaddrs
*v6Loopback
= NULL
;
2411 mDNSEthAddr PrimaryMAC
= zeroEthAddr
;
2412 char defaultname
[32];
2414 int InfoSocket
= socket(AF_INET6
, SOCK_DGRAM
, 0);
2415 if (InfoSocket
< 3 && errno
!= EAFNOSUPPORT
) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket
, errno
, strerror(errno
));
2417 if (m
->SleepState
) ifa
= NULL
;
2421 #if LIST_ALL_INTERFACES
2422 if (ifa
->ifa_addr
->sa_family
== AF_APPLETALK
)
2423 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2424 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2425 else if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2426 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2427 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2428 else if (ifa
->ifa_addr
->sa_family
!= AF_INET
&& ifa
->ifa_addr
->sa_family
!= AF_INET6
)
2429 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2430 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2431 if (!(ifa
->ifa_flags
& IFF_UP
))
2432 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2433 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2434 if (!(ifa
->ifa_flags
& IFF_MULTICAST
))
2435 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2436 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2437 if (ifa
->ifa_flags
& IFF_POINTOPOINT
)
2438 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2439 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2440 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2441 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2442 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
);
2445 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
2447 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
2448 if (sdl
->sdl_type
== IFT_ETHER
&& sdl
->sdl_alen
== sizeof(PrimaryMAC
) && mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
))
2449 mDNSPlatformMemCopy(PrimaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6);
2452 if (ifa
->ifa_flags
& IFF_UP
&& ifa
->ifa_addr
)
2453 if (ifa
->ifa_addr
->sa_family
== AF_INET
|| ifa
->ifa_addr
->sa_family
== AF_INET6
)
2455 if (!ifa
->ifa_netmask
)
2458 SetupAddr(&ip
, ifa
->ifa_addr
);
2459 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2460 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
);
2462 else if (ifa
->ifa_addr
->sa_family
!= ifa
->ifa_netmask
->sa_family
)
2465 SetupAddr(&ip
, ifa
->ifa_addr
);
2466 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2467 ifa
->ifa_name
, if_nametoindex(ifa
->ifa_name
), ifa
->ifa_flags
, ifa
->ifa_addr
->sa_family
, &ip
, ifa
->ifa_netmask
->sa_family
);
2471 int ifru_flags6
= 0;
2473 if (ifa
->ifa_addr
->sa_family
== AF_INET6
&& InfoSocket
>= 0)
2475 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2476 struct in6_ifreq ifr6
;
2477 mDNSPlatformMemZero((char *)&ifr6
, sizeof(ifr6
));
2478 strlcpy(ifr6
.ifr_name
, ifa
->ifa_name
, sizeof(ifr6
.ifr_name
));
2479 ifr6
.ifr_addr
= *sin6
;
2480 if (ioctl(InfoSocket
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
2481 ifru_flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
2482 verbosedebugf("%s %.16a %04X %04X", ifa
->ifa_name
, &sin6
->sin6_addr
, ifa
->ifa_flags
, ifru_flags6
);
2485 if (!(ifru_flags6
& (IN6_IFF_NOTREADY
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
)))
2487 if (ifa
->ifa_flags
& IFF_LOOPBACK
)
2488 if (ifa
->ifa_addr
->sa_family
== AF_INET
) v4Loopback
= ifa
;
2489 else v6Loopback
= ifa
;
2492 NetworkInterfaceInfoOSX
*i
= AddInterfaceToList(m
, ifa
, utc
);
2493 if (i
&& MulticastInterface(i
))
2495 if (ifa
->ifa_addr
->sa_family
== AF_INET
) foundav4
= mDNStrue
;
2496 else foundav6
= mDNStrue
;
2502 ifa
= ifa
->ifa_next
;
2505 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2506 if (!foundav4
&& v4Loopback
) AddInterfaceToList(m
, v4Loopback
, utc
);
2507 if (!foundav6
&& v6Loopback
) AddInterfaceToList(m
, v6Loopback
, utc
);
2509 // Now the list is complete, set the McastTxRx setting for each interface.
2510 NetworkInterfaceInfoOSX
*i
;
2511 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2514 mDNSBool txrx
= MulticastInterface(i
);
2515 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2516 txrx
= txrx
&& ((i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4(m
, i
->scope_id
));
2518 if (i
->ifinfo
.McastTxRx
!= txrx
)
2520 i
->ifinfo
.McastTxRx
= txrx
;
2521 i
->Exists
= 2; // State change; need to deregister and reregister this interface
2526 if (InfoSocket
>= 0) close(InfoSocket
);
2529 // If we haven't set up AutoTunnelHostAddr yet, do it now
2530 if (!mDNSSameEthAddress(&PrimaryMAC
, &zeroEthAddr
) && m
->AutoTunnelHostAddr
.b
[0] == 0)
2532 m
->AutoTunnelHostAddr
.b
[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2533 m
->AutoTunnelHostAddr
.b
[0x1] = mDNSRandom(255);
2534 m
->AutoTunnelHostAddr
.b
[0x2] = mDNSRandom(255);
2535 m
->AutoTunnelHostAddr
.b
[0x3] = mDNSRandom(255);
2536 m
->AutoTunnelHostAddr
.b
[0x4] = mDNSRandom(255);
2537 m
->AutoTunnelHostAddr
.b
[0x5] = mDNSRandom(255);
2538 m
->AutoTunnelHostAddr
.b
[0x6] = mDNSRandom(255);
2539 m
->AutoTunnelHostAddr
.b
[0x7] = mDNSRandom(255);
2540 m
->AutoTunnelHostAddr
.b
[0x8] = PrimaryMAC
.b
[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
2541 m
->AutoTunnelHostAddr
.b
[0x9] = PrimaryMAC
.b
[1];
2542 m
->AutoTunnelHostAddr
.b
[0xA] = PrimaryMAC
.b
[2];
2543 m
->AutoTunnelHostAddr
.b
[0xB] = 0xFF;
2544 m
->AutoTunnelHostAddr
.b
[0xC] = 0xFE;
2545 m
->AutoTunnelHostAddr
.b
[0xD] = PrimaryMAC
.b
[3];
2546 m
->AutoTunnelHostAddr
.b
[0xE] = PrimaryMAC
.b
[4];
2547 m
->AutoTunnelHostAddr
.b
[0xF] = PrimaryMAC
.b
[5];
2548 m
->AutoTunnelLabel
.c
[0] = mDNS_snprintf((char*)m
->AutoTunnelLabel
.c
+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
2549 m
->AutoTunnelHostAddr
.b
[0x8], m
->AutoTunnelHostAddr
.b
[0x9], m
->AutoTunnelHostAddr
.b
[0xA], m
->AutoTunnelHostAddr
.b
[0xB],
2550 m
->AutoTunnelHostAddr
.b
[0xC], m
->AutoTunnelHostAddr
.b
[0xD], m
->AutoTunnelHostAddr
.b
[0xE], m
->AutoTunnelHostAddr
.b
[0xF]);
2551 LogOperation("m->AutoTunnelLabel %#s", m
->AutoTunnelLabel
.c
);
2554 #ifndef kDefaultLocalHostNamePrefix
2555 #define kDefaultLocalHostNamePrefix "Macintosh"
2557 mDNS_snprintf(defaultname
, sizeof(defaultname
), kDefaultLocalHostNamePrefix
"-%02X%02X%02X%02X%02X%02X",
2558 PrimaryMAC
.b
[0], PrimaryMAC
.b
[1], PrimaryMAC
.b
[2], PrimaryMAC
.b
[3], PrimaryMAC
.b
[4], PrimaryMAC
.b
[5]);
2560 // Set up the nice label
2561 domainlabel nicelabel
;
2563 GetUserSpecifiedFriendlyComputerName(&nicelabel
);
2564 if (nicelabel
.c
[0] == 0)
2566 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname
);
2567 MakeDomainLabelFromLiteralString(&nicelabel
, defaultname
);
2570 // Set up the RFC 1034-compliant label
2571 domainlabel hostlabel
;
2573 GetUserSpecifiedLocalHostName(&hostlabel
);
2574 if (hostlabel
.c
[0] == 0)
2576 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname
);
2577 MakeDomainLabelFromLiteralString(&hostlabel
, defaultname
);
2580 // We use a case-sensitive comparison here because even though changing the capitalization
2581 // of the name alone is not significant to DNS, it's still a change from the user's point of view
2582 if (SameDomainLabelCS(m
->p
->usernicelabel
.c
, nicelabel
.c
))
2583 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m
->p
->usernicelabel
.c
, m
->nicelabel
.c
);
2586 if (m
->p
->usernicelabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2587 LogMsg("User updated Computer Name from %#s to %#s", m
->p
->usernicelabel
.c
, nicelabel
.c
);
2588 m
->p
->usernicelabel
= m
->nicelabel
= nicelabel
;
2591 if (SameDomainLabelCS(m
->p
->userhostlabel
.c
, hostlabel
.c
))
2592 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m
->p
->userhostlabel
.c
, m
->hostlabel
.c
);
2595 if (m
->p
->userhostlabel
.c
[0]) // Don't show message first time through, when we first read name from prefs on boot
2596 LogMsg("User updated Local Hostname from %#s to %#s", m
->p
->userhostlabel
.c
, hostlabel
.c
);
2597 m
->p
->userhostlabel
= m
->hostlabel
= hostlabel
;
2601 return(mStatus_NoError
);
2604 #if LogAllOperations || MDNS_DEBUGMSGS
2605 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
2606 // Returns -1 if all the one-bits are not contiguous
2607 mDNSlocal
int CountMaskBits(mDNSAddr
*mask
)
2609 int i
= 0, bits
= 0;
2610 int bytes
= mask
->type
== mDNSAddrType_IPv4
? 4 : mask
->type
== mDNSAddrType_IPv6
? 16 : 0;
2613 mDNSu8 b
= mask
->ip
.v6
.b
[i
++];
2614 while (b
& 0x80) { bits
++; b
<<= 1; }
2617 while (i
< bytes
) if (mask
->ip
.v6
.b
[i
++]) return(-1);
2622 // returns count of non-link local V4 addresses registered
2623 mDNSlocal
int SetupActiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2625 NetworkInterfaceInfoOSX
*i
;
2627 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2630 NetworkInterfaceInfo
*n
= &i
->ifinfo
;
2631 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2632 if (!primary
) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i
->ifa_name
);
2634 if (n
->InterfaceID
&& n
->InterfaceID
!= (mDNSInterfaceID
)primary
) // Sanity check
2636 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n
->InterfaceID
, primary
);
2637 n
->InterfaceID
= mDNSNULL
;
2640 if (!n
->InterfaceID
)
2642 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2643 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2644 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2645 n
->InterfaceID
= (mDNSInterfaceID
)primary
;
2646 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2647 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2648 // 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.
2649 i
->Occulting
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->LastSeen
> 0 && utc
- i
->LastSeen
< 60);
2650 mDNS_RegisterInterface(m
, n
, i
->Flashing
&& i
->Occulting
);
2651 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2652 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2653 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
, CountMaskBits(&n
->mask
),
2654 i
->Flashing
? " (Flashing)" : "",
2655 i
->Occulting
? " (Occulting)" : "",
2656 n
->InterfaceActive
? " (Primary)" : "");
2660 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i
->ifa_name
, i
->scope_id
, &i
->BSSID
, primary
, &n
->ip
);
2663 if (i
->sa_family
== AF_INET
)
2666 primary
->ifa_v4addr
.s_addr
= i
->ifinfo
.ip
.ip
.v4
.NotAnInteger
;
2667 imr
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
2668 imr
.imr_interface
= primary
->ifa_v4addr
;
2669 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv4
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &imr
, sizeof(imr
));
2670 // Joining same group twice can give "Address already in use" error -- no need to report that
2671 if (err
< 0 && errno
!= EADDRINUSE
)
2672 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
2675 if (i
->sa_family
== AF_INET6
)
2677 struct ipv6_mreq i6mr
;
2678 i6mr
.ipv6mr_interface
= primary
->scope_id
;
2679 i6mr
.ipv6mr_multiaddr
= *(struct in6_addr
*)&AllDNSLinkGroup_v6
.ip
.v6
;
2680 mStatus err
= setsockopt(m
->p
->permanentsockets
.sktv6
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &i6mr
, sizeof(i6mr
));
2681 // Joining same group twice can give "Address already in use" error -- no need to report that
2682 if (err
< 0 && errno
!= EADDRINUSE
)
2683 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err
, errno
, strerror(errno
));
2691 mDNSlocal
void MarkAllInterfacesInactive(mDNS
*const m
, mDNSs32 utc
)
2693 NetworkInterfaceInfoOSX
*i
;
2694 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2696 if (i
->Exists
) i
->LastSeen
= utc
;
2697 i
->Exists
= mDNSfalse
;
2701 // returns count of non-link local V4 addresses deregistered
2702 mDNSlocal
int ClearInactiveInterfaces(mDNS
*const m
, mDNSs32 utc
)
2705 // If an interface is going away, then deregister this from the mDNSCore.
2706 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2707 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2708 // it refers to has gone away we'll crash.
2709 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2710 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2711 NetworkInterfaceInfoOSX
*i
;
2713 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2715 // If this interface is no longer active, or its InterfaceID is changing, deregister it
2716 NetworkInterfaceInfoOSX
*primary
= SearchForInterfaceByName(m
, i
->ifa_name
, i
->sa_family
);
2717 if (i
->ifinfo
.InterfaceID
)
2718 if (i
->Exists
== 0 || i
->Exists
== 2 || i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
)primary
)
2720 i
->Flashing
= !(i
->ifa_flags
& IFF_LOOPBACK
) && (utc
- i
->AppearanceTime
< 60);
2721 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2722 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2723 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
),
2724 i
->Flashing
? " (Flashing)" : "",
2725 i
->Occulting
? " (Occulting)" : "",
2726 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2727 mDNS_DeregisterInterface(m
, &i
->ifinfo
, i
->Flashing
&& i
->Occulting
);
2728 if (!mDNSAddressIsLinkLocal(&i
->ifinfo
.ip
)) count
++;
2729 i
->ifinfo
.InterfaceID
= mDNSNULL
;
2730 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2731 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2732 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2737 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2738 NetworkInterfaceInfoOSX
**p
= &m
->p
->InterfaceList
;
2742 // If no longer active, delete interface from list and free memory
2745 if (i
->LastSeen
== utc
) i
->LastSeen
= utc
- 1;
2746 mDNSBool
delete = (NumCacheRecordsForInterfaceID(m
, (mDNSInterfaceID
)i
) == 0) && (utc
- i
->LastSeen
>= 60);
2747 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2748 i
->ifa_name
, i
->scope_id
, &i
->BSSID
, i
->ifinfo
.InterfaceID
,
2749 &i
->ifinfo
.ip
, CountMaskBits(&i
->ifinfo
.mask
), utc
- i
->LastSeen
,
2750 i
->ifinfo
.InterfaceActive
? " (Primary)" : "");
2754 if (i
->ifa_name
) freeL("NetworkInterfaceInfoOSX name", i
->ifa_name
);
2755 freeL("NetworkInterfaceInfoOSX", i
);
2756 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2764 mDNSlocal
void AppendDNameListElem(DNameListElem
***List
, mDNSu32 uid
, domainname
*name
)
2766 DNameListElem
*dnle
= (DNameListElem
*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem
));
2767 if (!dnle
) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
2770 dnle
->next
= mDNSNULL
;
2772 AssignDomainName(&dnle
->name
, name
);
2774 *List
= &dnle
->next
;
2778 mDNSexport
void mDNSPlatformSetDNSConfig(mDNS
*const m
, mDNSBool setservers
, mDNSBool setsearch
, domainname
*const fqdn
, DNameListElem
**RegDomains
, DNameListElem
**BrowseDomains
)
2781 char buf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
2784 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
2785 if (fqdn
) fqdn
->c
[0] = 0;
2786 if (RegDomains
) *RegDomains
= NULL
;
2787 if (BrowseDomains
) *BrowseDomains
= NULL
;
2789 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
2790 setservers
? " setservers" : "",
2791 setsearch
? " setsearch" : "",
2792 fqdn
? " fqdn" : "",
2793 RegDomains
? " RegDomains" : "",
2794 BrowseDomains
? " BrowseDomains" : "");
2796 // Add the inferred address-based configuration discovery domains
2797 // (should really be in core code I think, not platform-specific)
2800 struct ifaddrs
*ifa
= myGetIfAddrs(1);
2804 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
2806 !(ifa
->ifa_flags
& IFF_LOOPBACK
) &&
2807 !SetupAddr(&a
, ifa
->ifa_addr
) &&
2808 !SetupAddr(&n
, ifa
->ifa_netmask
) &&
2809 !mDNSv4AddressIsLinkLocal(&a
.ip
.v4
) )
2811 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2812 mDNS_snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d.in-addr.arpa.", a
.ip
.v4
.b
[3] & n
.ip
.v4
.b
[3],
2813 a
.ip
.v4
.b
[2] & n
.ip
.v4
.b
[2],
2814 a
.ip
.v4
.b
[1] & n
.ip
.v4
.b
[1],
2815 a
.ip
.v4
.b
[0] & n
.ip
.v4
.b
[0]);
2816 mDNS_AddSearchDomain_CString(buf
);
2818 ifa
= ifa
->ifa_next
;
2822 #ifndef MDNS_NO_DNSINFO
2823 if (setservers
|| setsearch
)
2825 dns_config_t
*config
= dns_configuration_copy();
2828 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2829 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2830 // Apparently this is expected behaviour -- "not a bug".
2831 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2832 // If we are still getting failures after three minutes, then we log them.
2833 if (mDNSMacOSXSystemBuildNumber(NULL
) > 7 && (mDNSu32
)mDNSPlatformRawTime() > (mDNSu32
)(mDNSPlatformOneSecond
* 180))
2834 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2838 LogOperation("mDNSPlatformSetDNSConfig: Registering %d resolvers", config
->n_resolver
);
2841 for (i
= 0; i
< config
->n_resolver
; i
++)
2844 dns_resolver_t
*r
= config
->resolver
[i
];
2845 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
2846 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
2847 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
2848 if (r
->port
== 5353) continue;
2849 if (r
->search_order
== DEFAULT_SEARCH_ORDER
|| !r
->domain
|| !*r
->domain
) d
.c
[0] = 0; // we ignore domain for "default" resolver
2850 else if (!MakeDomainNameFromDNSNameString(&d
, r
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", r
->domain
); continue; }
2852 for (j
= 0; j
< config
->n_resolver
; j
++) // check if this is the lowest-weighted server for the domain
2854 dns_resolver_t
*p
= config
->resolver
[j
];
2855 if (p
->port
== 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
2856 if (p
->search_order
<= r
->search_order
)
2859 if (p
->search_order
== DEFAULT_SEARCH_ORDER
|| !p
->domain
|| !*p
->domain
) tmp
.c
[0] = '\0';
2860 else if (!MakeDomainNameFromDNSNameString(&tmp
, p
->domain
)) { LogMsg("RegisterSplitDNS: bad domain %s", p
->domain
); continue; }
2861 if (SameDomainName(&d
, &tmp
))
2862 if (p
->search_order
< r
->search_order
|| j
< i
) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2865 if (j
< config
->n_resolver
) // found a lower-weighted resolver for this domain
2866 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i
, d
.c
, j
);
2869 mDNSInterfaceID interface
= mDNSInterface_Any
;
2872 // DNS server option parsing
2873 if (r
->options
!= NULL
)
2875 char *nextOption
= r
->options
;
2876 char *currentOption
= NULL
;
2877 while ((currentOption
= strsep(&nextOption
, " ")) != NULL
&& currentOption
[0] != 0)
2879 // The option may be in the form of interface=xxx where xxx is an interface name.
2880 if (strncmp(currentOption
, kInterfaceSpecificOption
, sizeof(kInterfaceSpecificOption
) - 1) == 0)
2882 NetworkInterfaceInfoOSX
*i
;
2883 char ifname
[IF_NAMESIZE
+1];
2884 mDNSu32 ifindex
= 0;
2885 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
2886 // This allows us to block these special queries from going out on the wire.
2887 strlcpy(ifname
, currentOption
+ sizeof(kInterfaceSpecificOption
)-1, sizeof(ifname
));
2888 ifindex
= if_nametoindex(ifname
);
2889 if (ifindex
== 0) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname
); continue; }
2890 LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__
, r
->domain
, ifname
, ifindex
);
2891 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
2892 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
2893 for (i
= m
->p
->InterfaceList
; i
; i
= i
->next
)
2894 if (i
->ifinfo
.InterfaceID
&& i
->scope_id
== ifindex
) break;
2895 if (i
!= NULL
) interface
= i
->ifinfo
.InterfaceID
;
2896 if (interface
== mDNSNULL
) { disabled
= 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex
, ifname
); continue; }
2900 for (n
= 0; n
< r
->n_nameserver
; n
++)
2901 if (r
->nameserver
[n
]->sa_family
== AF_INET
&& (interface
|| disabled
|| !AddrRequiresPPPConnection(r
->nameserver
[n
])))
2904 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
2905 debugf("Adding dns server from slot %d %#a for domain %##s", i
, &saddr
, d
.c
);
2906 if (SetupAddr(&saddr
, r
->nameserver
[n
])) LogMsg("RegisterSplitDNS: bad IP address");
2909 DNSServer
*s
= mDNS_AddDNSServer(m
, &d
, mDNSInterface_Any
, &saddr
, r
->port
? mDNSOpaque16fromIntVal(r
->port
) : UnicastDNSPort
);
2910 if (s
&& disabled
) s
->teststate
= DNSServer_Disabled
;
2918 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
2919 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
2920 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
2921 // instead use the search domain list as the sole authority for what domains to search and in what order
2922 // (and the domain from the "domain" field will also appear somewhere in that list).
2923 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
2924 // search lists for other resolvers in the list need to be ignored.
2925 if (config
->resolver
[0]->n_search
== 0) mDNS_AddSearchDomain_CString(config
->resolver
[0]->domain
);
2926 else for (i
= 0; i
< config
->resolver
[0]->n_search
; i
++) mDNS_AddSearchDomain_CString(config
->resolver
[0]->search
[i
]);
2928 dns_configuration_free(config
);
2929 setservers
= mDNSfalse
; // Done these now -- no need to fetch the same data from SCDynamicStore
2930 setsearch
= mDNSfalse
;
2933 #endif // MDNS_NO_DNSINFO
2935 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL
, NULL
);
2938 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_DynamicDNS
);
2943 CFArrayRef fqdnArray
= CFDictionaryGetValue(dict
, CFSTR("HostNames"));
2944 if (fqdnArray
&& CFArrayGetCount(fqdnArray
) > 0)
2946 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
2947 CFDictionaryRef fqdnDict
= CFArrayGetValueAtIndex(fqdnArray
, 0);
2948 if (fqdnDict
&& DDNSSettingEnabled(fqdnDict
))
2950 CFStringRef name
= CFDictionaryGetValue(fqdnDict
, CFSTR("Domain"));
2953 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
2954 !MakeDomainNameFromDNSNameString(fqdn
, buf
) || !fqdn
->c
[0])
2955 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf
[0] ? buf
: "(unknown)");
2956 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf
);
2964 CFArrayRef regArray
= CFDictionaryGetValue(dict
, CFSTR("RegistrationDomains"));
2965 if (regArray
&& CFArrayGetCount(regArray
) > 0)
2967 CFDictionaryRef regDict
= CFArrayGetValueAtIndex(regArray
, 0);
2968 if (regDict
&& DDNSSettingEnabled(regDict
))
2970 CFStringRef name
= CFDictionaryGetValue(regDict
, CFSTR("Domain"));
2973 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
2974 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
2975 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf
[0] ? buf
: "(unknown)");
2978 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf
);
2979 AppendDNameListElem(&RegDomains
, 0, &d
);
2988 CFArrayRef browseArray
= CFDictionaryGetValue(dict
, CFSTR("BrowseDomains"));
2991 for (i
= 0; i
< CFArrayGetCount(browseArray
); i
++)
2993 CFDictionaryRef browseDict
= CFArrayGetValueAtIndex(browseArray
, i
);
2994 if (browseDict
&& DDNSSettingEnabled(browseDict
))
2996 CFStringRef name
= CFDictionaryGetValue(browseDict
, CFSTR("Domain"));
2999 if (!CFStringGetCString(name
, buf
, sizeof(buf
), kCFStringEncodingUTF8
) ||
3000 !MakeDomainNameFromDNSNameString(&d
, buf
) || !d
.c
[0])
3001 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf
[0] ? buf
: "(unknown)");
3004 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf
);
3005 AppendDNameListElem(&BrowseDomains
, 0, &d
);
3017 CFDictionaryRef btmm
= SCDynamicStoreCopyValue(store
, NetworkChangedKey_BackToMyMac
);
3020 CFIndex size
= CFDictionaryGetCount(btmm
);
3021 const void *key
[size
];
3022 const void *val
[size
];
3023 CFDictionaryGetKeysAndValues(btmm
, key
, val
);
3024 for (i
= 0; i
< size
; i
++)
3026 LogOperation("BackToMyMac %d", i
);
3027 if (!CFStringGetCString(key
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3028 LogMsg("Can't read BackToMyMac %d key %s", i
, buf
);
3031 mDNSu32 uid
= atoi(buf
);
3032 if (!CFStringGetCString(val
[i
], buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3033 LogMsg("Can't read BackToMyMac %d val %s", i
, buf
);
3034 else if (MakeDomainNameFromDNSNameString(&d
, buf
) && d
.c
[0])
3036 LogOperation("BackToMyMac %d %d %##s", i
, uid
, d
.c
);
3037 AppendDNameListElem(&RegDomains
, uid
, &d
);
3045 if (setservers
|| setsearch
)
3047 CFStringRef key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3050 CFDictionaryRef dict
= SCDynamicStoreCopyValue(store
, key
);
3055 CFArrayRef values
= CFDictionaryGetValue(dict
, kSCPropNetDNSServerAddresses
);
3058 for (i
= 0; i
< CFArrayGetCount(values
); i
++)
3060 CFStringRef s
= CFArrayGetValueAtIndex(values
, i
);
3062 mDNSAddr addr
= { mDNSAddrType_IPv4
, { { { 0 } } } };
3063 if (s
&& CFStringGetCString(s
, buf
, 256, kCFStringEncodingUTF8
) &&
3064 inet_aton(buf
, (struct in_addr
*) &addr
.ip
.v4
))
3065 mDNS_AddDNSServer(m
, mDNSNULL
, mDNSInterface_Any
, &addr
, UnicastDNSPort
);
3071 // Add the manual and/or DHCP-dicovered search domains
3072 CFArrayRef searchDomains
= CFDictionaryGetValue(dict
, kSCPropNetDNSSearchDomains
);
3075 for (i
= 0; i
< CFArrayGetCount(searchDomains
); i
++)
3077 CFStringRef s
= CFArrayGetValueAtIndex(searchDomains
, i
);
3078 if (s
&& CFStringGetCString(s
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3079 mDNS_AddSearchDomain_CString(buf
);
3082 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3084 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3085 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3086 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3087 // instead use the search domain list as the sole authority for what domains to search and in what order
3088 // (and the domain from the "domain" field will also appear somewhere in that list).
3089 CFStringRef string
= CFDictionaryGetValue(dict
, kSCPropNetDNSDomainName
);
3090 if (string
&& CFStringGetCString(string
, buf
, sizeof(buf
), kCFStringEncodingUTF8
))
3091 mDNS_AddSearchDomain_CString(buf
);
3103 mDNSexport mStatus
mDNSPlatformGetPrimaryInterface(mDNS
*const m
, mDNSAddr
*v4
, mDNSAddr
*v6
, mDNSAddr
*r
)
3105 SCDynamicStoreRef store
= NULL
;
3106 CFDictionaryRef dict
= NULL
;
3107 CFStringRef key
= NULL
;
3108 CFStringRef string
= NULL
;
3114 // get IPv4 settings
3116 store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL
, NULL
);
3117 require_action(store
, exit
, err
= mStatus_UnknownErr
);
3119 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3120 require_action(key
, exit
, err
= mStatus_UnknownErr
);
3122 dict
= SCDynamicStoreCopyValue(store
, key
);
3123 require_action(dict
, exit
, err
= mStatus_UnknownErr
);
3125 // handle router changes
3127 r
->type
= mDNSAddrType_IPv4
;
3128 r
->ip
.v4
= zerov4Addr
;
3130 string
= CFDictionaryGetValue(dict
, kSCPropNetIPv4Router
);
3134 struct sockaddr_in saddr
;
3136 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
))
3137 LogMsg("Could not convert router to CString");
3140 saddr
.sin_len
= sizeof(saddr
);
3141 saddr
.sin_family
= AF_INET
;
3143 inet_aton(buf
, &saddr
.sin_addr
);
3145 if (AddrRequiresPPPConnection((struct sockaddr
*)&saddr
)) debugf("Ignoring router %s (requires PPP connection)", buf
);
3146 else *(in_addr_t
*)&r
->ip
.v4
= saddr
.sin_addr
.s_addr
;
3150 // handle primary interface changes
3151 // 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
3152 if (nAdditions
|| nDeletions
) mDNS_SetPrimaryInterfaceInfo(m
, NULL
, NULL
, NULL
);
3154 string
= CFDictionaryGetValue(dict
, kSCDynamicStorePropNetPrimaryInterface
);
3158 mDNSBool HavePrimaryGlobalv6
= mDNSfalse
; // does the primary interface have a global v6 address?
3159 struct ifaddrs
*ifa
= myGetIfAddrs(1);
3161 *v4
= *v6
= zeroAddr
;
3163 if (!CFStringGetCString(string
, buf
, 256, kCFStringEncodingUTF8
)) { LogMsg("Could not convert router to CString"); goto exit
; }
3165 // find primary interface in list
3166 while (ifa
&& (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
) || !HavePrimaryGlobalv6
))
3168 mDNSAddr tmp6
= zeroAddr
;
3169 if (!strcmp(buf
, ifa
->ifa_name
))
3171 if (ifa
->ifa_addr
->sa_family
== AF_INET
)
3173 if (mDNSIPv4AddressIsZero(v4
->ip
.v4
) || mDNSv4AddressIsLinkLocal(&v4
->ip
.v4
)) SetupAddr(v4
, ifa
->ifa_addr
);
3175 else if (ifa
->ifa_addr
->sa_family
== AF_INET6
)
3177 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3178 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) // global prefix: 001
3179 { HavePrimaryGlobalv6
= mDNStrue
; *v6
= tmp6
; }
3184 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3185 if (!HavePrimaryGlobalv6
&& ifa
->ifa_addr
->sa_family
== AF_INET6
&& !v6
->ip
.v6
.b
[0])
3187 SetupAddr(&tmp6
, ifa
->ifa_addr
);
3188 if (tmp6
.ip
.v6
.b
[0] >> 5 == 1) *v6
= tmp6
;
3191 ifa
= ifa
->ifa_next
;
3194 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3195 // V4 to communicate w/ our DNS server
3199 if (dict
) CFRelease(dict
);
3200 if (key
) CFRelease(key
);
3201 if (store
) CFRelease(store
);
3205 mDNSexport
void mDNSPlatformDynDNSHostNameStatusChanged(const domainname
*const dname
, const mStatus status
)
3207 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status
, dname
->c
);
3208 char uname
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3209 ConvertDomainNameToCString(dname
, uname
);
3215 if (!(*(p
+1)) && *p
== '.') *p
= 0; // if last character, strip trailing dot
3219 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3220 // That single entity is a CFDictionary with name "HostNames".
3221 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3222 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3223 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3224 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3225 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3227 const CFStringRef StateKeys
[1] = { CFSTR("HostNames") };
3228 const CFStringRef HostKeys
[1] = { CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
) };
3229 const CFStringRef StatusKeys
[1] = { CFSTR("Status") };
3230 if (!HostKeys
[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname
);
3233 const CFNumberRef StatusVals
[1] = { CFNumberCreate(NULL
, kCFNumberSInt32Type
, &status
) };
3234 if (!StatusVals
[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status
);
3237 const CFDictionaryRef HostVals
[1] = { CFDictionaryCreate(NULL
, (void*)StatusKeys
, (void*)StatusVals
, 1, NULL
, NULL
) };
3240 const CFDictionaryRef StateVals
[1] = { CFDictionaryCreate(NULL
, (void*)HostKeys
, (void*)HostVals
, 1, NULL
, NULL
) };
3243 CFDictionaryRef StateDict
= CFDictionaryCreate(NULL
, (void*)StateKeys
, (void*)StateVals
, 1, NULL
, NULL
);
3246 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig
, StateDict
);
3247 CFRelease(StateDict
);
3249 CFRelease(StateVals
[0]);
3251 CFRelease(HostVals
[0]);
3253 CFRelease(StatusVals
[0]);
3255 CFRelease(HostKeys
[0]);
3259 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3260 mDNSlocal
void SetDomainSecrets(mDNS
*m
)
3262 #ifdef NO_SECURITYFRAMEWORK
3264 LogMsg("Note: SetDomainSecrets: no keychain support");
3266 mDNSBool haveAutoTunnels
= mDNSfalse
;
3268 LogOperation("SetDomainSecrets");
3270 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3271 // In the case where the user simultaneously removes their DDNS host name and the key
3272 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3273 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3274 // address records behind that we no longer have permission to delete.
3275 DomainAuthInfo
*ptr
;
3276 for (ptr
= m
->AuthInfoList
; ptr
; ptr
= ptr
->next
)
3277 ptr
->deltime
= NonZeroTime(m
->timenow
+ mDNSPlatformOneSecond
*10);
3279 #if APPLE_OSX_mDNSResponder
3281 // Mark all TunnelClients for deletion
3282 ClientTunnel
*client
;
3283 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3285 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client
->dstname
.c
);
3286 client
->markedForDeletion
= mDNStrue
;
3289 #endif APPLE_OSX_mDNSResponder
3291 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3292 if (!sa
) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3294 CFDataRef data
= NULL
;
3295 const int itemsPerEntry
= 3; // domain name, key name, key value
3296 CFArrayRef secrets
= NULL
;
3297 int err
= mDNSKeychainGetSecrets(&secrets
);
3298 if (err
|| !secrets
)
3299 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err
, secrets
);
3302 CFIndex ArrayCount
= CFArrayGetCount(secrets
);
3303 // Iterate through the secrets
3304 for (i
= 0; i
< ArrayCount
; ++i
)
3307 CFArrayRef entry
= CFArrayGetValueAtIndex(secrets
, i
);
3308 if (CFArrayGetTypeID() != CFGetTypeID(entry
) || itemsPerEntry
!= CFArrayGetCount(entry
))
3309 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3310 for (j
= 0; j
< CFArrayGetCount(entry
); ++j
)
3311 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry
, j
)))
3312 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3314 // Validate that attributes are not too large
3315 char dstring
[MAX_ESCAPED_DOMAIN_NAME
];
3316 char keynamebuf
[MAX_ESCAPED_DOMAIN_NAME
]; // Max legal C-string name, including terminating NUL
3317 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3318 data
= CFArrayGetValueAtIndex(entry
, 0);
3319 if (CFDataGetLength(data
) >= (int)sizeof(dstring
))
3320 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data
)); continue; }
3321 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)dstring
);
3322 dstring
[CFDataGetLength(data
)] = '\0';
3323 data
= CFArrayGetValueAtIndex(entry
, 1);
3324 if (CFDataGetLength(data
) >= (int)sizeof(keynamebuf
))
3325 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data
)); continue; }
3326 CFDataGetBytes(data
, CFRangeMake(0,CFDataGetLength(data
)), (UInt8
*)keynamebuf
);
3327 keynamebuf
[CFDataGetLength(data
)] = '\0';
3330 if (!MakeDomainNameFromDNSNameString(&domain
, dstring
)) { LogMsg("SetDomainSecrets: bad key domain %s", dstring
); continue; }
3334 if (!MakeDomainNameFromDNSNameString(&keyname
, keynamebuf
)) { LogMsg("SetDomainSecrets: bad key name %s", keynamebuf
); continue; }
3337 char keystring
[1024];
3338 data
= CFArrayGetValueAtIndex(entry
, 2);
3339 if (CFDataGetLength(data
) >= (int)sizeof(keystring
))
3340 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data
)); continue; }
3341 CFDataGetBytes(data
, CFRangeMake(0, CFDataGetLength(data
)), (UInt8
*)keystring
);
3342 keystring
[CFDataGetLength(data
)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3344 DomainAuthInfo
*FoundInList
;
3345 for (FoundInList
= m
->AuthInfoList
; FoundInList
; FoundInList
= FoundInList
->next
)
3346 if (SameDomainName(&FoundInList
->domain
, &domain
)) break;
3348 #if APPLE_OSX_mDNSResponder
3351 // If any client tunnel destination is in this domain, set deletion flag to false
3352 ClientTunnel
*client
;
3353 for (client
= m
->TunnelClients
; client
; client
= client
->next
)
3354 if (FoundInList
== GetAuthInfoForName_internal(m
, &client
->dstname
))
3356 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client
->dstname
.c
);
3357 client
->markedForDeletion
= mDNSfalse
;
3358 // If the key has changed, reconfigure the tunnel
3359 if (strncmp(keystring
, client
->b64keydata
, sizeof(client
->b64keydata
)))
3361 mDNSBool queryNotInProgress
= client
->q
.ThisQInterval
< 0;
3362 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client
->dstname
.c
, queryNotInProgress
? "reconfiguring" : "query in progress");
3363 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNSfalse
);
3364 mDNS_snprintf(client
->b64keydata
, sizeof(client
->b64keydata
), "%s", keystring
);
3365 if (queryNotInProgress
) AutoTunnelSetKeys(client
, mDNStrue
);
3370 mDNSBool keyChanged
= FoundInList
&& FoundInList
->AutoTunnel
? strncmp(keystring
, FoundInList
->b64keydata
, sizeof(FoundInList
->b64keydata
)) : mDNSfalse
;
3372 #endif APPLE_OSX_mDNSResponder
3374 // Uncomment the line below to view the keys as they're read out of the system keychain
3375 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3376 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, keystring);
3378 // If didn't find desired domain in the list, make a new entry
3380 if (FoundInList
&& FoundInList
->AutoTunnel
&& haveAutoTunnels
== mDNSfalse
) haveAutoTunnels
= mDNStrue
;
3383 ptr
= (DomainAuthInfo
*)mallocL("DomainAuthInfo", sizeof(*ptr
));
3384 if (!ptr
) { LogMsg("SetDomainSecrets: No memory"); continue; }
3387 LogOperation("SetDomainSecrets: %d of %d %##s", i
, ArrayCount
, &domain
);
3388 if (mDNS_SetSecretForDomain(m
, ptr
, &domain
, &keyname
, keystring
, IsTunnelModeDomain(&domain
)) == mStatus_BadParamErr
)
3390 if (!FoundInList
) mDNSPlatformMemFree(ptr
); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3394 #if APPLE_OSX_mDNSResponder
3395 if (keyChanged
&& AnonymousRacoonConfig
)
3397 LogOperation("SetDomainSecrets: secret changed for %##s", &domain
);
3398 (void)mDNSConfigureServer(kmDNSUp
, keystring
);
3400 #endif APPLE_OSX_mDNSResponder
3402 CFStringRef cfs
= CFStringCreateWithCString(NULL
, dstring
, kCFStringEncodingUTF8
);
3403 if (cfs
) { CFArrayAppendValue(sa
, cfs
); CFRelease(cfs
); }
3407 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig
, sa
);
3410 #if APPLE_OSX_mDNSResponder
3412 // clean up ClientTunnels
3413 ClientTunnel
**ptr
= &m
->TunnelClients
;
3416 if ((*ptr
)->markedForDeletion
)
3418 ClientTunnel
*cur
= *ptr
;
3419 LogOperation("SetDomainSecrets: removing client %##s from list", cur
->dstname
.c
);
3420 if (cur
->q
.ThisQInterval
>= 0) mDNS_StopQuery(m
, &cur
->q
);
3421 AutoTunnelSetKeys(cur
, mDNSfalse
);
3423 freeL("ClientTunnel", cur
);
3426 ptr
= &(*ptr
)->next
;
3429 DomainAuthInfo
*info
= m
->AuthInfoList
;
3432 if (info
->AutoTunnel
&& info
->deltime
&& info
->AutoTunnelNAT
.clientContext
)
3434 // stop the NAT operation
3435 mDNS_StopNATOperation_internal(m
, &info
->AutoTunnelNAT
);
3436 if (info
->AutoTunnelHostRecord
.namestorage
.c
[0] && info
->AutoTunnelNAT
.clientCallback
)
3438 // reset port and let the AutoTunnelNATCallback handle cleanup
3439 info
->AutoTunnelNAT
.ExternalAddress
= m
->ExternalAddress
;
3440 info
->AutoTunnelNAT
.ExternalPort
= zeroIPPort
;
3441 info
->AutoTunnelNAT
.Lifetime
= 0;
3442 info
->AutoTunnelNAT
.Result
= mStatus_NoError
;
3443 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3444 info
->AutoTunnelNAT
.clientCallback(m
, &info
->AutoTunnelNAT
);
3445 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3447 info
->AutoTunnelNAT
.clientContext
= mDNSNULL
;
3452 if (!haveAutoTunnels
&& !m
->TunnelClients
&& m
->AutoTunnelHostAddrActive
)
3454 // remove interface if no autotunnel servers and no more client tunnels
3455 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3456 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
3457 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
3458 memset(m
->AutoTunnelHostAddr
.b
, 0, sizeof(m
->AutoTunnelHostAddr
.b
));
3461 if (!haveAutoTunnels
&& AnonymousRacoonConfig
)
3463 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3464 AnonymousRacoonConfig
= mDNSfalse
;
3465 (void)mDNSConfigureServer(kmDNSDown
, "");
3468 if (m
->AutoTunnelHostAddr
.b
[0])
3469 if (TunnelClients(m
) || TunnelServers(m
))
3470 SetupLocalAutoTunnelInterface_internal(m
);
3472 #endif APPLE_OSX_mDNSResponder
3474 #endif /* NO_SECURITYFRAMEWORK */
3477 mDNSlocal
void SetLocalDomains(void)
3479 CFMutableArrayRef sa
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3480 if (!sa
) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3482 CFArrayAppendValue(sa
, CFSTR("local"));
3483 CFArrayAppendValue(sa
, CFSTR("254.169.in-addr.arpa"));
3484 CFArrayAppendValue(sa
, CFSTR("8.e.f.ip6.arpa"));
3485 CFArrayAppendValue(sa
, CFSTR("9.e.f.ip6.arpa"));
3486 CFArrayAppendValue(sa
, CFSTR("a.e.f.ip6.arpa"));
3487 CFArrayAppendValue(sa
, CFSTR("b.e.f.ip6.arpa"));
3489 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig
, sa
);
3493 mDNSexport
void mDNSMacOSXNetworkChanged(mDNS
*const m
)
3495 LogOperation("*** Network Configuration Change *** (%d)%s",
3496 m
->p
->NetworkChanged
? mDNS_TimeNow(m
) - m
->p
->NetworkChanged
: 0,
3497 m
->p
->NetworkChanged
? "": " (no scheduled configuration change)");
3498 m
->p
->NetworkChanged
= 0; // If we received a network change event and deferred processing, we're now dealing with it
3499 mDNSs32 utc
= mDNSPlatformUTC();
3500 MarkAllInterfacesInactive(m
, utc
);
3501 UpdateInterfaceList(m
, utc
);
3502 int nDeletions
= ClearInactiveInterfaces(m
, utc
);
3503 int nAdditions
= SetupActiveInterfaces(m
, utc
);
3505 #if APPLE_OSX_mDNSResponder
3507 if (m
->AutoTunnelHostAddr
.b
[0])
3510 if (TunnelClients(m
) || TunnelServers(m
))
3511 SetupLocalAutoTunnelInterface_internal(m
);
3515 // Scan to find client tunnels whose questions have completed,
3516 // but whose local inner/outer addresses have changed since the tunnel was set up
3518 for (p
= m
->TunnelClients
; p
; p
= p
->next
)
3519 if (p
->q
.ThisQInterval
< 0)
3521 mDNSAddr tmpSrc
= zeroAddr
;
3522 mDNSAddr tmpDst
= { mDNSAddrType_IPv4
, {{{0}}} };
3523 tmpDst
.ip
.v4
= p
->rmt_outer
;
3524 FindSourceAddrForIP(&tmpDst
, &tmpSrc
);
3525 if (!mDNSSameIPv6Address(p
->loc_inner
, m
->AutoTunnelHostAddr
) ||
3526 !mDNSSameIPv4Address(p
->loc_outer
, tmpSrc
.ip
.v4
))
3528 AutoTunnelSetKeys(p
, mDNSfalse
);
3529 p
->loc_inner
= m
->AutoTunnelHostAddr
;
3530 p
->loc_outer
= tmpSrc
.ip
.v4
;
3531 AutoTunnelSetKeys(p
, mDNStrue
);
3535 #endif APPLE_OSX_mDNSResponder
3537 uDNS_SetupDNSConfig(m
); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
3538 if (nDeletions
|| nAdditions
) mDNS_UpdateLLQs(m
); // so that LLQs are restarted against the up to date name servers
3540 if (m
->MainCallback
)
3541 m
->MainCallback(m
, mStatus_ConfigChanged
);
3544 mDNSlocal
void NetworkChanged(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *context
)
3546 (void)store
; // Parameter not used
3547 (void)changedKeys
; // Parameter not used
3548 mDNS
*const m
= (mDNS
*const)context
;
3552 mDNSs32 delay
= mDNSPlatformOneSecond
; // Start off assuming a one-second delay
3554 int c
= CFArrayGetCount(changedKeys
); // Count changes
3555 CFRange range
= { 0, c
};
3556 int c1
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Hostnames
) != 0);
3557 int c2
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_Computername
) != 0);
3558 int c3
= (CFArrayContainsValue(changedKeys
, range
, NetworkChangedKey_DynamicDNS
) != 0);
3559 if (c
&& c
- c1
- c2
- c3
== 0) delay
= mDNSPlatformOneSecond
/20; // If these were the only changes, shorten delay
3561 #if LogAllOperations
3566 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys
, i
), buf
, sizeof(buf
), kCFStringEncodingUTF8
)) buf
[0] = 0;
3567 LogOperation("*** NetworkChanged SC key: %s", buf
);
3569 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
3571 c1
? "(Local Hostname) " : "",
3572 c2
? "(Computer Name) " : "",
3573 c3
? "(DynamicDNS) " : "",
3577 if (!m
->p
->NetworkChanged
||
3578 m
->p
->NetworkChanged
- NonZeroTime(m
->timenow
+ delay
) < 0)
3579 m
->p
->NetworkChanged
= NonZeroTime(m
->timenow
+ delay
);
3581 if (!m
->SuppressSending
||
3582 m
->SuppressSending
- m
->p
->NetworkChanged
< 0)
3583 m
->SuppressSending
= m
->p
->NetworkChanged
;
3586 KQueueUnlock(m
, "NetworkChanged");
3589 mDNSlocal mStatus
WatchForNetworkChanges(mDNS
*const m
)
3592 SCDynamicStoreContext context
= { 0, m
, NULL
, NULL
, NULL
};
3593 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged
, &context
);
3594 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3595 CFStringRef pattern1
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv4
);
3596 CFStringRef pattern2
= SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL
, kSCDynamicStoreDomainState
, kSCCompAnyRegex
, kSCEntNetIPv6
);
3597 CFMutableArrayRef patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3599 if (!store
) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error
; }
3600 if (!keys
|| !pattern1
|| !pattern2
|| !patterns
) goto error
;
3602 CFArrayAppendValue(keys
, NetworkChangedKey_IPv4
);
3603 CFArrayAppendValue(keys
, NetworkChangedKey_IPv6
);
3604 CFArrayAppendValue(keys
, NetworkChangedKey_Hostnames
);
3605 CFArrayAppendValue(keys
, NetworkChangedKey_Computername
);
3606 CFArrayAppendValue(keys
, NetworkChangedKey_DNS
);
3607 CFArrayAppendValue(keys
, NetworkChangedKey_DynamicDNS
);
3608 CFArrayAppendValue(keys
, NetworkChangedKey_BackToMyMac
);
3609 CFArrayAppendValue(patterns
, pattern1
);
3610 CFArrayAppendValue(patterns
, pattern2
);
3611 CFArrayAppendValue(patterns
, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3612 if (!SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
3613 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error
; }
3615 m
->p
->StoreRLS
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
3616 if (!m
->p
->StoreRLS
) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error
; }
3618 CFRunLoopAddSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3619 m
->p
->Store
= store
;
3624 if (store
) CFRelease(store
);
3627 if (patterns
) CFRelease(patterns
);
3628 if (pattern2
) CFRelease(pattern2
);
3629 if (pattern1
) CFRelease(pattern1
);
3630 if (keys
) CFRelease(keys
);
3635 #ifndef NO_SECURITYFRAMEWORK
3636 mDNSlocal OSStatus
KeychainChanged(SecKeychainEvent keychainEvent
, SecKeychainCallbackInfo
*info
, void *context
)
3638 LogOperation("*** Keychain Changed ***");
3639 mDNS
*const m
= (mDNS
*const)context
;
3641 OSStatus err
= SecKeychainCopyDefault(&skc
);
3644 if (info
->keychain
== skc
)
3646 // 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
3647 mDNSBool relevant
= (keychainEvent
== kSecDeleteEvent
);
3650 UInt32 tags
[3] = { kSecTypeItemAttr
, kSecServiceItemAttr
, kSecAccountItemAttr
};
3651 SecKeychainAttributeInfo attrInfo
= { 3, tags
, NULL
}; // Count, array of tags, array of formats
3652 SecKeychainAttributeList
*a
= NULL
;
3653 err
= SecKeychainItemCopyAttributesAndData(info
->item
, &attrInfo
, NULL
, &a
, NULL
, NULL
);
3656 relevant
= ((a
->attr
[0].length
== 4 && (!strncasecmp(a
->attr
[0].data
, "ddns", 4) || !strncasecmp(a
->attr
[0].data
, "sndd", 4))) ||
3657 (a
->attr
[1].length
>= 4 && (!strncasecmp(a
->attr
[1].data
, "dns:", 4))));
3658 SecKeychainItemFreeAttributesAndData(a
, NULL
);
3663 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
3665 keychainEvent
== kSecAddEvent
? "kSecAddEvent" :
3666 keychainEvent
== kSecDeleteEvent
? "kSecDeleteEvent" :
3667 keychainEvent
== kSecUpdateEvent
? "kSecUpdateEvent" : "<Unknown>");
3670 SetDomainSecrets(m
);
3672 KQueueUnlock(m
, "KeychainChanged");
3683 mDNSlocal
void PowerChanged(void *refcon
, io_service_t service
, natural_t messageType
, void *messageArgument
)
3685 mDNS
*const m
= (mDNS
*const)refcon
;
3687 (void)service
; // Parameter not used
3690 case kIOMessageCanSystemPowerOff
: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3691 case kIOMessageSystemWillPowerOff
: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3692 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000250
3693 case kIOMessageSystemWillNotPowerOff
: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3694 case kIOMessageCanSystemSleep
: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3695 case kIOMessageSystemWillSleep
: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3696 mDNSCoreMachineSleep(m
, true); mDNSMacOSXNetworkChanged(m
); break; // E0000280
3697 case kIOMessageSystemWillNotSleep
: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3698 case kIOMessageSystemHasPoweredOn
: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3699 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3700 if (m
->SleepState
) mDNSCoreMachineSleep(m
, false);
3701 // Just to be safe, also make sure our interface list is fully up to date, in case we
3702 // haven't yet received the System Configuration Framework "network changed" event that
3703 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3704 mDNSMacOSXNetworkChanged(m
); break; // E0000300
3705 case kIOMessageSystemWillRestart
: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3706 case kIOMessageSystemWillPowerOn
: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3707 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3708 mDNSMacOSXNetworkChanged(m
); mDNSCoreMachineSleep(m
, false); break; // E0000320
3709 default: LogOperation("PowerChanged unknown message %X", messageType
); break;
3711 IOAllowPowerChange(m
->p
->PowerConnection
, (long)messageArgument
);
3712 KQueueUnlock(m
, "Sleep/Wake");
3714 #endif /* NO_IOPOWER */
3716 #if COMPILER_LIKES_PRAGMA_MARK
3718 #pragma mark - Initialization & Teardown
3721 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
3722 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
3723 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
3724 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
3726 // Major version 6 is 10.2.x (Jaguar)
3727 // Major version 7 is 10.3.x (Panther)
3728 // Major version 8 is 10.4.x (Tiger)
3729 mDNSexport
int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring
)
3731 int major
= 0, minor
= 0;
3732 char letter
= 0, prodname
[256]="<Unknown>", prodvers
[256]="<Unknown>", buildver
[256]="<Unknown>";
3733 CFDictionaryRef vers
= _CFCopySystemVersionDictionary();
3736 CFStringRef cfprodname
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductNameKey
);
3737 CFStringRef cfprodvers
= CFDictionaryGetValue(vers
, _kCFSystemVersionProductVersionKey
);
3738 CFStringRef cfbuildver
= CFDictionaryGetValue(vers
, _kCFSystemVersionBuildVersionKey
);
3739 if (cfprodname
) CFStringGetCString(cfprodname
, prodname
, sizeof(prodname
), kCFStringEncodingUTF8
);
3740 if (cfprodvers
) CFStringGetCString(cfprodvers
, prodvers
, sizeof(prodvers
), kCFStringEncodingUTF8
);
3741 if (cfbuildver
) CFStringGetCString(cfbuildver
, buildver
, sizeof(buildver
), kCFStringEncodingUTF8
);
3742 sscanf(buildver
, "%d%c%d", &major
, &letter
, &minor
);
3745 if (!major
) { major
=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
3746 if (HINFO_SWstring
) mDNS_snprintf(HINFO_SWstring
, 256, "%s %s (%s), %s", prodname
, prodvers
, buildver
, mDNSResponderVersionString
);
3750 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3751 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3752 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3753 mDNSlocal mDNSBool
mDNSPlatformInit_CanReceiveUnicast(void)
3756 int s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
3758 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s
, errno
, strerror(errno
));
3761 struct sockaddr_in s5353
;
3762 s5353
.sin_family
= AF_INET
;
3763 s5353
.sin_port
= MulticastDNSPort
.NotAnInteger
;
3764 s5353
.sin_addr
.s_addr
= 0;
3765 err
= bind(s
, (struct sockaddr
*)&s5353
, sizeof(s5353
));
3769 if (err
) LogMsg("No unicast UDP responses");
3770 else debugf("Unicast UDP responses okay");
3774 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3775 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3776 // (.local manually generated via explicit callback)
3777 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3778 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3779 // 4) result above should generate a callback from question in (1). result added to global list
3780 // 5) global list delivered to client via GetSearchDomainList()
3781 // 6) client calls to enumerate domains now go over LocalOnly interface
3782 // (!!!KRS may add outgoing interface in addition)
3784 mDNSlocal mStatus
mDNSPlatformInit_setup(mDNS
*const m
)
3788 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3789 // 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.
3791 for (i
=0; i
<100; i
++)
3793 domainlabel testlabel
;
3795 GetUserSpecifiedLocalHostName(&testlabel
);
3796 if (testlabel
.c
[0]) break;
3800 m
->hostlabel
.c
[0] = 0;
3802 char *HINFO_HWstring
= "Macintosh";
3803 char HINFO_HWstring_buffer
[256];
3804 int get_model
[2] = { CTL_HW
, HW_MODEL
};
3805 size_t len_model
= sizeof(HINFO_HWstring_buffer
);
3806 if (sysctl(get_model
, 2, HINFO_HWstring_buffer
, &len_model
, NULL
, 0) == 0)
3807 HINFO_HWstring
= HINFO_HWstring_buffer
;
3809 char HINFO_SWstring
[256] = "";
3810 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring
) < 7) m
->KnownBugs
|= mDNS_KnownBug_PhantomInterfaces
;
3811 if (mDNSPlatformInit_CanReceiveUnicast()) m
->CanReceiveUnicastOn5353
= mDNStrue
;
3813 mDNSu32 hlen
= mDNSPlatformStrLen(HINFO_HWstring
);
3814 mDNSu32 slen
= mDNSPlatformStrLen(HINFO_SWstring
);
3815 if (hlen
+ slen
< 254)
3817 m
->HIHardware
.c
[0] = hlen
;
3818 m
->HISoftware
.c
[0] = slen
;
3819 mDNSPlatformMemCopy(&m
->HIHardware
.c
[1], HINFO_HWstring
, hlen
);
3820 mDNSPlatformMemCopy(&m
->HISoftware
.c
[1], HINFO_SWstring
, slen
);
3823 m
->p
->permanentsockets
.m
= m
;
3824 m
->p
->permanentsockets
.sktv4
= m
->p
->permanentsockets
.sktv6
= -1;
3825 m
->p
->permanentsockets
.kqsv4
.KQcallback
= m
->p
->permanentsockets
.kqsv6
.KQcallback
= myKQSocketCallBack
;
3826 m
->p
->permanentsockets
.kqsv4
.KQcontext
= m
->p
->permanentsockets
.kqsv6
.KQcontext
= &m
->p
->permanentsockets
;
3827 m
->p
->permanentsockets
.kqsv4
.KQtask
= m
->p
->permanentsockets
.kqsv6
.KQtask
= "UDP packet reception";
3829 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET
);
3831 err
= SetupSocket(&m
->p
->permanentsockets
, MulticastDNSPort
, AF_INET6
);
3834 struct sockaddr_in s4
;
3835 socklen_t n4
= sizeof(s4
);
3836 if (getsockname(m
->p
->permanentsockets
.sktv4
, (struct sockaddr
*)&s4
, &n4
) < 0) LogMsg("getsockname v4 error %d (%s)", errno
, strerror(errno
));
3837 else m
->UnicastPort4
.NotAnInteger
= s4
.sin_port
;
3839 if (m
->p
->permanentsockets
.sktv6
>= 0)
3841 struct sockaddr_in6 s6
;
3842 socklen_t n6
= sizeof(s6
);
3843 if (getsockname(m
->p
->permanentsockets
.sktv6
, (struct sockaddr
*)&s6
, &n6
) < 0) LogMsg("getsockname v6 error %d (%s)", errno
, strerror(errno
));
3844 else m
->UnicastPort6
.NotAnInteger
= s6
.sin6_port
;
3848 m
->p
->InterfaceList
= mDNSNULL
;
3849 m
->p
->userhostlabel
.c
[0] = 0;
3850 m
->p
->usernicelabel
.c
[0] = 0;
3851 m
->p
->NotifyUser
= 0;
3853 m
->AutoTunnelHostAddr
.b
[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
3855 mDNSs32 utc
= mDNSPlatformUTC();
3856 UpdateInterfaceList(m
, utc
);
3857 SetupActiveInterfaces(m
, utc
);
3859 NetworkChangedKey_IPv4
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
);
3860 NetworkChangedKey_IPv6
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
);
3861 NetworkChangedKey_Hostnames
= SCDynamicStoreKeyCreateHostNames(NULL
);
3862 NetworkChangedKey_Computername
= SCDynamicStoreKeyCreateComputerName(NULL
);
3863 NetworkChangedKey_DNS
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetDNS
);
3864 if (!NetworkChangedKey_IPv4
|| !NetworkChangedKey_IPv6
|| !NetworkChangedKey_Hostnames
|| !NetworkChangedKey_Computername
|| !NetworkChangedKey_DNS
)
3865 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr
); }
3867 err
= WatchForNetworkChanges(m
);
3868 if (err
) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err
); return(err
); }
3870 // Explicitly ensure that our Keychain operations utilize the system domain.
3871 #ifndef NO_SECURITYFRAMEWORK
3872 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
3876 SetDomainSecrets(m
);
3880 #ifndef NO_SECURITYFRAMEWORK
3881 err
= SecKeychainAddCallback(KeychainChanged
, kSecAddEventMask
|kSecDeleteEventMask
|kSecUpdateEventMask
, m
);
3882 if (err
) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err
); return(err
); }
3886 m
->p
->PowerConnection
= IORegisterForSystemPower(m
, &m
->p
->PowerPortRef
, PowerChanged
, &m
->p
->PowerNotifier
);
3887 if (!m
->p
->PowerConnection
) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
3888 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
3889 #endif /* NO_IOPOWER */
3891 return(mStatus_NoError
);
3894 mDNSexport mStatus
mDNSPlatformInit(mDNS
*const m
)
3897 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
3900 mStatus result
= mDNSPlatformInit_setup(m
);
3902 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3903 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3904 if (result
== mStatus_NoError
) mDNSCoreInitComplete(m
, mStatus_NoError
);
3908 mDNSexport
void mDNSPlatformClose(mDNS
*const m
)
3910 if (m
->p
->PowerConnection
)
3912 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m
->p
->PowerPortRef
), kCFRunLoopDefaultMode
);
3914 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
3915 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
3916 IODeregisterForSystemPower(&m
->p
->PowerNotifier
);
3917 IOServiceClose ( m
->p
->PowerConnection
);
3918 IONotificationPortDestroy ( m
->p
->PowerPortRef
);
3919 #endif /* NO_IOPOWER */
3920 m
->p
->PowerConnection
= 0;
3925 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m
->p
->StoreRLS
, kCFRunLoopDefaultMode
);
3926 CFRunLoopSourceInvalidate(m
->p
->StoreRLS
);
3927 CFRelease(m
->p
->StoreRLS
);
3928 CFRelease(m
->p
->Store
);
3930 m
->p
->StoreRLS
= NULL
;
3933 mDNSs32 utc
= mDNSPlatformUTC();
3934 MarkAllInterfacesInactive(m
, utc
);
3935 ClearInactiveInterfaces(m
, utc
);
3936 CloseSocketSet(&m
->p
->permanentsockets
);
3938 #if APPLE_OSX_mDNSResponder
3939 if (m
->AutoTunnelHostAddrActive
&& m
->AutoTunnelHostAddr
.b
[0])
3941 m
->AutoTunnelHostAddrActive
= mDNSfalse
;
3942 LogMsg("Removing AutoTunnel address %.16a", &m
->AutoTunnelHostAddr
);
3943 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown
, m
->AutoTunnelHostAddr
.b
);
3945 #endif // APPLE_OSX_mDNSResponder
3948 #if COMPILER_LIKES_PRAGMA_MARK
3950 #pragma mark - General Platform Support Layer functions
3953 mDNSexport mDNSu32
mDNSPlatformRandomSeed(void)
3955 return(mach_absolute_time());
3958 mDNSexport mDNSs32 mDNSPlatformOneSecond
= 1000;
3960 mDNSexport mStatus
mDNSPlatformTimeInit(void)
3962 // Notes: Typical values for mach_timebase_info:
3963 // tbi.numer = 1000 million
3964 // tbi.denom = 33 million
3965 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
3966 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
3967 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
3968 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
3969 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
3971 // Arithmetic notes:
3972 // tbi.denom is at least 1, and not more than 2^32-1.
3973 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
3974 // tbi.denom is at least 1, and not more than 2^32-1.
3975 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
3976 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
3977 // which is unlikely on any current or future Macintosh.
3978 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
3979 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
3980 struct mach_timebase_info tbi
;
3981 kern_return_t result
= mach_timebase_info(&tbi
);
3982 if (result
== KERN_SUCCESS
) clockdivisor
= ((uint64_t)tbi
.denom
* 1000000) / tbi
.numer
;
3986 mDNSexport mDNSs32
mDNSPlatformRawTime(void)
3988 if (clockdivisor
== 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
3990 static uint64_t last_mach_absolute_time
= 0;
3991 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
3992 uint64_t this_mach_absolute_time
= mach_absolute_time();
3993 if ((int64_t)this_mach_absolute_time
- (int64_t)last_mach_absolute_time
< 0)
3995 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time
);
3996 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time
);
3997 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
3998 last_mach_absolute_time
= this_mach_absolute_time
;
3999 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4000 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4001 if (mDNSMacOSXSystemBuildNumber(NULL
) >= 8)
4002 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4003 "This error occurs from time to time, often on newly released hardware, "
4004 "and usually the exact cause is different in each instance.\r\r"
4005 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4006 "and assign it to Radar Component “Kernel” Version “X”.");
4008 last_mach_absolute_time
= this_mach_absolute_time
;
4010 return((mDNSs32
)(this_mach_absolute_time
/ clockdivisor
));
4013 mDNSexport mDNSs32
mDNSPlatformUTC(void)
4018 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4019 mDNSexport
void mDNSPlatformLock (const mDNS
*const m
) { (void)m
; }
4020 mDNSexport
void mDNSPlatformUnlock (const mDNS
*const m
) { (void)m
; }
4021 mDNSexport
void mDNSPlatformStrCopy( void *dst
, const void *src
) { strcpy((char *)dst
, (char *)src
); }
4022 mDNSexport mDNSu32
mDNSPlatformStrLen ( const void *src
) { return(strlen((char*)src
)); }
4023 mDNSexport
void mDNSPlatformMemCopy( void *dst
, const void *src
, mDNSu32 len
) { memcpy(dst
, src
, len
); }
4024 mDNSexport mDNSBool
mDNSPlatformMemSame(const void *dst
, const void *src
, mDNSu32 len
) { return(memcmp(dst
, src
, len
) == 0); }
4025 mDNSexport
void mDNSPlatformMemZero( void *dst
, mDNSu32 len
) { bzero(dst
, len
); }
4026 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4027 mDNSexport
void * mDNSPlatformMemAllocate(mDNSu32 len
) { return(mallocL("mDNSPlatformMemAllocate", len
)); }
4029 mDNSexport
void mDNSPlatformMemFree (void *mem
) { freeL("mDNSPlatformMemFree", mem
); }