]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mDNSMacOSX.c
5cba5efa009f222f02f9b8b22dd6f20732baca68
[apple/mdnsresponder.git] / mDNSMacOSX / mDNSMacOSX.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16
17 Change History (most recent first):
18
19 $Log: mDNSMacOSX.c,v $
20 Revision 1.508 2007/11/02 21:59:37 cheshire
21 Added comment about locking
22
23 Revision 1.507 2007/11/02 20:18:13 cheshire
24 <rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
25
26 Revision 1.506 2007/10/30 20:46:45 cheshire
27 <rdar://problem/5496734> BTMM: Need to retry registrations after failures
28
29 Revision 1.505 2007/10/29 23:55:10 cheshire
30 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
31 Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
32 (and indeed should not, since the result fields will not yet be set up correctly in this case)
33
34 Revision 1.504 2007/10/26 00:50:37 cheshire
35 <rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
36
37 Revision 1.503 2007/10/25 23:11:42 cheshire
38 Ignore IPv6 ULA addresses configured on lo0 loopback interface
39
40 Revision 1.502 2007/10/22 20:07:07 cheshire
41 Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
42 Posix build can share the code (better than just pasting it into mDNSPosix.c)
43
44 Revision 1.501 2007/10/22 19:40:30 cheshire
45 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
46 Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
47
48 Revision 1.500 2007/10/17 22:49:55 cheshire
49 <rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
50
51 Revision 1.499 2007/10/17 19:47:54 cheshire
52 Improved debugging messages
53
54 Revision 1.498 2007/10/17 18:42:06 cheshire
55 Export SetDomainSecrets so its callable from other files
56
57 Revision 1.497 2007/10/16 17:03:07 cheshire
58 <rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
59 Cut SetDomainSecrets stack from 3792 to 1760 bytes
60
61 Revision 1.496 2007/10/04 20:33:05 mcguire
62 <rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
63
64 Revision 1.495 2007/10/02 05:03:38 cheshire
65 Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
66
67 Revision 1.494 2007/09/29 20:40:19 cheshire
68 <rdar://problem/5513378> Crash in ReissueBlockedQuestions
69
70 Revision 1.493 2007/09/29 03:16:45 cheshire
71 <rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
72 When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
73
74 Revision 1.492 2007/09/28 23:58:35 mcguire
75 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
76 Fix locking issue.
77
78 Revision 1.491 2007/09/27 23:28:53 mcguire
79 <rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
80
81 Revision 1.490 2007/09/26 23:01:21 mcguire
82 <rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
83
84 Revision 1.489 2007/09/26 22:58:16 mcguire
85 <rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
86
87 Revision 1.488 2007/09/26 00:32:45 cheshire
88 Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
89
90 Revision 1.487 2007/09/21 17:07:41 mcguire
91 <rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
92
93 Revision 1.486 2007/09/19 23:17:38 cheshire
94 <rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
95
96 Revision 1.485 2007/09/19 21:44:29 cheshire
97 Improved "mDNSKeychainGetSecrets failed" error message
98
99 Revision 1.484 2007/09/18 21:44:55 cheshire
100 <rdar://problem/5469006> Crash in GetAuthInfoForName_internal
101 Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
102
103 Revision 1.483 2007/09/17 22:19:39 mcguire
104 <rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
105 No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
106
107 Revision 1.482 2007/09/14 21:16:03 cheshire
108 <rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
109
110 Revision 1.481 2007/09/14 21:14:56 mcguire
111 <rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
112
113 Revision 1.480 2007/09/13 00:16:42 cheshire
114 <rdar://problem/5468706> Miscellaneous NAT Traversal improvements
115
116 Revision 1.479 2007/09/12 19:22:20 cheshire
117 Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
118 Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
119
120 Revision 1.478 2007/09/07 22:21:45 vazquez
121 <rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
122
123 Revision 1.477 2007/09/07 21:22:30 cheshire
124 <rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
125 Don't log failures binding to port 5351
126
127 Revision 1.476 2007/09/06 20:38:08 cheshire
128 <rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
129
130 Revision 1.475 2007/09/05 02:24:28 cheshire
131 <rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
132 In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
133
134 Revision 1.474 2007/09/04 22:32:58 mcguire
135 <rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
136
137 Revision 1.473 2007/08/31 19:53:15 cheshire
138 <rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
139 If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
140
141 Revision 1.472 2007/08/31 18:49:49 vazquez
142 <rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
143
144 Revision 1.471 2007/08/31 02:05:46 cheshire
145 Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
146
147 Revision 1.470 2007/08/30 22:50:04 mcguire
148 <rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
149
150 Revision 1.469 2007/08/30 19:40:51 cheshire
151 Added syslog messages to report various initialization failures
152
153 Revision 1.468 2007/08/30 00:12:20 cheshire
154 Check error codes and log failures during AutoTunnel setup
155
156 Revision 1.467 2007/08/28 00:33:04 jgraessley
157 <rdar://problem/5423932> Selective compilation options
158
159 Revision 1.466 2007/08/24 23:25:55 cheshire
160 Debugging messages to help track down duplicate items being read from system keychain
161
162 Revision 1.465 2007/08/24 00:39:12 cheshire
163 Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
164
165 Revision 1.464 2007/08/24 00:15:21 cheshire
166 Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
167
168 Revision 1.463 2007/08/23 21:02:35 cheshire
169 SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
170
171 Revision 1.462 2007/08/18 01:02:03 mcguire
172 <rdar://problem/5415593> No Bonjour services are getting registered at boot
173
174 Revision 1.461 2007/08/10 22:25:57 mkrochma
175 <rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
176
177 Revision 1.460 2007/08/08 22:34:59 mcguire
178 <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
179
180 Revision 1.459 2007/08/08 21:07:48 vazquez
181 <rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
182
183 Revision 1.458 2007/08/03 02:18:41 mcguire
184 <rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
185
186 Revision 1.457 2007/08/02 16:48:45 mcguire
187 <rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
188
189 Revision 1.456 2007/08/02 03:28:30 vazquez
190 Make ExternalAddress and err unused to fix build warnings
191
192 Revision 1.455 2007/08/01 03:09:22 cheshire
193 <rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
194
195 Revision 1.454 2007/07/31 23:08:34 mcguire
196 <rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
197
198 Revision 1.453 2007/07/31 19:13:58 mkrochma
199 No longer need to include "btmm" in hostname to avoid name conflicts
200
201 Revision 1.452 2007/07/27 19:30:41 cheshire
202 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
203 to properly reflect tri-state nature of the possible responses
204
205 Revision 1.451 2007/07/25 22:25:45 cheshire
206 <rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
207
208 Revision 1.450 2007/07/25 21:19:10 cheshire
209 <rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
210
211 Revision 1.449 2007/07/25 01:36:09 mcguire
212 <rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
213
214 Revision 1.448 2007/07/24 21:30:09 cheshire
215 Added "AutoTunnel server listening for connections..." diagnostic message
216
217 Revision 1.447 2007/07/24 20:24:18 cheshire
218 Only remove AutoTunnel address if we have created it.
219 Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
220
221 Revision 1.446 2007/07/24 03:00:09 cheshire
222 SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
223
224 Revision 1.445 2007/07/23 20:26:26 cheshire
225 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
226 Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
227 for existence of "Setup:/Network/DynamicDNS" settings
228
229 Revision 1.444 2007/07/21 00:54:49 cheshire
230 <rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
231
232 Revision 1.443 2007/07/20 23:23:11 cheshire
233 Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
234
235 Revision 1.442 2007/07/20 20:23:24 cheshire
236 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
237 Fixed errors reading the Setup:/Network/BackToMyMac preferences
238
239 Revision 1.441 2007/07/20 16:46:45 mcguire
240 <rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
241
242 Revision 1.440 2007/07/20 16:22:07 mcguire
243 <rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
244
245 Revision 1.439 2007/07/20 01:14:56 cheshire
246 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
247 Cleaned up log messages
248
249 Revision 1.438 2007/07/20 00:54:21 cheshire
250 <rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
251
252 Revision 1.437 2007/07/19 22:01:27 cheshire
253 Added "#pragma mark" sections headings to divide code into related function groups
254
255 Revision 1.436 2007/07/18 03:25:25 cheshire
256 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
257 Bring up server-side tunnel on demand, when necessary
258
259 Revision 1.435 2007/07/18 01:05:08 cheshire
260 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
261 Add list of client tunnels so we can automatically reconfigure when local address changes
262
263 Revision 1.434 2007/07/16 20:16:00 vazquez
264 <rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
265 Remove unnecessary LNT init code
266
267 Revision 1.433 2007/07/14 00:36:07 cheshire
268 Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
269
270 Revision 1.432 2007/07/12 23:55:11 cheshire
271 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
272 Don't need two separate DNSQuestion structures when looking up tunnel endpoint
273
274 Revision 1.431 2007/07/12 23:34:48 cheshire
275 Removed 'LogOperation' message to reduce verbosity in syslog
276
277 Revision 1.430 2007/07/12 22:16:46 cheshire
278 Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
279
280 Revision 1.429 2007/07/12 02:51:28 cheshire
281 <rdar://problem/5303834> Automatically configure IPSec policy when resolving services
282
283 Revision 1.428 2007/07/11 23:17:31 cheshire
284 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
285 Improve log message to indicate if we're starting or restarting racoon
286
287 Revision 1.427 2007/07/11 22:50:30 cheshire
288 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
289 Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
290
291 Revision 1.426 2007/07/11 20:40:49 cheshire
292 <rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
293 In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
294
295 Revision 1.425 2007/07/11 19:24:19 cheshire
296 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
297 Configure internal AutoTunnel address
298 (For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
299 assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
300
301 Revision 1.424 2007/07/11 19:00:27 cheshire
302 Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
303
304 Revision 1.423 2007/07/11 03:00:59 cheshire
305 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
306 Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
307
308 Revision 1.422 2007/07/10 01:21:20 cheshire
309 Added (commented out) line for displaying key data for debugging
310
311 Revision 1.421 2007/06/25 20:58:11 cheshire
312 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
313 Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
314
315 Revision 1.420 2007/06/22 21:52:14 cheshire
316 <rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
317
318 Revision 1.419 2007/06/22 21:32:00 cheshire
319 <rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
320
321 Revision 1.418 2007/06/21 16:37:43 jgraessley
322 Bug #: 5280520
323 Reviewed by: Stuart Cheshire
324 Additional changes to get this compiling on the embedded platform.
325
326 Revision 1.417 2007/06/20 01:44:00 cheshire
327 More information in "Network Configuration Change" message
328
329 Revision 1.416 2007/06/20 01:10:12 cheshire
330 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
331
332 Revision 1.415 2007/06/15 19:23:38 cheshire
333 <rdar://problem/5254053> mDNSResponder renames my host without asking
334 Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
335
336 Revision 1.414 2007/05/17 22:00:59 cheshire
337 <rdar://problem/5210966> Lower network change delay from two seconds to one second
338
339 Revision 1.413 2007/05/16 16:43:27 cheshire
340 Only log "bind" failures for our shared mDNS port and for binding to zero
341 -- other attempts to bind to a particular port may legitimately fail
342
343 Revision 1.412 2007/05/15 21:49:21 cheshire
344 Get rid of "#pragma unused"
345
346 Revision 1.411 2007/05/14 23:54:55 cheshire
347 Instead of sprintf, use safer length-limited mDNS_snprintf
348
349 Revision 1.410 2007/05/12 01:05:00 cheshire
350 Updated debugging messages
351
352 Revision 1.409 2007/05/10 22:39:48 cheshire
353 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
354 Only define CountMaskBits for builds with debugging messages
355
356 Revision 1.408 2007/05/10 22:19:00 cheshire
357 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
358 Don't deliver multicast packets for which we can't find an associated InterfaceID
359
360 Revision 1.407 2007/05/10 21:40:28 cheshire
361 Don't log unnecessary "Address already in use" errors when joining multicast groups
362
363 Revision 1.406 2007/05/08 00:56:17 cheshire
364 <rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
365
366 Revision 1.405 2007/05/04 20:21:39 cheshire
367 Improve "connect failed" error message
368
369 Revision 1.404 2007/05/02 19:41:53 cheshire
370 No need to alarm people with "Connection reset by peer" syslog message
371
372 Revision 1.403 2007/04/28 01:31:59 cheshire
373 Improve debugging support for catching memory corruption problems
374
375 Revision 1.402 2007/04/26 22:54:57 cheshire
376 Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
377
378 Revision 1.401 2007/04/26 00:35:16 cheshire
379 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
380 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
381 inside the firewall may give answers where a public one gives none, and vice versa.)
382
383 Revision 1.400 2007/04/24 21:50:27 cheshire
384 Debugging: Show list of changedKeys in NetworkChanged callback
385
386 Revision 1.399 2007/04/23 22:28:47 cheshire
387 Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
388
389 Revision 1.398 2007/04/23 04:57:00 cheshire
390 Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
391
392 Revision 1.397 2007/04/22 06:02:03 cheshire
393 <rdar://problem/4615977> Query should immediately return failure when no server
394
395 Revision 1.396 2007/04/21 21:47:47 cheshire
396 <rdar://problem/4376383> Daemon: Add watchdog timer
397
398 Revision 1.395 2007/04/18 20:58:34 cheshire
399 <rdar://problem/5140339> Domain discovery not working over VPN
400 Needed different code to handle the case where there's only a single search domain
401
402 Revision 1.394 2007/04/17 23:05:50 cheshire
403 <rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
404
405 Revision 1.393 2007/04/17 19:21:29 cheshire
406 <rdar://problem/5140339> Domain discovery not working over VPN
407
408 Revision 1.392 2007/04/17 17:15:09 cheshire
409 Change NO_CFUSERNOTIFICATION code so it still logs to syslog
410
411 Revision 1.391 2007/04/07 01:01:48 cheshire
412 <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
413
414 Revision 1.390 2007/04/06 18:45:02 cheshire
415 Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
416
417 Revision 1.389 2007/04/05 21:39:49 cheshire
418 Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
419
420 Revision 1.388 2007/04/05 21:09:52 cheshire
421 Condense sprawling code
422
423 Revision 1.387 2007/04/05 20:40:37 cheshire
424 Remove unused mDNSPlatformTCPGetFlags()
425
426 Revision 1.386 2007/04/05 19:50:56 cheshire
427 Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
428
429 Revision 1.385 2007/04/03 19:39:19 cheshire
430 Fixed intel byte order bug in mDNSPlatformSetDNSServers()
431
432 Revision 1.384 2007/03/31 01:10:53 cheshire
433 Add debugging
434
435 Revision 1.383 2007/03/31 00:13:48 cheshire
436 Remove LogMsg
437
438 Revision 1.382 2007/03/28 21:01:29 cheshire
439 <rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
440
441 Revision 1.381 2007/03/28 15:56:37 cheshire
442 <rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
443
444 Revision 1.380 2007/03/26 22:54:46 cheshire
445 Fix compile error
446
447 Revision 1.379 2007/03/22 18:31:48 cheshire
448 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
449
450 Revision 1.378 2007/03/22 00:49:20 cheshire
451 <rdar://problem/4848295> Advertise model information via Bonjour
452
453 Revision 1.377 2007/03/21 00:30:05 cheshire
454 <rdar://problem/4789455> Multiple errors in DNameList-related code
455
456 Revision 1.376 2007/03/20 17:07:15 cheshire
457 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
458
459 Revision 1.375 2007/03/20 00:50:57 cheshire
460 <rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
461
462 Revision 1.374 2007/03/06 23:29:50 cheshire
463 <rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
464
465 Revision 1.373 2007/02/28 01:51:20 cheshire
466 Added comment about reverse-order IP address
467
468 Revision 1.372 2007/02/28 01:06:48 cheshire
469 Use %#a format code instead of %d.%d.%d.%d
470
471 Revision 1.371 2007/02/08 21:12:28 cheshire
472 <rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
473
474 Revision 1.370 2007/01/16 22:59:58 cheshire
475 Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
476
477 Revision 1.369 2007/01/10 02:09:32 cheshire
478 Better LogOperation record of keys read from System Keychain
479
480 Revision 1.368 2007/01/10 01:25:31 cheshire
481 Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
482
483 Revision 1.367 2007/01/10 01:22:01 cheshire
484 Make sure c1, c2, c3 are initialized
485
486 Revision 1.366 2007/01/09 22:37:20 cheshire
487 Provide ten-second grace period for deleted keys, to give mDNSResponder
488 time to delete host name before it gives up access to the required key.
489
490 Revision 1.365 2007/01/09 21:09:20 cheshire
491 Need locking in KeychainChanged()
492
493 Revision 1.364 2007/01/09 20:17:04 cheshire
494 mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
495
496 Revision 1.363 2007/01/09 02:41:18 cheshire
497 uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
498 moved it to mDNS_Init() in mDNS.c (core code)
499
500 Revision 1.362 2007/01/08 23:54:01 cheshire
501 Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
502
503 Revision 1.361 2007/01/05 08:30:48 cheshire
504 Trim excessive "$Log" checkin history from before 2006
505 (checkin history still available via "cvs log ..." of course)
506
507 Revision 1.360 2007/01/04 00:12:24 cheshire
508 <rdar://problem/4742742> Read *all* DNS keys from keychain,
509 not just key for the system-wide default registration domain
510
511 Revision 1.359 2006/12/22 21:14:37 cheshire
512 Added comment explaining why we allow both "ddns" and "sndd" as valid item types
513 The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
514
515 Revision 1.358 2006/12/22 20:59:50 cheshire
516 <rdar://problem/4742742> Read *all* DNS keys from keychain,
517 not just key for the system-wide default registration domain
518
519 Revision 1.357 2006/12/21 00:09:45 cheshire
520 Use mDNSPlatformMemZero instead of bzero
521
522 Revision 1.356 2006/12/20 23:15:53 mkrochma
523 Fix the private domain list code so that it actually works
524
525 Revision 1.355 2006/12/20 23:04:36 mkrochma
526 Fix crash when adding private domain list to Dynamic Store
527
528 Revision 1.354 2006/12/19 22:43:55 cheshire
529 Fix compiler warnings
530
531 Revision 1.353 2006/12/14 22:08:29 cheshire
532 Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
533 to release data allocated by SecKeychainItemCopyAttributesAndData()
534
535 Revision 1.352 2006/12/14 02:33:26 cheshire
536 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
537
538 Revision 1.351 2006/11/28 21:37:51 mkrochma
539 Tweak where the private DNS data is written
540
541 Revision 1.350 2006/11/28 07:55:02 herscher
542 <rdar://problem/4742743> dnsextd has a slow memory leak
543
544 Revision 1.349 2006/11/28 07:45:58 herscher
545 <rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
546
547 Revision 1.348 2006/11/16 21:47:20 mkrochma
548 <rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
549
550 Revision 1.347 2006/11/10 00:54:16 cheshire
551 <rdar://problem/4816598> Changing case of Computer Name doesn't work
552
553 Revision 1.346 2006/10/31 02:34:58 cheshire
554 <rdar://problem/4692130> Stop creating HINFO records
555
556 Revision 1.345 2006/09/21 20:04:38 mkrochma
557 Accidently changed function name while checking in previous fix
558
559 Revision 1.344 2006/09/21 19:04:13 mkrochma
560 <rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
561
562 Revision 1.343 2006/09/15 21:20:16 cheshire
563 Remove uDNS_info substructure from mDNS_struct
564
565 Revision 1.342 2006/08/16 00:31:50 mkrochma
566 <rdar://problem/4386944> Get rid of NotAnInteger references
567
568 Revision 1.341 2006/08/14 23:24:40 cheshire
569 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
570
571 Revision 1.340 2006/07/29 19:11:13 mkrochma
572 Change GetUserSpecifiedDDNSConfig LogMsg to debugf
573
574 Revision 1.339 2006/07/27 03:24:35 cheshire
575 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
576 Further refinement: Declare KQueueEntry parameter "const"
577
578 Revision 1.338 2006/07/27 02:59:25 cheshire
579 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
580 Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
581 after releasing BigMutex, in case actions it took have resulted in new work for the
582 kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
583 add new active interfaces to its list, and consequently schedule queries to be sent).
584
585 Revision 1.337 2006/07/22 06:11:37 cheshire
586 <rdar://problem/4049048> Convert mDNSResponder to use kqueue
587
588 Revision 1.336 2006/07/15 02:01:32 cheshire
589 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
590 Fix broken "empty string" browsing
591
592 Revision 1.335 2006/07/14 05:25:11 cheshire
593 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
594 Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
595
596 Revision 1.334 2006/07/05 23:42:00 cheshire
597 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
598
599 Revision 1.333 2006/06/29 05:33:30 cheshire
600 <rdar://problem/4607043> mDNSResponder conditional compilation options
601
602 Revision 1.332 2006/06/28 09:10:36 cheshire
603 Extra debugging messages
604
605 Revision 1.331 2006/06/21 22:29:42 cheshire
606 Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
607
608 Revision 1.330 2006/06/20 23:06:00 cheshire
609 Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
610
611 Revision 1.329 2006/06/08 23:22:33 cheshire
612 Comment changes
613
614 Revision 1.328 2006/03/19 03:27:49 cheshire
615 <rdar://problem/4118624> Suppress "interface flapping" logic for loopback
616
617 Revision 1.327 2006/03/19 02:00:09 cheshire
618 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
619
620 Revision 1.326 2006/03/08 22:42:23 cheshire
621 Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
622
623 Revision 1.325 2006/01/10 00:39:17 cheshire
624 Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
625
626 Revision 1.324 2006/01/09 19:28:59 cheshire
627 <rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
628
629 Revision 1.323 2006/01/05 21:45:27 cheshire
630 <rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
631
632 Revision 1.322 2006/01/05 21:41:50 cheshire
633 <rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
634
635 Revision 1.321 2006/01/05 21:35:06 cheshire
636 Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
637
638 */
639
640 // ***************************************************************************
641 // mDNSMacOSX.c:
642 // Supporting routines to run mDNS on a CFRunLoop platform
643 // ***************************************************************************
644
645 // For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
646 // including ones that mDNSResponder chooses not to use.
647 #define LIST_ALL_INTERFACES 0
648
649 // For enabling AAAA records over IPv4. Setting this to 0 sends only
650 // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
651 // AAAA and A records over both IPv4 and IPv6.
652 #define AAAA_OVER_V4 1
653
654 // In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
655 // IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
656 // which means there's a good chance that most or all the other devices on that network should also have IPv4.
657 // By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
658 // At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
659 // so were willing to make that sacrifice.
660 // In Mac OS X 10.5, in 2007, two things have changed:
661 // 1. IPv6-only devices are starting to become more common, so we can't ignore them.
662 // 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
663
664 #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
665
666 #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
667 #include "DNSCommon.h"
668 #include "uDNS.h"
669 #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
670 #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
671 #include "PlatformCommon.h"
672
673
674 #include <stdio.h>
675 #include <stdarg.h> // For va_list support
676 #include <net/if.h>
677 #include <net/if_types.h> // For IFT_ETHER
678 #include <net/if_dl.h>
679 #include <sys/uio.h>
680 #include <sys/param.h>
681 #include <sys/socket.h>
682 #include <sys/sysctl.h>
683 #include <sys/event.h>
684 #include <fcntl.h>
685 #include <sys/ioctl.h>
686 #include <time.h> // platform support for UTC time
687 #include <arpa/inet.h> // for inet_aton
688 #include <pthread.h>
689
690 #include <netinet/in.h> // For IP_RECVTTL
691 #ifndef IP_RECVTTL
692 #define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
693 #endif
694
695 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
696 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
697 #include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
698 #include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
699
700 #if TARGET_OS_EMBEDDED
701 #define NO_SECURITYFRAMEWORK 1
702 #endif
703
704 #ifndef NO_SECURITYFRAMEWORK
705 #include <Security/SecureTransport.h>
706 #include <Security/Security.h>
707 #endif /* NO_SECURITYFRAMEWORK */
708
709 #include <DebugServices.h>
710 #include "dnsinfo.h"
711
712 // Code contributed by Dave Heller:
713 // Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
714 // work on Mac OS X 10.1, which does not have the getifaddrs call.
715 #define RUN_ON_PUMA_WITHOUT_IFADDRS 0
716 #if RUN_ON_PUMA_WITHOUT_IFADDRS
717 #include "mDNSMacOSXPuma.c"
718 #else
719 #include <ifaddrs.h>
720 #endif
721
722 #include <IOKit/IOKitLib.h>
723 #include <IOKit/IOMessage.h>
724 #include <mach/mach_error.h>
725 #include <mach/mach_port.h>
726 #include <mach/mach_time.h>
727 #include "helper.h"
728
729 #define kInterfaceSpecificOption "interface="
730
731 // ***************************************************************************
732 // Globals
733
734 #if COMPILER_LIKES_PRAGMA_MARK
735 #pragma mark - Globals
736 #endif
737
738 static mDNSu32 clockdivisor = 0;
739
740 mDNSexport int KQueueFD;
741
742 #ifndef NO_SECURITYFRAMEWORK
743 static CFArrayRef ServerCerts;
744 #endif /* NO_SECURITYFRAMEWORK */
745
746 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
747
748 CFStringRef NetworkChangedKey_IPv4;
749 CFStringRef NetworkChangedKey_IPv6;
750 CFStringRef NetworkChangedKey_Hostnames;
751 CFStringRef NetworkChangedKey_Computername;
752 CFStringRef NetworkChangedKey_DNS;
753 CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
754 CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
755
756 // ***************************************************************************
757 // Functions
758
759 #if COMPILER_LIKES_PRAGMA_MARK
760 #pragma mark -
761 #pragma mark - Utility Functions
762 #endif
763
764 // We only attempt to send and receive multicast packets on interfaces that are
765 // (a) flagged as multicast-capable
766 // (b) *not* flagged as point-to-point (e.g. modem)
767 // Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
768 // to run up the user's bill sending multicast traffic over a link where there's only a single device at the
769 // other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
770 #define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
771
772 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
773 {
774 static int notifyCount = 0;
775 if (notifyCount) return;
776
777 // If we display our alert early in the boot process, then it vanishes once the desktop appears.
778 // To avoid this, we don't try to display alerts in the first three minutes after boot.
779 if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
780
781 // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
782 #if !ForceAlerts
783 {
784 // Determine if we're at Apple (17.*.*.*)
785 extern mDNS mDNSStorage;
786 NetworkInterfaceInfoOSX *i;
787 for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
788 if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
789 break;
790 if (!i) return; // If not at Apple, don't show the alert
791 }
792 #endif
793
794 LogMsg("%s", title);
795 LogMsg("%s", msg);
796 // Display a notification to the user
797 notifyCount++;
798
799 #ifndef NO_CFUSERNOTIFICATION
800 static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
801 CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
802 CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
803 CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
804 CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
805 CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
806 #endif /* NO_CFUSERNOTIFICATION */
807 }
808
809 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
810 {
811 static struct ifaddrs *ifa = NULL;
812
813 if (refresh && ifa)
814 {
815 freeifaddrs(ifa);
816 ifa = NULL;
817 }
818
819 if (ifa == NULL) getifaddrs(&ifa);
820
821 return ifa;
822 }
823
824 mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
825 {
826 NetworkInterfaceInfoOSX *i;
827 for (i = m->p->InterfaceList; i; i = i->next)
828 if (i->Exists && !strcmp(i->ifa_name, ifname) &&
829 ((AAAA_OVER_V4 ) ||
830 (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
831 (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
832 return(NULL);
833 }
834
835 mDNSlocal int myIfIndexToName(u_short index, char *name)
836 {
837 struct ifaddrs *ifa;
838 for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
839 if (ifa->ifa_addr->sa_family == AF_LINK)
840 if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
841 { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
842 return -1;
843 }
844
845 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
846 {
847 NetworkInterfaceInfoOSX *i;
848 if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
849 if (index == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
850
851 // Don't get tricked by inactive interfaces with no InterfaceID set
852 for (i = m->p->InterfaceList; i; i = i->next)
853 if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
854
855 // Not found. Make sure our interface list is up to date, then try again.
856 LogOperation("InterfaceID for interface index %d not found; Updating interface list", index);
857 mDNSMacOSXNetworkChanged(m);
858 for (i = m->p->InterfaceList; i; i = i->next)
859 if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
860
861 return(mDNSNULL);
862 }
863
864 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
865 {
866 NetworkInterfaceInfoOSX *i;
867 if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
868 if (id == mDNSInterface_Any ) return(0);
869
870 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
871 for (i = m->p->InterfaceList; i; i = i->next)
872 if ((mDNSInterfaceID)i == id) return(i->scope_id);
873
874 // Not found. Make sure our interface list is up to date, then try again.
875 LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id);
876 mDNSMacOSXNetworkChanged(m);
877 for (i = m->p->InterfaceList; i; i = i->next)
878 if ((mDNSInterfaceID)i == id) return(i->scope_id);
879
880 return(0);
881 }
882
883 #if COMPILER_LIKES_PRAGMA_MARK
884 #pragma mark -
885 #pragma mark - UDP & TCP send & receive
886 #endif
887
888 mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
889 {
890 mDNSBool result = mDNSfalse;
891 SCNetworkConnectionFlags flags;
892 SCNetworkReachabilityRef ReachRef = NULL;
893
894 ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
895 if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
896 if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
897 result = flags & kSCNetworkFlagsConnectionRequired;
898
899 end:
900 if (ReachRef) CFRelease(ReachRef);
901 return result;
902 }
903
904 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
905 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
906 // OR send via our primary v4 unicast socket
907 mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
908 mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
909 {
910 // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
911 // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
912 // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
913 NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID;
914 char *ifa_name = info ? info->ifa_name : "unicast";
915 struct sockaddr_storage to;
916 int s = -1, err;
917 mStatus result = mStatus_NoError;
918
919 // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
920 // anonymous socket created for this purpose, so that we'll receive the response.
921 // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
922 if (InterfaceID && !mDNSAddrIsDNSMulticast(dst))
923 {
924 const DNSMessage *const m = (DNSMessage *)msg;
925 if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
926 LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
927 }
928
929 if (dst->type == mDNSAddrType_IPv4)
930 {
931 struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
932 sin_to->sin_len = sizeof(*sin_to);
933 sin_to->sin_family = AF_INET;
934 sin_to->sin_port = dstPort.NotAnInteger;
935 sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
936 s = m->p->permanentsockets.sktv4;
937 if (info) // Specify outgoing interface
938 {
939 if (!mDNSAddrIsDNSMulticast(dst))
940 {
941 #ifdef IP_FORCE_OUT_IFP
942 setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, ifa_name, strlen(ifa_name) + 1);
943 #else
944 {
945 static int displayed = 0;
946 if (!displayed)
947 {
948 displayed = 1;
949 LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
950 }
951 }
952 #endif
953 }
954 else
955 {
956 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
957 if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
958 }
959 }
960 }
961 else if (dst->type == mDNSAddrType_IPv6)
962 {
963 struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
964 sin6_to->sin6_len = sizeof(*sin6_to);
965 sin6_to->sin6_family = AF_INET6;
966 sin6_to->sin6_port = dstPort.NotAnInteger;
967 sin6_to->sin6_flowinfo = 0;
968 sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
969 sin6_to->sin6_scope_id = info ? info->scope_id : 0;
970 s = m->p->permanentsockets.sktv6;
971 if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
972 {
973 err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
974 if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno));
975 }
976 }
977 else
978 {
979 LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
980 #if ForceAlerts
981 *(long*)0 = 0;
982 #endif
983 return mStatus_BadParamErr;
984 }
985
986 // Don't send if it would cause dial-on-demand connection initiation.
987 // As an optimization, don't bother consulting reachability API / routing
988 // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
989 if (!info && !mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
990 {
991 debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
992 return mStatus_NoError;
993 }
994
995 if (s >= 0)
996 verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
997 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
998 else
999 verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
1000 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
1001
1002 // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
1003 // If we don't have the corresponding type of socket available, then return mStatus_Invalid
1004 if (s < 0) return(mStatus_Invalid);
1005
1006 err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
1007 if (err < 0)
1008 {
1009 static int MessageCount = 0;
1010 // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
1011 if (!mDNSAddressIsAllDNSLinkGroup(dst))
1012 if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
1013 // Don't report EHOSTUNREACH in the first three minutes after boot
1014 // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
1015 // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
1016 if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
1017 // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
1018 if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
1019 if (MessageCount < 1000)
1020 {
1021 MessageCount++;
1022 LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
1023 InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
1024 }
1025 result = mStatus_UnknownErr;
1026 }
1027
1028 #ifdef IP_FORCE_OUT_IFP
1029 if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
1030 setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1);
1031 #endif
1032
1033 return(result);
1034 }
1035
1036 mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
1037 struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
1038 {
1039 static unsigned int numLogMessages = 0;
1040 struct iovec databuffers = { (char *)buffer, max };
1041 struct msghdr msg;
1042 ssize_t n;
1043 struct cmsghdr *cmPtr;
1044 char ancillary[1024];
1045
1046 *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
1047
1048 // Set up the message
1049 msg.msg_name = (caddr_t)from;
1050 msg.msg_namelen = *fromlen;
1051 msg.msg_iov = &databuffers;
1052 msg.msg_iovlen = 1;
1053 msg.msg_control = (caddr_t)&ancillary;
1054 msg.msg_controllen = sizeof(ancillary);
1055 msg.msg_flags = 0;
1056
1057 // Receive the data
1058 n = recvmsg(s, &msg, 0);
1059 if (n<0)
1060 {
1061 if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
1062 return(-1);
1063 }
1064 if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
1065 {
1066 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
1067 s, n, msg.msg_controllen, sizeof(struct cmsghdr));
1068 return(-1);
1069 }
1070 if (msg.msg_flags & MSG_CTRUNC)
1071 {
1072 if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
1073 return(-1);
1074 }
1075
1076 *fromlen = msg.msg_namelen;
1077
1078 // Parse each option out of the ancillary data.
1079 for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
1080 {
1081 // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
1082 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
1083 {
1084 dstaddr->type = mDNSAddrType_IPv4;
1085 dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
1086 }
1087 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
1088 {
1089 struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
1090 if (sdl->sdl_nlen < IF_NAMESIZE)
1091 {
1092 mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1093 ifname[sdl->sdl_nlen] = 0;
1094 // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
1095 }
1096 }
1097 if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
1098 *ttl = *(u_char*)CMSG_DATA(cmPtr);
1099 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
1100 {
1101 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
1102 dstaddr->type = mDNSAddrType_IPv6;
1103 dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
1104 myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
1105 }
1106 if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
1107 *ttl = *(int*)CMSG_DATA(cmPtr);
1108 }
1109
1110 return(n);
1111 }
1112
1113 mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
1114 {
1115 const KQSocketSet *const ss = (const KQSocketSet *)context;
1116 mDNS *const m = ss->m;
1117 int err, count = 0;
1118
1119 if (filter != EVFILT_READ)
1120 LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
1121
1122 if (s1 != ss->sktv4 && s1 != ss->sktv6)
1123 {
1124 LogMsg("myKQSocketCallBack: native socket %d", s1);
1125 LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
1126 LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
1127 }
1128
1129 while (1)
1130 {
1131 mDNSAddr senderAddr, destAddr;
1132 mDNSIPPort senderPort, destPort = MulticastDNSPort;
1133 struct sockaddr_storage from;
1134 size_t fromlen = sizeof(from);
1135 char packetifname[IF_NAMESIZE] = "";
1136 mDNSu8 ttl;
1137 err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
1138 if (err < 0) break;
1139
1140 count++;
1141 if (from.ss_family == AF_INET)
1142 {
1143 struct sockaddr_in *sin = (struct sockaddr_in*)&from;
1144 senderAddr.type = mDNSAddrType_IPv4;
1145 senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
1146 senderPort.NotAnInteger = sin->sin_port;
1147 //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1148 }
1149 else if (from.ss_family == AF_INET6)
1150 {
1151 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
1152 senderAddr.type = mDNSAddrType_IPv6;
1153 senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
1154 senderPort.NotAnInteger = sin6->sin6_port;
1155 //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
1156 }
1157 else
1158 {
1159 LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
1160 return;
1161 }
1162
1163 // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
1164 mDNSInterfaceID InterfaceID = mDNSNULL;
1165 NetworkInterfaceInfo *intf = m->HostInterfaces;
1166 while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
1167 // When going to sleep we deregister all our interfaces, but if the machine
1168 // takes a few seconds to sleep we may continue to receive multicasts
1169 // during that time, which would confuse mDNSCoreReceive, because as far
1170 // as it's concerned, we should have no active interfaces any more.
1171 // Hence we ignore multicasts for which we can find no matching InterfaceID.
1172 if (intf) InterfaceID = intf->InterfaceID;
1173 else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
1174
1175 // LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
1176 // &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
1177
1178 mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
1179 }
1180
1181 if (err < 0 && (errno != EWOULDBLOCK || count == 0))
1182 {
1183 // Something is busted here.
1184 // kqueue says there is a packet, but myrecvfrom says there is not.
1185 // Try calling select() to get another opinion.
1186 // Find out about other socket parameter that can help understand why select() says the socket is ready for read
1187 // All of this is racy, as data may have arrived after the call to select()
1188 static unsigned int numLogMessages = 0;
1189 int save_errno = errno;
1190 int so_error = -1;
1191 int so_nread = -1;
1192 int fionread = -1;
1193 socklen_t solen = sizeof(int);
1194 fd_set readfds;
1195 struct timeval timeout;
1196 int selectresult;
1197 FD_ZERO(&readfds);
1198 FD_SET(s1, &readfds);
1199 timeout.tv_sec = 0;
1200 timeout.tv_usec = 0;
1201 selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
1202 if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
1203 LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
1204 if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
1205 LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
1206 if (ioctl(s1, FIONREAD, &fionread) == -1)
1207 LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
1208 if (numLogMessages++ < 100)
1209 LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
1210 s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
1211 if (numLogMessages > 5)
1212 NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
1213 "Congratulations, you've reproduced an elusive bug.\r"
1214 "Please contact the current assignee of <rdar://problem/3375328>.\r"
1215 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1216 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1217
1218 sleep(1); // After logging this error, rate limit so we don't flood syslog
1219 }
1220 }
1221
1222 // TCP socket support
1223
1224 struct TCPSocket_struct
1225 {
1226 TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
1227 TCPConnectionCallback callback;
1228 int fd;
1229 KQueueEntry kqEntry;
1230 #ifndef NO_SECURITYFRAMEWORK
1231 SSLContextRef tlsContext;
1232 #endif /* NO_SECURITYFRAMEWORK */
1233 void *context;
1234 mDNSBool setup;
1235 mDNSBool handshakecomplete;
1236 mDNSBool connected;
1237 };
1238
1239 #ifndef NO_SECURITYFRAMEWORK
1240
1241 mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
1242 {
1243 int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1244 if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1245 if (ret >= 0) { *dataLength = ret; return(noErr); }
1246 *dataLength = 0;
1247 if (errno == EAGAIN ) return(errSSLWouldBlock);
1248 if (errno == ENOENT ) return(errSSLClosedGraceful);
1249 if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
1250 LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno));
1251 return(errSSLClosedAbort);
1252 }
1253
1254 mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
1255 {
1256 int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
1257 if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
1258 if (ret > 0) { *dataLength = ret; return(noErr); }
1259 *dataLength = 0;
1260 if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
1261 if ( errno == EAGAIN ) return(errSSLWouldBlock);
1262 if ( errno == ECONNRESET) return(errSSLClosedAbort);
1263 LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno));
1264 return(errSSLClosedAbort);
1265 }
1266
1267 mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
1268 {
1269 mStatus err = SSLNewContext(server, &sock->tlsContext);
1270 if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
1271
1272 err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
1273 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
1274
1275 err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
1276 if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
1277
1278 return(err);
1279 }
1280
1281 mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
1282 {
1283 static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
1284 const domainname *d1 = mDNSNULL; // TLD
1285 const domainname *d2 = mDNSNULL; // SLD
1286 const domainname *d3 = mDNSNULL;
1287 while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
1288 return(d3 && SameDomainName(d3, mmc));
1289 }
1290
1291 #endif /* NO_SECURITYFRAMEWORK */
1292
1293 mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
1294 {
1295 TCPSocket *sock = context;
1296 mStatus err = mStatus_NoError;
1297
1298 //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
1299 //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
1300 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
1301 if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
1302
1303 if (sock->flags & kTCPSocketFlags_UseTLS)
1304 {
1305 #ifndef NO_SECURITYFRAMEWORK
1306 if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
1307 if (!sock->handshakecomplete)
1308 {
1309 //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
1310 err = SSLHandshake(sock->tlsContext);
1311 //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
1312 if (!err) sock->handshakecomplete = mDNStrue;
1313 else if (err == errSSLWouldBlock) return;
1314 else { LogMsg("KQ SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
1315 }
1316 #else
1317 err = mStatus_UnsupportedErr;
1318 #endif /* NO_SECURITYFRAMEWORK */
1319 }
1320
1321 mDNSBool connect = !sock->connected;
1322 sock->connected = mDNStrue;
1323 sock->callback(sock, sock->context, connect, err);
1324 // NOTE: the callback may call CloseConnection here, which frees the context structure!
1325 }
1326
1327 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
1328 {
1329 struct kevent new_event;
1330 EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
1331 return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
1332 }
1333
1334 mDNSexport void KQueueLock(mDNS *const m)
1335 {
1336 pthread_mutex_lock(&m->p->BigMutex);
1337 m->p->BigMutexStartTime = mDNSPlatformRawTime();
1338 }
1339
1340 mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
1341 {
1342 mDNSs32 end = mDNSPlatformRawTime();
1343 (void)task;
1344 if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
1345 LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
1346
1347 pthread_mutex_unlock(&m->p->BigMutex);
1348
1349 char wake = 1;
1350 if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
1351 LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno));
1352 }
1353
1354 mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
1355 {
1356 (void) m;
1357
1358 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
1359 if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
1360
1361 mDNSPlatformMemZero(sock, sizeof(TCPSocket));
1362 sock->callback = mDNSNULL;
1363 sock->fd = socket(AF_INET, SOCK_STREAM, 0);
1364 sock->kqEntry.KQcallback= tcpKQSocketCallback;
1365 sock->kqEntry.KQcontext = sock;
1366 sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
1367 sock->flags = flags;
1368 sock->context = mDNSNULL;
1369 sock->setup = mDNSfalse;
1370 sock->handshakecomplete = mDNSfalse;
1371 sock->connected = mDNSfalse;
1372
1373 if (sock->fd == -1)
1374 {
1375 LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
1376 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1377 return(mDNSNULL);
1378 }
1379
1380 // Bind it
1381 struct sockaddr_in addr;
1382 memset(&addr, 0, sizeof(addr));
1383 addr.sin_family = AF_INET;
1384 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1385 addr.sin_port = port->NotAnInteger;
1386 if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
1387 { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
1388
1389 // Receive interface identifiers
1390 const int on = 1; // "on" for setsockopt
1391 if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
1392 { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
1393
1394 memset(&addr, 0, sizeof(addr));
1395 socklen_t len = sizeof(addr);
1396 if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
1397 { LogMsg("getsockname - %s", strerror(errno)); goto error; }
1398
1399 port->NotAnInteger = addr.sin_port;
1400 return sock;
1401
1402 error:
1403 close(sock->fd);
1404 freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
1405 return(mDNSNULL);
1406 }
1407
1408 mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
1409 TCPConnectionCallback callback, void *context)
1410 {
1411 struct sockaddr_in saddr;
1412 mStatus err = mStatus_NoError;
1413
1414 sock->callback = callback;
1415 sock->context = context;
1416 sock->setup = mDNSfalse;
1417 sock->handshakecomplete = mDNSfalse;
1418 sock->connected = mDNSfalse;
1419
1420 (void) InterfaceID; //!!!KRS use this if non-zero!!!
1421
1422 if (dst->type != mDNSAddrType_IPv4)
1423 {
1424 LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
1425 return mStatus_UnknownErr;
1426 }
1427
1428 mDNSPlatformMemZero(&saddr, sizeof(saddr));
1429 saddr.sin_family = AF_INET;
1430 saddr.sin_port = dstport.NotAnInteger;
1431 saddr.sin_len = sizeof(saddr);
1432 saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
1433
1434 // Don't send if it would cause dial-on-demand connection initiation.
1435 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
1436 {
1437 debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
1438 return mStatus_UnknownErr;
1439 }
1440
1441 sock->kqEntry.KQcallback = tcpKQSocketCallback;
1442 sock->kqEntry.KQcontext = sock;
1443 sock->kqEntry.KQtask = "Outgoing TCP";
1444
1445 // Watch for connect complete (write is ready)
1446 // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
1447 if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
1448 {
1449 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1450 close(sock->fd);
1451 return errno;
1452 }
1453
1454 // Watch for incoming data
1455 if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
1456 {
1457 LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
1458 close(sock->fd); // Closing the descriptor removes all filters from the kqueue
1459 return errno;
1460 }
1461
1462 if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
1463 {
1464 LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
1465 return mStatus_UnknownErr;
1466 }
1467
1468 // initiate connection wth peer
1469 if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
1470 {
1471 if (errno == EINPROGRESS) return mStatus_ConnPending;
1472 LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock->fd, errno, strerror(errno));
1473 close(sock->fd);
1474 return mStatus_ConnFailed;
1475 }
1476
1477 LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
1478 // kQueue should notify us, but this LogMsg is to help track down if it doesn't
1479 return err;
1480 }
1481
1482 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
1483 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
1484 {
1485 mStatus err = mStatus_NoError;
1486
1487 TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
1488 if (!sock) return(mDNSNULL);
1489
1490 memset(sock, 0, sizeof(*sock));
1491 sock->fd = fd;
1492 sock->flags = flags;
1493
1494 if (flags & kTCPSocketFlags_UseTLS)
1495 {
1496 #ifndef NO_SECURITYFRAMEWORK
1497 if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
1498
1499 err = tlsSetupSock(sock, mDNStrue);
1500 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
1501
1502 err = SSLSetCertificate(sock->tlsContext, ServerCerts);
1503 if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
1504 #else
1505 err = mStatus_UnsupportedErr;
1506 #endif /* NO_SECURITYFRAMEWORK */
1507 }
1508 #ifndef NO_SECURITYFRAMEWORK
1509 exit:
1510 #endif
1511
1512 if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
1513 return(sock);
1514 }
1515
1516 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
1517 {
1518 if (sock)
1519 {
1520 #ifndef NO_SECURITYFRAMEWORK
1521 if (sock->tlsContext)
1522 {
1523 SSLClose(sock->tlsContext);
1524 SSLDisposeContext(sock->tlsContext);
1525 sock->tlsContext = NULL;
1526 }
1527 #endif /* NO_SECURITYFRAMEWORK */
1528 if (sock->fd != -1)
1529 {
1530 shutdown(sock->fd, 2);
1531 close(sock->fd);
1532 sock->fd = -1;
1533 }
1534
1535 freeL("mDNSPlatformTCPCloseConnection", sock);
1536 }
1537 }
1538
1539 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
1540 {
1541 long nread = 0;
1542 *closed = mDNSfalse;
1543
1544 if (sock->flags & kTCPSocketFlags_UseTLS)
1545 {
1546 #ifndef NO_SECURITYFRAMEWORK
1547 if (!sock->handshakecomplete)
1548 {
1549 //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
1550 mStatus err = SSLHandshake(sock->tlsContext);
1551 //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
1552 if (!err) sock->handshakecomplete = mDNStrue;
1553 else if (err == errSSLWouldBlock) return(0);
1554 else { LogMsg("Read SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
1555 }
1556
1557 //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
1558 mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
1559 //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
1560 if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
1561 else if (err && err != errSSLWouldBlock)
1562 { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
1563 #else
1564 nread = -1;
1565 *closed = mDNStrue;
1566 #endif /* NO_SECURITYFRAMEWORK */
1567 }
1568 else
1569 {
1570 static int CLOSEDcount = 0;
1571 static int EAGAINcount = 0;
1572 nread = recv(sock->fd, buf, buflen, 0);
1573
1574 if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
1575 else if (nread == 0)
1576 {
1577 *closed = mDNStrue;
1578 if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
1579 }
1580 // else nread is negative -- see what kind of error we got
1581 else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
1582 else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; }
1583 else // errno is EAGAIN (EWOULDBLOCK) -- no data available
1584 {
1585 nread = 0;
1586 if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
1587 }
1588 }
1589
1590 return nread;
1591 }
1592
1593 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
1594 {
1595 int nsent;
1596
1597 if (sock->flags & kTCPSocketFlags_UseTLS)
1598 {
1599 #ifndef NO_SECURITYFRAMEWORK
1600 size_t processed;
1601 mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
1602
1603 if (!err) nsent = (int) processed;
1604 else if (err == errSSLWouldBlock) nsent = 0;
1605 else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
1606 #else
1607 nsent = -1;
1608 #endif /* NO_SECURITYFRAMEWORK */
1609 }
1610 else
1611 {
1612 nsent = send(sock->fd, msg, len, 0);
1613 if (nsent < 0)
1614 {
1615 if (errno == EAGAIN) nsent = 0;
1616 else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
1617 }
1618 }
1619
1620 return nsent;
1621 }
1622
1623 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
1624 {
1625 return sock->fd;
1626 }
1627
1628 // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
1629 // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
1630 mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family)
1631 {
1632 const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
1633 int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
1634 KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
1635 const int on = 1;
1636 const int twofivefive = 255;
1637 mStatus err = mStatus_NoError;
1638 char *errstr = mDNSNULL;
1639
1640 int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
1641 if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
1642
1643 // ... with a shared UDP port, if it's for multicast receiving
1644 if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
1645 if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
1646
1647 if (sa_family == AF_INET)
1648 {
1649 // We want to receive destination addresses
1650 err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
1651 if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
1652
1653 // We want to receive interface identifiers
1654 err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
1655 if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
1656
1657 // We want to receive packet TTL value so we can check it
1658 err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
1659 // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
1660
1661 // Send unicast packets with TTL 255
1662 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
1663 if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
1664
1665 // And multicast packets with TTL 255 too
1666 err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
1667 if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
1668
1669 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1670 err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
1671 if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
1672
1673 // And start listening for packets
1674 struct sockaddr_in listening_sockaddr;
1675 listening_sockaddr.sin_family = AF_INET;
1676 listening_sockaddr.sin_port = port.NotAnInteger;
1677 listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket
1678 err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
1679 if (err) { errstr = "bind"; goto fail; }
1680 }
1681 else if (sa_family == AF_INET6)
1682 {
1683 // We want to receive destination addresses and receive interface identifiers
1684 err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
1685 if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
1686
1687 // We want to receive packet hop count value so we can check it
1688 err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
1689 if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
1690
1691 // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
1692 // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
1693 err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1694 if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
1695
1696 // Send unicast packets with TTL 255
1697 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
1698 if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
1699
1700 // And multicast packets with TTL 255 too
1701 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
1702 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
1703
1704 // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
1705 #ifdef IPV6_TCLASS
1706 // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
1707 int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it)
1708 err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
1709 if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
1710 #endif
1711
1712 // Want to receive our own packets
1713 err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
1714 if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
1715
1716 // And start listening for packets
1717 struct sockaddr_in6 listening_sockaddr6;
1718 mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
1719 listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
1720 listening_sockaddr6.sin6_family = AF_INET6;
1721 listening_sockaddr6.sin6_port = port.NotAnInteger;
1722 listening_sockaddr6.sin6_flowinfo = 0;
1723 listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
1724 listening_sockaddr6.sin6_scope_id = 0;
1725 err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
1726 if (err) { errstr = "bind"; goto fail; }
1727 }
1728
1729 fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
1730 fcntl(skt, F_SETFD, 1); // set close-on-exec
1731 *s = skt;
1732 k->KQcallback = myKQSocketCallBack;
1733 k->KQcontext = cp;
1734 k->KQtask = "UDP packet reception";
1735 KQueueSet(*s, EV_ADD, EVFILT_READ, k);
1736
1737 return(err);
1738
1739 fail:
1740 // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
1741 if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
1742 LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
1743
1744 // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
1745 if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE)
1746 NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
1747 "Congratulations, you've reproduced an elusive bug.\r"
1748 "Please contact the current assignee of <rdar://problem/3814904>.\r"
1749 "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
1750 "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
1751
1752 close(skt);
1753 return(err);
1754 }
1755
1756 struct UDPSocket_struct
1757 {
1758 KQSocketSet ss;
1759 };
1760
1761 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
1762 {
1763 mStatus err;
1764 UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
1765 if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
1766 memset(p, 0, sizeof(UDPSocket));
1767 p->ss.m = m;
1768 p->ss.sktv4 = -1;
1769 p->ss.sktv6 = -1;
1770 err = SetupSocket(&p->ss, port, AF_INET);
1771 if (err)
1772 {
1773 // In customer builds we don't want to log failures with port 5351, because this is a known issue
1774 // of failing to bind to this port when Internet Sharing has already bound to it
1775 if (mDNSSameIPPort(port, NATPMPPort))
1776 LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
1777 else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
1778 freeL("UDPSocket", p);
1779 return(mDNSNULL);
1780 }
1781 return(p);
1782 }
1783
1784 mDNSlocal void CloseSocketSet(KQSocketSet *ss)
1785 {
1786 if (ss->sktv4 != -1)
1787 {
1788 close(ss->sktv4);
1789 ss->sktv4 = -1;
1790 }
1791 if (ss->sktv6 != -1)
1792 {
1793 close(ss->sktv6);
1794 ss->sktv6 = -1;
1795 }
1796 }
1797
1798 mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
1799 {
1800 CloseSocketSet(&sock->ss);
1801 freeL("UDPSocket", sock);
1802 }
1803
1804 #if COMPILER_LIKES_PRAGMA_MARK
1805 #pragma mark -
1806 #pragma mark - Key Management
1807 #endif
1808
1809 #ifndef NO_SECURITYFRAMEWORK
1810 mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
1811 {
1812 CFMutableArrayRef certChain = NULL;
1813 if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
1814 SecCertificateRef cert;
1815 OSStatus err = SecIdentityCopyCertificate(identity, &cert);
1816 if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
1817 else
1818 {
1819 SecPolicySearchRef searchRef;
1820 err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
1821 if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
1822 else
1823 {
1824 SecPolicyRef policy;
1825 err = SecPolicySearchCopyNext(searchRef, &policy);
1826 if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
1827 else
1828 {
1829 CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
1830 if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
1831 else
1832 {
1833 SecTrustRef trust;
1834 err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
1835 if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
1836 else
1837 {
1838 err = SecTrustEvaluate(trust, NULL);
1839 if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
1840 else
1841 {
1842 CFArrayRef rawCertChain;
1843 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1844 err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
1845 if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
1846 else
1847 {
1848 certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
1849 if (!certChain) LogMsg("getCertChain: certChain is NULL");
1850 else
1851 {
1852 // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
1853 // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
1854 CFArraySetValueAtIndex(certChain, 0, identity);
1855 // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
1856 if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
1857 }
1858 CFRelease(rawCertChain);
1859 // Do not free statusChain:
1860 // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
1861 // certChain: Call the CFRelease function to release this object when you are finished with it.
1862 // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
1863 }
1864 }
1865 CFRelease(trust);
1866 }
1867 CFRelease(wrappedCert);
1868 }
1869 CFRelease(policy);
1870 }
1871 CFRelease(searchRef);
1872 }
1873 CFRelease(cert);
1874 }
1875 return certChain;
1876 }
1877 #endif /* NO_SECURITYFRAMEWORK */
1878
1879 mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
1880 {
1881 #ifdef NO_SECURITYFRAMEWORK
1882 return mStatus_UnsupportedErr;
1883 #else
1884 SecIdentityRef identity = nil;
1885 SecIdentitySearchRef srchRef = nil;
1886 OSStatus err;
1887
1888 // search for "any" identity matching specified key use
1889 // In this app, we expect there to be exactly one
1890 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
1891 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
1892
1893 err = SecIdentitySearchCopyNext(srchRef, &identity);
1894 if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
1895
1896 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
1897 { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
1898
1899 // Found one. Call getCertChain to create the correct certificate chain.
1900 ServerCerts = GetCertChain(identity);
1901 if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
1902
1903 return mStatus_NoError;
1904 #endif /* NO_SECURITYFRAMEWORK */
1905 }
1906
1907 mDNSexport void mDNSPlatformTLSTearDownCerts(void)
1908 {
1909 #ifndef NO_SECURITYFRAMEWORK
1910 if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
1911 #endif /* NO_SECURITYFRAMEWORK */
1912 }
1913
1914 // This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
1915 mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
1916 {
1917 CFStringEncoding encoding = kCFStringEncodingUTF8;
1918 CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
1919 if (cfs)
1920 {
1921 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1922 CFRelease(cfs);
1923 }
1924 }
1925
1926 // This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
1927 mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
1928 {
1929 CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
1930 if (cfs)
1931 {
1932 CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
1933 CFRelease(cfs);
1934 }
1935 }
1936
1937 mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
1938 {
1939 mDNSs32 val;
1940 CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
1941 if (!state) return mDNSfalse;
1942 if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
1943 return val ? mDNStrue : mDNSfalse;
1944 }
1945
1946 mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
1947 {
1948 if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
1949
1950 if (sa->sa_family == AF_INET)
1951 {
1952 struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
1953 ip->type = mDNSAddrType_IPv4;
1954 ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
1955 return(mStatus_NoError);
1956 }
1957
1958 if (sa->sa_family == AF_INET6)
1959 {
1960 struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
1961 // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
1962 // value into the second word of the IPv6 link-local address, so they can just
1963 // pass around IPv6 address structures instead of full sockaddr_in6 structures.
1964 // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
1965 // To work around this we always whack the second word of any IPv6 link-local address back to zero.
1966 if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1967 ip->type = mDNSAddrType_IPv6;
1968 ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
1969 return(mStatus_NoError);
1970 }
1971
1972 LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
1973 return(mStatus_Invalid);
1974 }
1975
1976 mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
1977 {
1978 mDNSEthAddr eth = zeroEthAddr;
1979 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
1980 if (store)
1981 {
1982 CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
1983 if (entityname)
1984 {
1985 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
1986 if (dict)
1987 {
1988 CFRange range = { 0, 6 }; // Offset, length
1989 CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
1990 if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
1991 CFRelease(dict);
1992 }
1993 CFRelease(entityname);
1994 }
1995 CFRelease(store);
1996 }
1997 return(eth);
1998 }
1999
2000 // Returns pointer to newly created NetworkInterfaceInfoOSX object, or
2001 // pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
2002 // may return NULL if out of memory (unlikely) or parameters are invalid for some reason
2003 // (e.g. sa_family not AF_INET or AF_INET6)
2004 mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
2005 {
2006 mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
2007 mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
2008
2009 mDNSAddr ip, mask;
2010 if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
2011 if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
2012
2013 NetworkInterfaceInfoOSX **p;
2014 for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
2015 if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID))
2016 {
2017 debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
2018 (*p)->Exists = mDNStrue;
2019 // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
2020 if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
2021 return(*p);
2022 }
2023
2024 NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
2025 debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
2026 if (!i) return(mDNSNULL);
2027 mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
2028 i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
2029 if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
2030 strcpy(i->ifa_name, ifa->ifa_name); // This is safe because we know we allocated i->ifa_name with sufficient space
2031
2032 i->ifinfo.InterfaceID = mDNSNULL;
2033 i->ifinfo.ip = ip;
2034 i->ifinfo.mask = mask;
2035 strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
2036 i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
2037 i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
2038 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
2039
2040 i->next = mDNSNULL;
2041 i->Exists = mDNStrue;
2042 i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
2043 i->LastSeen = utc;
2044 i->Flashing = mDNSfalse;
2045 i->Occulting = mDNSfalse;
2046 i->scope_id = scope_id;
2047 i->BSSID = bssid;
2048 i->sa_family = ifa->ifa_addr->sa_family;
2049 i->ifa_flags = ifa->ifa_flags;
2050
2051 *p = i;
2052 return(i);
2053 }
2054
2055 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2056 mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
2057 {
2058 NetworkInterfaceInfoOSX *i;
2059 for (i = m->p->InterfaceList; i; i = i->next)
2060 if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
2061 if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
2062 return(i);
2063 return(mDNSNULL);
2064 }
2065 #endif
2066
2067 #if APPLE_OSX_mDNSResponder
2068
2069 #if COMPILER_LIKES_PRAGMA_MARK
2070 #pragma mark -
2071 #pragma mark - AutoTunnel
2072 #endif
2073
2074 #define kRacoonPort 4500
2075
2076 static mDNSBool AnonymousRacoonConfig = mDNSfalse;
2077
2078 // MUST be called with lock held
2079 mDNSlocal mDNSBool TunnelServers(mDNS *const m)
2080 {
2081 ServiceRecordSet *p;
2082 for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
2083 {
2084 DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
2085 if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
2086 }
2087 return(mDNSfalse);
2088 }
2089
2090 // MUST be called with lock held
2091 mDNSlocal mDNSBool TunnelClients(mDNS *const m)
2092 {
2093 ClientTunnel *p;
2094 for (p = m->TunnelClients; p; p = p->next)
2095 if (p->q.ThisQInterval < 0)
2096 return(mDNStrue);
2097 return(mDNSfalse);
2098 }
2099
2100 mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
2101 {
2102 if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
2103 {
2104 mStatus err;
2105 LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
2106
2107 // 1. Set up our address record for the internal tunnel address
2108 // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
2109 info->AutoTunnelHostRecord.namestorage.c[0] = 0;
2110 AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
2111 AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
2112 info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
2113 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
2114 err = mDNS_Register(m, &info->AutoTunnelHostRecord);
2115 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
2116
2117 // 2. Set up device info record
2118 ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
2119 mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
2120 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
2121 mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
2122 info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
2123 info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
2124 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
2125 err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
2126 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
2127
2128 // 3. Set up our address record for the external tunnel address
2129 // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
2130 info->AutoTunnelTarget.namestorage.c[0] = 0;
2131 AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
2132 AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
2133 info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
2134
2135 mDNS_Lock(m);
2136 mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
2137 mDNS_Unlock(m);
2138
2139 // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
2140 AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
2141 AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
2142 AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
2143 info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
2144 info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
2145 info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
2146 AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
2147 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
2148 err = mDNS_Register(m, &info->AutoTunnelService);
2149 if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
2150
2151 LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
2152 info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
2153 info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
2154 }
2155 }
2156
2157 mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
2158 {
2159 LogOperation("DeregisterAutoTunnelRecords %##s", info->domain.c);
2160 if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
2161 {
2162 mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
2163 if (err)
2164 {
2165 info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
2166 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
2167 }
2168
2169 mDNS_Lock(m);
2170 mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
2171 mDNS_Unlock(m);
2172 }
2173
2174 if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
2175 {
2176 mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
2177 if (err)
2178 {
2179 info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
2180 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
2181 }
2182 }
2183
2184 if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
2185 {
2186 mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
2187 if (err)
2188 {
2189 info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
2190 LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
2191 }
2192 }
2193 }
2194
2195 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
2196 {
2197 DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
2198 if (result == mStatus_MemFree)
2199 {
2200 LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
2201 RegisterAutoTunnelRecords(m,info);
2202 }
2203 }
2204
2205 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
2206 {
2207 DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
2208 LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s",
2209 n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
2210
2211 m->NextSRVUpdate = m->timenow;
2212 DeregisterAutoTunnelRecords(m,info);
2213 RegisterAutoTunnelRecords(m,info);
2214
2215 // Determine whether we need racoon to accept incoming connections
2216 for (info = m->AuthInfoList; info; info = info->next)
2217 if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
2218 break;
2219 mDNSBool needRacoonConfig = info != mDNSNULL;
2220 if (needRacoonConfig != AnonymousRacoonConfig)
2221 {
2222 AnonymousRacoonConfig = needRacoonConfig;
2223 // Create or revert configuration file, and start (or SIGHUP) Racoon
2224 (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, info ? info->b64keydata : "");
2225 }
2226 }
2227
2228 mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr)
2229 {
2230 if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
2231 {
2232 LogOperation("Aborting deregistration of %s", ARDisplayString(m, rr));
2233 CompleteDeregistration(m, rr);
2234 }
2235 else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered)
2236 LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m, rr));
2237 }
2238
2239 // Before SetupLocalAutoTunnelInterface_internal is called,
2240 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
2241 // Must be called with the lock held
2242 mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
2243 {
2244 LogOperation("SetupLocalAutoTunnelInterface");
2245
2246 // 1. Configure the local IPv6 address
2247 if (!m->AutoTunnelHostAddrActive)
2248 {
2249 m->AutoTunnelHostAddrActive = mDNStrue;
2250 LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
2251 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
2252 }
2253
2254 // 2. If we have at least one server (pending) listening, publish our records
2255 if (TunnelServers(m))
2256 {
2257 DomainAuthInfo *info;
2258 for (info = m->AuthInfoList; info; info = info->next)
2259 {
2260 if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
2261 {
2262 // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
2263 AbortDeregistration(m, &info->AutoTunnelHostRecord);
2264 AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
2265 AbortDeregistration(m, &info->AutoTunnelService);
2266
2267 mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2268 mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2269 mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2270 mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
2271
2272 // Try to get a NAT port mapping for the AutoTunnelService
2273 info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
2274 info->AutoTunnelNAT.clientContext = info;
2275 info->AutoTunnelNAT.Protocol = NATOp_MapUDP;
2276 info->AutoTunnelNAT.IntPort = mDNSOpaque16fromIntVal(kRacoonPort);
2277 info->AutoTunnelNAT.RequestedPort = mDNSOpaque16fromIntVal(kRacoonPort);
2278 info->AutoTunnelNAT.NATLease = 0;
2279 mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
2280 if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
2281 }
2282 }
2283 }
2284 }
2285
2286 mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
2287 {
2288 return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, tun->loc_outer.b, kRacoonPort, tun->rmt_inner.b, tun->rmt_outer.b, mDNSVal16(tun->rmt_outer_port), tun->b64keydata));
2289 }
2290
2291 // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
2292 #define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
2293
2294 mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
2295 {
2296 DNSQuestion *q = m->Questions;
2297 while (q)
2298 {
2299 if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
2300 {
2301 LogOperation("Restart %##s", q->qname.c);
2302 mDNSQuestionCallback *tmp = q->QuestionCallback;
2303 q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
2304 mDNS_StopQuery(m, q);
2305 mDNS_StartQuery(m, q);
2306 q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
2307 if (!success) q->NoAnswer = NoAnswer_Fail;
2308 // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
2309 // In general we have to assume that the question list might have changed in arbitrary ways.
2310 // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
2311 // already in use. The safest solution is just to go back to the start of the list and start again.
2312 // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
2313 // just one suspended question, so it's really a 2n algorithm.
2314 q = m->Questions;
2315 }
2316 else
2317 q = q->next;
2318 }
2319 }
2320
2321 mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
2322 {
2323 ClientTunnel **p = &m->TunnelClients;
2324 while (*p != tun && *p) p = &(*p)->next;
2325 if (*p) *p = tun->next;
2326 ReissueBlockedQuestions(m, &tun->dstname, success);
2327 freeL("ClientTunnel", tun);
2328 }
2329
2330 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
2331 {
2332 ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
2333 LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
2334
2335 if (!AddRecord) return;
2336 mDNS_StopQuery(m, question);
2337
2338 if (!answer->rdlength)
2339 {
2340 LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c);
2341 UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
2342 return;
2343 }
2344
2345 if (question->qtype == kDNSType_AAAA)
2346 {
2347 if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
2348 {
2349 LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer->rdata->u.ipv6);
2350 UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
2351 return;
2352 }
2353
2354 tun->rmt_inner = answer->rdata->u.ipv6;
2355 LogOperation("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
2356 AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
2357 AppendDomainName(&question->qname, &tun->dstname);
2358 question->qtype = kDNSType_SRV;
2359 mDNS_StartQuery(m, &tun->q);
2360 }
2361 else if (question->qtype == kDNSType_SRV)
2362 {
2363 LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
2364 AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
2365 tun->rmt_outer_port = answer->rdata->u.srv.port;
2366 question->qtype = kDNSType_A;
2367 mDNS_StartQuery(m, &tun->q);
2368 }
2369 else if (question->qtype == kDNSType_A)
2370 {
2371 ClientTunnel *old = mDNSNULL;
2372 LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
2373 question->ThisQInterval = -1; // So we know this tunnel setup has completed
2374 tun->rmt_outer = answer->rdata->u.ipv4;
2375 tun->loc_inner = m->AutoTunnelHostAddr;
2376 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
2377 tmpDst.ip.v4 = tun->rmt_outer;
2378 mDNSAddr tmpSrc = zeroAddr;
2379 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
2380 if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
2381 else tun->loc_outer = m->AdvertisedV4.ip.v4;
2382
2383 ClientTunnel **p = &tun->next;
2384 mDNSBool needSetKeys = mDNStrue;
2385 while (*p)
2386 {
2387 if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
2388 else
2389 {
2390 LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2391 old = *p;
2392 *p = old->next;
2393 if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
2394 else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
2395 !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
2396 !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
2397 !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
2398 !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
2399 {
2400 LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2401 AutoTunnelSetKeys(old, mDNSfalse);
2402 }
2403 else needSetKeys = mDNSfalse;
2404
2405 freeL("ClientTunnel", old);
2406 }
2407 }
2408
2409 if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
2410
2411 if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); };
2412
2413 mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
2414 // Kick off any questions that were held pending this tunnel setup
2415 ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
2416 }
2417 else
2418 LogMsg("AutoTunnelCallback: Unknown question %p", question);
2419 }
2420
2421 // Must be called with the lock held
2422 mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
2423 {
2424 ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
2425 if (!p) return;
2426 AssignDomainName(&p->dstname, &q->qname);
2427 p->markedForDeletion = mDNSfalse;
2428 p->loc_inner = zerov6Addr;
2429 p->loc_outer = zerov4Addr;
2430 p->rmt_inner = zerov6Addr;
2431 p->rmt_outer = zerov4Addr;
2432 p->rmt_outer_port = zeroIPPort;
2433 mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata);
2434 p->next = m->TunnelClients;
2435 m->TunnelClients = p; // Intentionally build list in reverse order
2436
2437 p->q.InterfaceID = mDNSInterface_Any;
2438 p->q.Target = zeroAddr;
2439 AssignDomainName(&p->q.qname, &q->qname);
2440 p->q.qtype = kDNSType_AAAA;
2441 p->q.qclass = kDNSClass_IN;
2442 p->q.LongLived = mDNSfalse;
2443 p->q.ExpectUnique = mDNStrue;
2444 p->q.ForceMCast = mDNSfalse;
2445 p->q.ReturnIntermed = mDNStrue;
2446 p->q.QuestionCallback = AutoTunnelCallback;
2447 p->q.QuestionContext = p;
2448
2449 LogOperation("AddNewClientTunnel start %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : "");
2450 mDNS_StartQuery_internal(m, &p->q);
2451 }
2452
2453 #endif // APPLE_OSX_mDNSResponder
2454
2455 #if COMPILER_LIKES_PRAGMA_MARK
2456 #pragma mark -
2457 #pragma mark - Power State & Configuration Change Management
2458 #endif
2459
2460 mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
2461 {
2462 mDNSBool foundav4 = mDNSfalse;
2463 mDNSBool foundav6 = mDNSfalse;
2464 struct ifaddrs *ifa = myGetIfAddrs(1);
2465 struct ifaddrs *v4Loopback = NULL;
2466 struct ifaddrs *v6Loopback = NULL;
2467 mDNSEthAddr PrimaryMAC = zeroEthAddr;
2468 char defaultname[32];
2469 #ifndef NO_IPV6
2470 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
2471 if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
2472 #endif
2473 if (m->SleepState) ifa = NULL;
2474
2475 while (ifa)
2476 {
2477 #if LIST_ALL_INTERFACES
2478 if (ifa->ifa_addr->sa_family == AF_APPLETALK)
2479 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
2480 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2481 else if (ifa->ifa_addr->sa_family == AF_LINK)
2482 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
2483 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2484 else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
2485 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
2486 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2487 if (!(ifa->ifa_flags & IFF_UP))
2488 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
2489 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2490 if (!(ifa->ifa_flags & IFF_MULTICAST))
2491 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
2492 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2493 if (ifa->ifa_flags & IFF_POINTOPOINT)
2494 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
2495 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2496 if (ifa->ifa_flags & IFF_LOOPBACK)
2497 LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
2498 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
2499 #endif
2500
2501 if (ifa->ifa_addr->sa_family == AF_LINK)
2502 {
2503 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
2504 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
2505 mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
2506 }
2507
2508 if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
2509 if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
2510 {
2511 if (!ifa->ifa_netmask)
2512 {
2513 mDNSAddr ip;
2514 SetupAddr(&ip, ifa->ifa_addr);
2515 LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
2516 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
2517 }
2518 else if (ifa->ifa_addr->sa_family != ifa->ifa_netmask->sa_family)
2519 {
2520 mDNSAddr ip;
2521 SetupAddr(&ip, ifa->ifa_addr);
2522 LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
2523 ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
2524 }
2525 else
2526 {
2527 int ifru_flags6 = 0;
2528 #ifndef NO_IPV6
2529 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
2530 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
2531 {
2532 struct in6_ifreq ifr6;
2533 mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
2534 strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
2535 ifr6.ifr_addr = *sin6;
2536 if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
2537 ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
2538 verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
2539 }
2540 #endif
2541 if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
2542 {
2543 if (ifa->ifa_flags & IFF_LOOPBACK)
2544 {
2545 if (ifa->ifa_addr->sa_family == AF_INET) v4Loopback = ifa;
2546 #ifndef NO_IPV6
2547 else if (sin6->sin6_addr.s6_addr[0] != 0xFD) v6Loopback = ifa;
2548 #endif
2549 }
2550 else
2551 {
2552 NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
2553 if (i && MulticastInterface(i))
2554 {
2555 if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
2556 else foundav6 = mDNStrue;
2557 }
2558 }
2559 }
2560 }
2561 }
2562 ifa = ifa->ifa_next;
2563 }
2564
2565 // For efficiency, we don't register a loopback interface when other interfaces of that family are available
2566 if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
2567 if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
2568
2569 // Now the list is complete, set the McastTxRx setting for each interface.
2570 NetworkInterfaceInfoOSX *i;
2571 for (i = m->p->InterfaceList; i; i = i->next)
2572 if (i->Exists)
2573 {
2574 mDNSBool txrx = MulticastInterface(i);
2575 #if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
2576 txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
2577 #endif
2578 if (i->ifinfo.McastTxRx != txrx)
2579 {
2580 i->ifinfo.McastTxRx = txrx;
2581 i->Exists = 2; // State change; need to deregister and reregister this interface
2582 }
2583 }
2584
2585 #ifndef NO_IPV6
2586 if (InfoSocket >= 0) close(InfoSocket);
2587 #endif
2588
2589 // If we haven't set up AutoTunnelHostAddr yet, do it now
2590 if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
2591 {
2592 m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
2593 m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
2594 m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
2595 m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
2596 m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
2597 m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
2598 m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
2599 m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
2600 m->AutoTunnelHostAddr.b[0x8] = PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
2601 m->AutoTunnelHostAddr.b[0x9] = PrimaryMAC.b[1];
2602 m->AutoTunnelHostAddr.b[0xA] = PrimaryMAC.b[2];
2603 m->AutoTunnelHostAddr.b[0xB] = 0xFF;
2604 m->AutoTunnelHostAddr.b[0xC] = 0xFE;
2605 m->AutoTunnelHostAddr.b[0xD] = PrimaryMAC.b[3];
2606 m->AutoTunnelHostAddr.b[0xE] = PrimaryMAC.b[4];
2607 m->AutoTunnelHostAddr.b[0xF] = PrimaryMAC.b[5];
2608 m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
2609 m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
2610 m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
2611 LogOperation("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
2612 }
2613
2614 #ifndef kDefaultLocalHostNamePrefix
2615 #define kDefaultLocalHostNamePrefix "Macintosh"
2616 #endif
2617 mDNS_snprintf(defaultname, sizeof(defaultname), kDefaultLocalHostNamePrefix "-%02X%02X%02X%02X%02X%02X",
2618 PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
2619
2620 // Set up the nice label
2621 domainlabel nicelabel;
2622 nicelabel.c[0] = 0;
2623 GetUserSpecifiedFriendlyComputerName(&nicelabel);
2624 if (nicelabel.c[0] == 0)
2625 {
2626 LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
2627 MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
2628 }
2629
2630 // Set up the RFC 1034-compliant label
2631 domainlabel hostlabel;
2632 hostlabel.c[0] = 0;
2633 GetUserSpecifiedLocalHostName(&hostlabel);
2634 if (hostlabel.c[0] == 0)
2635 {
2636 LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
2637 MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
2638 }
2639
2640 mDNSBool namechange = mDNSfalse;
2641
2642 // We use a case-sensitive comparison here because even though changing the capitalization
2643 // of the name alone is not significant to DNS, it's still a change from the user's point of view
2644 if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
2645 debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
2646 else
2647 {
2648 if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
2649 LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c);
2650 m->p->usernicelabel = m->nicelabel = nicelabel;
2651 namechange = mDNStrue;
2652 }
2653
2654 if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
2655 debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
2656 else
2657 {
2658 if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
2659 LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c);
2660 m->p->userhostlabel = m->hostlabel = hostlabel;
2661 mDNS_SetFQDN(m);
2662 namechange = mDNStrue;
2663 }
2664
2665 #if APPLE_OSX_mDNSResponder
2666 if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
2667 {
2668 DomainAuthInfo *info;
2669 for (info = m->AuthInfoList; info; info = info->next)
2670 if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress))
2671 AutoTunnelNATCallback(m, &info->AutoTunnelNAT);
2672 }
2673 #endif
2674
2675 return(mStatus_NoError);
2676 }
2677
2678 #if LogAllOperations || MDNS_DEBUGMSGS
2679 // Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
2680 // Returns -1 if all the one-bits are not contiguous
2681 mDNSlocal int CountMaskBits(mDNSAddr *mask)
2682 {
2683 int i = 0, bits = 0;
2684 int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
2685 while (i < bytes)
2686 {
2687 mDNSu8 b = mask->ip.v6.b[i++];
2688 while (b & 0x80) { bits++; b <<= 1; }
2689 if (b) return(-1);
2690 }
2691 while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
2692 return(bits);
2693 }
2694 #endif
2695
2696 // returns count of non-link local V4 addresses registered
2697 mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
2698 {
2699 NetworkInterfaceInfoOSX *i;
2700 int count = 0;
2701 for (i = m->p->InterfaceList; i; i = i->next)
2702 if (i->Exists)
2703 {
2704 NetworkInterfaceInfo *n = &i->ifinfo;
2705 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
2706 if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
2707
2708 if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check
2709 {
2710 LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
2711 n->InterfaceID = mDNSNULL;
2712 }
2713
2714 if (!n->InterfaceID)
2715 {
2716 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2717 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2718 // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
2719 n->InterfaceID = (mDNSInterfaceID)primary;
2720 // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
2721 // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
2722 // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
2723 i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
2724 mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
2725 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
2726 LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2727 i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
2728 i->Flashing ? " (Flashing)" : "",
2729 i->Occulting ? " (Occulting)" : "",
2730 n->InterfaceActive ? " (Primary)" : "");
2731 }
2732
2733 if (!n->McastTxRx)
2734 debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
2735 else
2736 {
2737 if (i->sa_family == AF_INET)
2738 {
2739 struct ip_mreq imr;
2740 primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
2741 imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
2742 imr.imr_interface = primary->ifa_v4addr;
2743 mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
2744 // Joining same group twice can give "Address already in use" error -- no need to report that
2745 if (err < 0 && errno != EADDRINUSE)
2746 LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
2747 }
2748 #ifndef NO_IPV6
2749 if (i->sa_family == AF_INET6)
2750 {
2751 struct ipv6_mreq i6mr;
2752 i6mr.ipv6mr_interface = primary->scope_id;
2753 i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
2754 mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
2755 // Joining same group twice can give "Address already in use" error -- no need to report that
2756 if (err < 0 && errno != EADDRINUSE)
2757 LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno));
2758 }
2759 #endif
2760 }
2761 }
2762 return count;
2763 }
2764
2765 mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
2766 {
2767 NetworkInterfaceInfoOSX *i;
2768 for (i = m->p->InterfaceList; i; i = i->next)
2769 {
2770 if (i->Exists) i->LastSeen = utc;
2771 i->Exists = mDNSfalse;
2772 }
2773 }
2774
2775 // returns count of non-link local V4 addresses deregistered
2776 mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
2777 {
2778 // First pass:
2779 // If an interface is going away, then deregister this from the mDNSCore.
2780 // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
2781 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
2782 // it refers to has gone away we'll crash.
2783 // Don't actually close the sockets or free the memory yet: When the last representative of an interface goes away
2784 // mDNSCore may want to send goodbye packets on that interface. (Not yet implemented, but a good idea anyway.)
2785 NetworkInterfaceInfoOSX *i;
2786 int count = 0;
2787 for (i = m->p->InterfaceList; i; i = i->next)
2788 {
2789 // If this interface is no longer active, or its InterfaceID is changing, deregister it
2790 NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
2791 if (i->ifinfo.InterfaceID)
2792 if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
2793 {
2794 i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
2795 LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
2796 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2797 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
2798 i->Flashing ? " (Flashing)" : "",
2799 i->Occulting ? " (Occulting)" : "",
2800 i->ifinfo.InterfaceActive ? " (Primary)" : "");
2801 mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
2802 if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
2803 i->ifinfo.InterfaceID = mDNSNULL;
2804 // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
2805 // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
2806 // If n->InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
2807 }
2808 }
2809
2810 // Second pass:
2811 // Now that everything that's going to deregister has done so, we can close sockets and free the memory
2812 NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
2813 while (*p)
2814 {
2815 i = *p;
2816 // If no longer active, delete interface from list and free memory
2817 if (!i->Exists)
2818 {
2819 if (i->LastSeen == utc) i->LastSeen = utc - 1;
2820 mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
2821 LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
2822 i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
2823 &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
2824 i->ifinfo.InterfaceActive ? " (Primary)" : "");
2825 if (delete)
2826 {
2827 *p = i->next;
2828 if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
2829 freeL("NetworkInterfaceInfoOSX", i);
2830 continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
2831 }
2832 }
2833 p = &i->next;
2834 }
2835 return count;
2836 }
2837
2838 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
2839 {
2840 DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
2841 if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
2842 else
2843 {
2844 dnle->next = mDNSNULL;
2845 dnle->uid = uid;
2846 AssignDomainName(&dnle->name, name);
2847 **List = dnle;
2848 *List = &dnle->next;
2849 }
2850 }
2851
2852 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
2853 {
2854 int i;
2855 char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
2856 domainname d;
2857
2858 // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
2859 if (fqdn) fqdn->c[0] = 0;
2860 if (RegDomains ) *RegDomains = NULL;
2861 if (BrowseDomains) *BrowseDomains = NULL;
2862
2863 LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
2864 setservers ? " setservers" : "",
2865 setsearch ? " setsearch" : "",
2866 fqdn ? " fqdn" : "",
2867 RegDomains ? " RegDomains" : "",
2868 BrowseDomains ? " BrowseDomains" : "");
2869
2870 // Add the inferred address-based configuration discovery domains
2871 // (should really be in core code I think, not platform-specific)
2872 if (setsearch)
2873 {
2874 struct ifaddrs *ifa = myGetIfAddrs(1);
2875 while (ifa)
2876 {
2877 mDNSAddr a, n;
2878 if (ifa->ifa_addr->sa_family == AF_INET &&
2879 ifa->ifa_netmask &&
2880 !(ifa->ifa_flags & IFF_LOOPBACK) &&
2881 !SetupAddr(&a, ifa->ifa_addr) &&
2882 !SetupAddr(&n, ifa->ifa_netmask) &&
2883 !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
2884 {
2885 // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
2886 mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
2887 a.ip.v4.b[2] & n.ip.v4.b[2],
2888 a.ip.v4.b[1] & n.ip.v4.b[1],
2889 a.ip.v4.b[0] & n.ip.v4.b[0]);
2890 mDNS_AddSearchDomain_CString(buf);
2891 }
2892 ifa = ifa->ifa_next;
2893 }
2894 }
2895
2896 #ifndef MDNS_NO_DNSINFO
2897 if (setservers || setsearch)
2898 {
2899 dns_config_t *config = dns_configuration_copy();
2900 if (!config)
2901 {
2902 // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
2903 // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
2904 // Apparently this is expected behaviour -- "not a bug".
2905 // Accordingly, we suppress syslog messages for the first three minutes after boot.
2906 // If we are still getting failures after three minutes, then we log them.
2907 if (mDNSMacOSXSystemBuildNumber(NULL) > 7 && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
2908 LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
2909 }
2910 else
2911 {
2912 LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
2913 if (setservers)
2914 {
2915 for (i = 0; i < config->n_resolver; i++)
2916 {
2917 int j, n;
2918 dns_resolver_t *r = config->resolver[i];
2919 // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
2920 // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
2921 // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
2922 if (r->port == 5353) continue;
2923 if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
2924 else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
2925
2926 for (j = 0; j < config->n_resolver; j++) // check if this is the lowest-weighted server for the domain
2927 {
2928 dns_resolver_t *p = config->resolver[j];
2929 if (p->port == 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
2930 if (p->search_order <= r->search_order)
2931 {
2932 domainname tmp;
2933 if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
2934 else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
2935 if (SameDomainName(&d, &tmp))
2936 if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
2937 }
2938 }
2939 if (j < config->n_resolver) // found a lower-weighted resolver for this domain
2940 debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j);
2941 else
2942 {
2943 mDNSInterfaceID interface = mDNSInterface_Any;
2944 int disabled = 0;
2945
2946 // DNS server option parsing
2947 if (r->options != NULL)
2948 {
2949 char *nextOption = r->options;
2950 char *currentOption = NULL;
2951 while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
2952 {
2953 // The option may be in the form of interface=xxx where xxx is an interface name.
2954 if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
2955 {
2956 NetworkInterfaceInfoOSX *i;
2957 char ifname[IF_NAMESIZE+1];
2958 mDNSu32 ifindex = 0;
2959 // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
2960 // This allows us to block these special queries from going out on the wire.
2961 strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
2962 ifindex = if_nametoindex(ifname);
2963 if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
2964 LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
2965 // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
2966 // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
2967 for (i = m->p->InterfaceList; i; i = i->next)
2968 if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break;
2969 if (i != NULL) interface = i->ifinfo.InterfaceID;
2970 if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
2971 }
2972 }
2973 }
2974 for (n = 0; n < r->n_nameserver; n++)
2975 if (r->nameserver[n]->sa_family == AF_INET && (interface || disabled || !AddrRequiresPPPConnection(r->nameserver[n])))
2976 {
2977 mDNSAddr saddr;
2978 // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
2979 debugf("Adding dns server from slot %d %#a for domain %##s", i, &saddr, d.c);
2980 if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
2981 else
2982 {
2983 DNSServer *s = mDNS_AddDNSServer(m, &d, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
2984 if (s && disabled) s->teststate = DNSServer_Disabled;
2985 }
2986 }
2987 }
2988 }
2989 }
2990 if (setsearch)
2991 {
2992 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
2993 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
2994 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
2995 // instead use the search domain list as the sole authority for what domains to search and in what order
2996 // (and the domain from the "domain" field will also appear somewhere in that list).
2997 // Also, all search domains get added to the search list for resolver[0], so the domains and/or
2998 // search lists for other resolvers in the list need to be ignored.
2999 if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
3000 else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
3001 }
3002 dns_configuration_free(config);
3003 setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
3004 setsearch = mDNSfalse;
3005 }
3006 }
3007 #endif // MDNS_NO_DNSINFO
3008
3009 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
3010 if (store)
3011 {
3012 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
3013 if (dict)
3014 {
3015 if (fqdn)
3016 {
3017 CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
3018 if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
3019 {
3020 // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
3021 CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
3022 if (fqdnDict && DDNSSettingEnabled(fqdnDict))
3023 {
3024 CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
3025 if (name)
3026 {
3027 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3028 !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
3029 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
3030 else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
3031 }
3032 }
3033 }
3034 }
3035
3036 if (RegDomains)
3037 {
3038 CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
3039 if (regArray && CFArrayGetCount(regArray) > 0)
3040 {
3041 CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
3042 if (regDict && DDNSSettingEnabled(regDict))
3043 {
3044 CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
3045 if (name)
3046 {
3047 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3048 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
3049 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
3050 else
3051 {
3052 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
3053 AppendDNameListElem(&RegDomains, 0, &d);
3054 }
3055 }
3056 }
3057 }
3058 }
3059
3060 if (BrowseDomains)
3061 {
3062 CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
3063 if (browseArray)
3064 {
3065 for (i = 0; i < CFArrayGetCount(browseArray); i++)
3066 {
3067 CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
3068 if (browseDict && DDNSSettingEnabled(browseDict))
3069 {
3070 CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
3071 if (name)
3072 {
3073 if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
3074 !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
3075 LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
3076 else
3077 {
3078 debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
3079 AppendDNameListElem(&BrowseDomains, 0, &d);
3080 }
3081 }
3082 }
3083 }
3084 }
3085 }
3086 CFRelease(dict);
3087 }
3088
3089 if (RegDomains)
3090 {
3091 CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
3092 if (btmm)
3093 {
3094 CFIndex size = CFDictionaryGetCount(btmm);
3095 const void *key[size];
3096 const void *val[size];
3097 CFDictionaryGetKeysAndValues(btmm, key, val);
3098 for (i = 0; i < size; i++)
3099 {
3100 LogOperation("BackToMyMac %d", i);
3101 if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
3102 LogMsg("Can't read BackToMyMac %d key %s", i, buf);
3103 else
3104 {
3105 mDNSu32 uid = atoi(buf);
3106 if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
3107 LogMsg("Can't read BackToMyMac %d val %s", i, buf);
3108 else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
3109 {
3110 LogOperation("BackToMyMac %d %d %##s", i, uid, d.c);
3111 AppendDNameListElem(&RegDomains, uid, &d);
3112 }
3113 }
3114 }
3115 CFRelease(btmm);
3116 }
3117 }
3118
3119 if (setservers || setsearch)
3120 {
3121 CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
3122 if (key)
3123 {
3124 CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
3125 if (dict)
3126 {
3127 if (setservers)
3128 {
3129 CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
3130 if (values)
3131 {
3132 for (i = 0; i < CFArrayGetCount(values); i++)
3133 {
3134 CFStringRef s = CFArrayGetValueAtIndex(values, i);
3135 char buf[256];
3136 mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
3137 if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
3138 inet_aton(buf, (struct in_addr *) &addr.ip.v4))
3139 mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
3140 }
3141 }
3142 }
3143 if (setsearch)
3144 {
3145 // Add the manual and/or DHCP-dicovered search domains
3146 CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
3147 if (searchDomains)
3148 {
3149 for (i = 0; i < CFArrayGetCount(searchDomains); i++)
3150 {
3151 CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
3152 if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
3153 mDNS_AddSearchDomain_CString(buf);
3154 }
3155 }
3156 else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
3157 {
3158 // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
3159 // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
3160 // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
3161 // instead use the search domain list as the sole authority for what domains to search and in what order
3162 // (and the domain from the "domain" field will also appear somewhere in that list).
3163 CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
3164 if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
3165 mDNS_AddSearchDomain_CString(buf);
3166 }
3167 }
3168 CFRelease(dict);
3169 }
3170 CFRelease(key);
3171 }
3172 }
3173 CFRelease(store);
3174 }
3175 }
3176
3177 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
3178 {
3179 SCDynamicStoreRef store = NULL;
3180 CFDictionaryRef dict = NULL;
3181 CFStringRef key = NULL;
3182 CFStringRef string = NULL;
3183 int nAdditions = 0;
3184 int nDeletions = 0;
3185 char buf[256];
3186 mStatus err = 0;
3187
3188 // get IPv4 settings
3189
3190 store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
3191 require_action(store, exit, err = mStatus_UnknownErr);
3192
3193 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
3194 require_action(key, exit, err = mStatus_UnknownErr);
3195
3196 dict = SCDynamicStoreCopyValue(store, key);
3197 require_action(dict, exit, err = mStatus_UnknownErr);
3198
3199 // handle router changes
3200
3201 r->type = mDNSAddrType_IPv4;
3202 r->ip.v4 = zerov4Addr;
3203
3204 string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
3205
3206 if (string)
3207 {
3208 struct sockaddr_in saddr;
3209
3210 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
3211 LogMsg("Could not convert router to CString");
3212 else
3213 {
3214 saddr.sin_len = sizeof(saddr);
3215 saddr.sin_family = AF_INET;
3216 saddr.sin_port = 0;
3217 inet_aton(buf, &saddr.sin_addr);
3218
3219 if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
3220 else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
3221 }
3222 }
3223
3224 // handle primary interface changes
3225 // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
3226 if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
3227
3228 string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
3229
3230 if (string)
3231 {
3232 mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
3233 struct ifaddrs *ifa = myGetIfAddrs(1);
3234
3235 *v4 = *v6 = zeroAddr;
3236
3237 if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
3238
3239 // find primary interface in list
3240 while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
3241 {
3242 mDNSAddr tmp6 = zeroAddr;
3243 if (!strcmp(buf, ifa->ifa_name))
3244 {
3245 if (ifa->ifa_addr->sa_family == AF_INET)
3246 {
3247 if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
3248 }
3249 else if (ifa->ifa_addr->sa_family == AF_INET6)
3250 {
3251 SetupAddr(&tmp6, ifa->ifa_addr);
3252 if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
3253 { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
3254 }
3255 }
3256 else
3257 {
3258 // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
3259 if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
3260 {
3261 SetupAddr(&tmp6, ifa->ifa_addr);
3262 if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
3263 }
3264 }
3265 ifa = ifa->ifa_next;
3266 }
3267
3268 // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
3269 // V4 to communicate w/ our DNS server
3270 }
3271
3272 exit:
3273 if (dict) CFRelease(dict);
3274 if (key) CFRelease(key);
3275 if (store) CFRelease(store);
3276 return err;
3277 }
3278
3279 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
3280 {
3281 LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
3282 char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
3283 ConvertDomainNameToCString(dname, uname);
3284
3285 char *p = uname;
3286 while (*p)
3287 {
3288 *p = tolower(*p);
3289 if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
3290 p++;
3291 }
3292
3293 // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
3294 // That single entity is a CFDictionary with name "HostNames".
3295 // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
3296 // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
3297 // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
3298 // The CFDictionary for each FQDN holds (at present) a single name/value pair,
3299 // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
3300
3301 const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
3302 const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
3303 const CFStringRef StatusKeys[1] = { CFSTR("Status") };
3304 if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
3305 else
3306 {
3307 const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
3308 if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
3309 else
3310 {
3311 const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
3312 if (HostVals[0])
3313 {
3314 const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
3315 if (StateVals[0])
3316 {
3317 CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
3318 if (StateDict)
3319 {
3320 mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict);
3321 CFRelease(StateDict);
3322 }
3323 CFRelease(StateVals[0]);
3324 }
3325 CFRelease(HostVals[0]);
3326 }
3327 CFRelease(StatusVals[0]);
3328 }
3329 CFRelease(HostKeys[0]);
3330 }
3331 }
3332
3333 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
3334 mDNSexport void SetDomainSecrets(mDNS *m)
3335 {
3336 #ifdef NO_SECURITYFRAMEWORK
3337 (void)m;
3338 LogMsg("Note: SetDomainSecrets: no keychain support");
3339 #else
3340 mDNSBool haveAutoTunnels = mDNSfalse;
3341
3342 LogOperation("SetDomainSecrets");
3343
3344 // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
3345 // In the case where the user simultaneously removes their DDNS host name and the key
3346 // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
3347 // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
3348 // address records behind that we no longer have permission to delete.
3349 DomainAuthInfo *ptr;
3350 for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
3351 ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
3352
3353 #if APPLE_OSX_mDNSResponder
3354 {
3355 // Mark all TunnelClients for deletion
3356 ClientTunnel *client;
3357 for (client = m->TunnelClients; client; client = client->next)
3358 {
3359 LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
3360 client->markedForDeletion = mDNStrue;
3361 }
3362 }
3363 #endif APPLE_OSX_mDNSResponder
3364
3365 // String Array used to write list of private domains to Dynamic Store
3366 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3367 if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
3368 CFIndex i;
3369 CFDataRef data = NULL;
3370 const int itemsPerEntry = 3; // domain name, key name, key value
3371 CFArrayRef secrets = NULL;
3372 int err = mDNSKeychainGetSecrets(&secrets);
3373 if (err || !secrets)
3374 LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
3375 else
3376 {
3377 CFIndex ArrayCount = CFArrayGetCount(secrets);
3378 // Iterate through the secrets
3379 for (i = 0; i < ArrayCount; ++i)
3380 {
3381 int j;
3382 CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
3383 if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
3384 { LogMsg("SetDomainSecrets: malformed entry"); continue; }
3385 for (j = 0; j < CFArrayGetCount(entry); ++j)
3386 if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
3387 { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
3388
3389 // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
3390
3391 // Get DNS domain this key is for
3392 char stringbuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal domainname as C-string, including terminating NUL
3393 data = CFArrayGetValueAtIndex(entry, 0);
3394 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3395 { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
3396 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
3397 stringbuf[CFDataGetLength(data)] = '\0';
3398
3399 domainname domain;
3400 if (!MakeDomainNameFromDNSNameString(&domain, stringbuf)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
3401
3402 // Get key name
3403 data = CFArrayGetValueAtIndex(entry, 1);
3404 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3405 { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
3406 CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
3407 stringbuf[CFDataGetLength(data)] = '\0';
3408
3409 domainname keyname;
3410 if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
3411
3412 // Get key data
3413 data = CFArrayGetValueAtIndex(entry, 2);
3414 if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
3415 { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
3416 CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
3417 stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
3418
3419 DomainAuthInfo *FoundInList;
3420 for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
3421 if (SameDomainName(&FoundInList->domain, &domain)) break;
3422
3423 #if APPLE_OSX_mDNSResponder
3424 if (FoundInList)
3425 {
3426 // If any client tunnel destination is in this domain, set deletion flag to false
3427 ClientTunnel *client;
3428 for (client = m->TunnelClients; client; client = client->next)
3429 if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
3430 {
3431 LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
3432 client->markedForDeletion = mDNSfalse;
3433 // If the key has changed, reconfigure the tunnel
3434 if (strncmp(stringbuf, client->b64keydata, sizeof(client->b64keydata)))
3435 {
3436 mDNSBool queryNotInProgress = client->q.ThisQInterval < 0;
3437 LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client->dstname.c, queryNotInProgress ? "reconfiguring" : "query in progress");
3438 if (queryNotInProgress) AutoTunnelSetKeys(client, mDNSfalse);
3439 mDNS_snprintf(client->b64keydata, sizeof(client->b64keydata), "%s", stringbuf);
3440 if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue);
3441 }
3442 }
3443 }
3444
3445 mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(stringbuf, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse;
3446
3447 #endif APPLE_OSX_mDNSResponder
3448
3449 // Uncomment the line below to view the keys as they're read out of the system keychain
3450 // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
3451 //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf);
3452
3453 // If didn't find desired domain in the list, make a new entry
3454 ptr = FoundInList;
3455 if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
3456 if (!FoundInList)
3457 {
3458 ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
3459 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
3460 }
3461
3462 LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
3463 if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
3464 {
3465 if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
3466 continue;
3467 }
3468
3469 #if APPLE_OSX_mDNSResponder
3470 if (keyChanged && AnonymousRacoonConfig)
3471 {
3472 LogOperation("SetDomainSecrets: secret changed for %##s", &domain);
3473 (void)mDNSConfigureServer(kmDNSUp, stringbuf);
3474 }
3475 #endif APPLE_OSX_mDNSResponder
3476
3477 ConvertDomainNameToCString(&domain, stringbuf);
3478 CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
3479 if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
3480 }
3481 CFRelease(secrets);
3482 }
3483 mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa);
3484 CFRelease(sa);
3485
3486 #if APPLE_OSX_mDNSResponder
3487 {
3488 // clean up ClientTunnels
3489 ClientTunnel **ptr = &m->TunnelClients;
3490 while (*ptr)
3491 {
3492 if ((*ptr)->markedForDeletion)
3493 {
3494 ClientTunnel *cur = *ptr;
3495 LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c);
3496 if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
3497 AutoTunnelSetKeys(cur, mDNSfalse);
3498 *ptr = cur->next;
3499 freeL("ClientTunnel", cur);
3500 }
3501 else
3502 ptr = &(*ptr)->next;
3503 }
3504
3505 DomainAuthInfo *info = m->AuthInfoList;
3506 while (info)
3507 {
3508 if (info->AutoTunnel && info->deltime && info->AutoTunnelNAT.clientContext)
3509 {
3510 // stop the NAT operation
3511 mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
3512 if (info->AutoTunnelNAT.clientCallback)
3513 {
3514 // Reset port and let the AutoTunnelNATCallback handle cleanup
3515 info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
3516 info->AutoTunnelNAT.ExternalPort = zeroIPPort;
3517 info->AutoTunnelNAT.Lifetime = 0;
3518 info->AutoTunnelNAT.Result = mStatus_NoError;
3519 mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
3520 info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
3521 mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
3522 }
3523 info->AutoTunnelNAT.clientContext = mDNSNULL;
3524 }
3525 info = info->next;
3526 }
3527
3528 if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
3529 {
3530 // remove interface if no autotunnel servers and no more client tunnels
3531 LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
3532 m->AutoTunnelHostAddrActive = mDNSfalse;
3533 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
3534 memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b));
3535 }
3536
3537 if (!haveAutoTunnels && AnonymousRacoonConfig)
3538 {
3539 LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
3540 AnonymousRacoonConfig = mDNSfalse;
3541 (void)mDNSConfigureServer(kmDNSDown, "");
3542 }
3543
3544 if (m->AutoTunnelHostAddr.b[0])
3545 if (TunnelClients(m) || TunnelServers(m))
3546 SetupLocalAutoTunnelInterface_internal(m);
3547 }
3548 #endif APPLE_OSX_mDNSResponder
3549
3550 #endif /* NO_SECURITYFRAMEWORK */
3551 }
3552
3553 mDNSlocal void SetLocalDomains(void)
3554 {
3555 CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3556 if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
3557
3558 CFArrayAppendValue(sa, CFSTR("local"));
3559 CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
3560 CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
3561 CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
3562 CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
3563 CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
3564
3565 mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa);
3566 CFRelease(sa);
3567 }
3568
3569 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
3570 {
3571 LogOperation("*** Network Configuration Change *** (%d)%s",
3572 m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
3573 m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
3574 m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
3575 mDNSs32 utc = mDNSPlatformUTC();
3576 MarkAllInterfacesInactive(m, utc);
3577 UpdateInterfaceList(m, utc);
3578 ClearInactiveInterfaces(m, utc);
3579 SetupActiveInterfaces(m, utc);
3580
3581 #if APPLE_OSX_mDNSResponder
3582 {
3583 if (m->AutoTunnelHostAddr.b[0])
3584 {
3585 mDNS_Lock(m);
3586 if (TunnelClients(m) || TunnelServers(m))
3587 SetupLocalAutoTunnelInterface_internal(m);
3588 mDNS_Unlock(m);
3589 }
3590
3591 // Scan to find client tunnels whose questions have completed,
3592 // but whose local inner/outer addresses have changed since the tunnel was set up
3593 ClientTunnel *p;
3594 for (p = m->TunnelClients; p; p = p->next)
3595 if (p->q.ThisQInterval < 0)
3596 {
3597 mDNSAddr tmpSrc = zeroAddr;
3598 mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
3599 tmpDst.ip.v4 = p->rmt_outer;
3600 mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
3601 if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
3602 !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
3603 {
3604 AutoTunnelSetKeys(p, mDNSfalse);
3605 p->loc_inner = m->AutoTunnelHostAddr;
3606 p->loc_outer = tmpSrc.ip.v4;
3607 AutoTunnelSetKeys(p, mDNStrue);
3608 }
3609 }
3610 }
3611 #endif APPLE_OSX_mDNSResponder
3612
3613 uDNS_SetupDNSConfig(m);
3614
3615 if (m->MainCallback)
3616 m->MainCallback(m, mStatus_ConfigChanged);
3617 }
3618
3619 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
3620 {
3621 (void)store; // Parameter not used
3622 (void)changedKeys; // Parameter not used
3623 mDNS *const m = (mDNS *const)context;
3624 KQueueLock(m);
3625 mDNS_Lock(m);
3626
3627 mDNSs32 delay = mDNSPlatformOneSecond; // Start off assuming a one-second delay
3628
3629 int c = CFArrayGetCount(changedKeys); // Count changes
3630 CFRange range = { 0, c };
3631 int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
3632 int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
3633 int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
3634 if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay
3635
3636 #if LogAllOperations
3637 int i;
3638 for (i=0; i<c; i++)
3639 {
3640 char buf[256];
3641 if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
3642 LogOperation("*** NetworkChanged SC key: %s", buf);
3643 }
3644 LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
3645 c, c>1?"s":"",
3646 c1 ? "(Local Hostname) " : "",
3647 c2 ? "(Computer Name) " : "",
3648 c3 ? "(DynamicDNS) " : "",
3649 delay);
3650 #endif
3651
3652 if (!m->p->NetworkChanged ||
3653 m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
3654 m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
3655
3656 // KeyChain frequently fails to notify clients of change events. To work around this
3657 // we set a timer and periodically poll to detect if any changes have occurred.
3658 // Without this Back To My Mac just does't work for a large number of users.
3659 // See <rdar://problem/5124399> Not getting Keychain Changed events when enabling BTMM
3660 if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac))
3661 {
3662 LogOperation("*** NetworkChanged *** starting KeyChainBugTimer");
3663 m->p->KeyChainBugTimer = NonZeroTime(m->timenow + delay);
3664 m->p->KeyChainBugInterval = mDNSPlatformOneSecond;
3665 }
3666
3667 if (!m->SuppressSending ||
3668 m->SuppressSending - m->p->NetworkChanged < 0)
3669 m->SuppressSending = m->p->NetworkChanged;
3670
3671 mDNS_Unlock(m);
3672 KQueueUnlock(m, "NetworkChanged");
3673 }
3674
3675 mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
3676 {
3677 mStatus err = -1;
3678 SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
3679 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
3680 CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3681 CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
3682 CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
3683 CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3684
3685 if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
3686 if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
3687
3688 CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
3689 CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
3690 CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
3691 CFArrayAppendValue(keys, NetworkChangedKey_Computername);
3692 CFArrayAppendValue(keys, NetworkChangedKey_DNS);
3693 CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
3694 CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
3695 CFArrayAppendValue(patterns, pattern1);
3696 CFArrayAppendValue(patterns, pattern2);
3697 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
3698 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
3699 { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
3700
3701 m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
3702 if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
3703
3704 CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
3705 m->p->Store = store;
3706 err = 0;
3707 goto exit;
3708
3709 error:
3710 if (store) CFRelease(store);
3711
3712 exit:
3713 if (patterns) CFRelease(patterns);
3714 if (pattern2) CFRelease(pattern2);
3715 if (pattern1) CFRelease(pattern1);
3716 if (keys) CFRelease(keys);
3717
3718 return(err);
3719 }
3720
3721 #ifndef NO_SECURITYFRAMEWORK
3722 mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
3723 {
3724 LogOperation("*** Keychain Changed ***");
3725 mDNS *const m = (mDNS *const)context;
3726 SecKeychainRef skc;
3727 OSStatus err = SecKeychainCopyDefault(&skc);
3728 if (!err)
3729 {
3730 if (info->keychain == skc)
3731 {
3732 // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
3733 mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
3734 if (!relevant)
3735 {
3736 UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
3737 SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
3738 SecKeychainAttributeList *a = NULL;
3739 err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
3740 if (!err)
3741 {
3742 relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
3743 (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
3744 SecKeychainItemFreeAttributesAndData(a, NULL);
3745 }
3746 }
3747 if (relevant)
3748 {
3749 LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
3750 keychainEvent,
3751 keychainEvent == kSecAddEvent ? "kSecAddEvent" :
3752 keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
3753 keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
3754 // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
3755 KQueueLock(m);
3756 mDNS_Lock(m);
3757 SetDomainSecrets(m);
3758 mDNS_Unlock(m);
3759 KQueueUnlock(m, "KeychainChanged");
3760 }
3761 }
3762 CFRelease(skc);
3763 }
3764
3765 return 0;
3766 }
3767 #endif
3768
3769 #ifndef NO_IOPOWER
3770 mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
3771 {
3772 mDNS *const m = (mDNS *const)refcon;
3773 KQueueLock(m);
3774 (void)service; // Parameter not used
3775 switch(messageType)
3776 {
3777 case kIOMessageCanSystemPowerOff: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
3778 case kIOMessageSystemWillPowerOff: LogOperation("PowerChanged kIOMessageSystemWillPowerOff");
3779 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000250
3780 case kIOMessageSystemWillNotPowerOff: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
3781 case kIOMessageCanSystemSleep: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
3782 case kIOMessageSystemWillSleep: LogOperation("PowerChanged kIOMessageSystemWillSleep");
3783 mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000280
3784 case kIOMessageSystemWillNotSleep: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
3785 case kIOMessageSystemHasPoweredOn: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn");
3786 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
3787 if (m->SleepState) mDNSCoreMachineSleep(m, false);
3788 // Just to be safe, also make sure our interface list is fully up to date, in case we
3789 // haven't yet received the System Configuration Framework "network changed" event that
3790 // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message
3791 mDNSMacOSXNetworkChanged(m); break; // E0000300
3792 case kIOMessageSystemWillRestart: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
3793 case kIOMessageSystemWillPowerOn: LogOperation("PowerChanged kIOMessageSystemWillPowerOn");
3794 // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
3795 mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; // E0000320
3796 default: LogOperation("PowerChanged unknown message %X", messageType); break;
3797 }
3798 IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
3799 KQueueUnlock(m, "Sleep/Wake");
3800 }
3801 #endif /* NO_IOPOWER */
3802
3803 #if COMPILER_LIKES_PRAGMA_MARK
3804 #pragma mark -
3805 #pragma mark - Initialization & Teardown
3806 #endif
3807
3808 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
3809 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
3810 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
3811 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
3812
3813 // Major version 6 is 10.2.x (Jaguar)
3814 // Major version 7 is 10.3.x (Panther)
3815 // Major version 8 is 10.4.x (Tiger)
3816 mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
3817 {
3818 int major = 0, minor = 0;
3819 char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
3820 CFDictionaryRef vers = _CFCopySystemVersionDictionary();
3821 if (vers)
3822 {
3823 CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
3824 CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
3825 CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
3826 if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
3827 if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
3828 if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
3829 sscanf(buildver, "%d%c%d", &major, &letter, &minor);
3830 CFRelease(vers);
3831 }
3832 if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
3833 if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
3834 return(major);
3835 }
3836
3837 // Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
3838 // If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
3839 // we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
3840 mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
3841 {
3842 int err = -1;
3843 int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
3844 if (s < 3)
3845 LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
3846 else
3847 {
3848 struct sockaddr_in s5353;
3849 s5353.sin_family = AF_INET;
3850 s5353.sin_port = MulticastDNSPort.NotAnInteger;
3851 s5353.sin_addr.s_addr = 0;
3852 err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
3853 close(s);
3854 }
3855
3856 if (err) LogMsg("No unicast UDP responses");
3857 else debugf("Unicast UDP responses okay");
3858 return(err == 0);
3859 }
3860
3861 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
3862 // 1) query for b._dns-sd._udp.local on LocalOnly interface
3863 // (.local manually generated via explicit callback)
3864 // 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
3865 // 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
3866 // 4) result above should generate a callback from question in (1). result added to global list
3867 // 5) global list delivered to client via GetSearchDomainList()
3868 // 6) client calls to enumerate domains now go over LocalOnly interface
3869 // (!!!KRS may add outgoing interface in addition)
3870
3871 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
3872 {
3873 mStatus err;
3874
3875 // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
3876 // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
3877 int i;
3878 for (i=0; i<100; i++)
3879 {
3880 domainlabel testlabel;
3881 testlabel.c[0] = 0;
3882 GetUserSpecifiedLocalHostName(&testlabel);
3883 if (testlabel.c[0]) break;
3884 usleep(50000);
3885 }
3886
3887 m->hostlabel.c[0] = 0;
3888
3889 char *HINFO_HWstring = "Macintosh";
3890 char HINFO_HWstring_buffer[256];
3891 int get_model[2] = { CTL_HW, HW_MODEL };
3892 size_t len_model = sizeof(HINFO_HWstring_buffer);
3893 if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
3894 HINFO_HWstring = HINFO_HWstring_buffer;
3895
3896 char HINFO_SWstring[256] = "";
3897 if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
3898 if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
3899
3900 mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
3901 mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
3902 if (hlen + slen < 254)
3903 {
3904 m->HIHardware.c[0] = hlen;
3905 m->HISoftware.c[0] = slen;
3906 mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
3907 mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
3908 }
3909
3910 m->p->permanentsockets.m = m;
3911 m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
3912 m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
3913 m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
3914 m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
3915
3916 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET);
3917 #ifndef NO_IPV6
3918 err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6);
3919 #endif
3920
3921 struct sockaddr_in s4;
3922 socklen_t n4 = sizeof(s4);
3923 if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
3924 else m->UnicastPort4.NotAnInteger = s4.sin_port;
3925 #ifndef NO_IPV6
3926 if (m->p->permanentsockets.sktv6 >= 0)
3927 {
3928 struct sockaddr_in6 s6;
3929 socklen_t n6 = sizeof(s6);
3930 if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
3931 else m->UnicastPort6.NotAnInteger = s6.sin6_port;
3932 }
3933 #endif
3934
3935 m->p->InterfaceList = mDNSNULL;
3936 m->p->userhostlabel.c[0] = 0;
3937 m->p->usernicelabel.c[0] = 0;
3938 m->p->NotifyUser = 0;
3939 m->p->KeyChainBugTimer = 0;
3940
3941 m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
3942
3943 mDNSs32 utc = mDNSPlatformUTC();
3944 UpdateInterfaceList(m, utc);
3945 SetupActiveInterfaces(m, utc);
3946
3947 NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
3948 NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
3949 NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
3950 NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
3951 NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
3952 if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
3953 { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
3954
3955 err = WatchForNetworkChanges(m);
3956 if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
3957
3958 // Explicitly ensure that our Keychain operations utilize the system domain.
3959 #ifndef NO_SECURITYFRAMEWORK
3960 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
3961 #endif
3962
3963 mDNS_Lock(m);
3964 SetDomainSecrets(m);
3965 SetLocalDomains();
3966 mDNS_Unlock(m);
3967
3968 #ifndef NO_SECURITYFRAMEWORK
3969 err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
3970 if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
3971 #endif
3972
3973 #ifndef NO_IOPOWER
3974 m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
3975 if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
3976 else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
3977 #endif /* NO_IOPOWER */
3978
3979 return(mStatus_NoError);
3980 }
3981
3982 mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
3983 {
3984 #if MDNS_NO_DNSINFO
3985 LogMsg("Note: Compiled without Apple-specific Split-DNS support");
3986 #endif
3987
3988 mStatus result = mDNSPlatformInit_setup(m);
3989
3990 // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
3991 // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
3992 if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
3993 return(result);
3994 }
3995
3996 mDNSexport void mDNSPlatformClose(mDNS *const m)
3997 {
3998 if (m->p->PowerConnection)
3999 {
4000 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
4001 #ifndef NO_IOPOWER
4002 // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
4003 // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
4004 IODeregisterForSystemPower(&m->p->PowerNotifier);
4005 IOServiceClose ( m->p->PowerConnection);
4006 IONotificationPortDestroy ( m->p->PowerPortRef);
4007 #endif /* NO_IOPOWER */
4008 m->p->PowerConnection = 0;
4009 }
4010
4011 if (m->p->Store)
4012 {
4013 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
4014 CFRunLoopSourceInvalidate(m->p->StoreRLS);
4015 CFRelease(m->p->StoreRLS);
4016 CFRelease(m->p->Store);
4017 m->p->Store = NULL;
4018 m->p->StoreRLS = NULL;
4019 }
4020
4021 mDNSs32 utc = mDNSPlatformUTC();
4022 MarkAllInterfacesInactive(m, utc);
4023 ClearInactiveInterfaces(m, utc);
4024 CloseSocketSet(&m->p->permanentsockets);
4025
4026 #if APPLE_OSX_mDNSResponder
4027 if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
4028 {
4029 m->AutoTunnelHostAddrActive = mDNSfalse;
4030 LogMsg("Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
4031 (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
4032 }
4033 #endif // APPLE_OSX_mDNSResponder
4034 }
4035
4036 #if COMPILER_LIKES_PRAGMA_MARK
4037 #pragma mark -
4038 #pragma mark - General Platform Support Layer functions
4039 #endif
4040
4041 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
4042 {
4043 return(mach_absolute_time());
4044 }
4045
4046 mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
4047
4048 mDNSexport mStatus mDNSPlatformTimeInit(void)
4049 {
4050 // Notes: Typical values for mach_timebase_info:
4051 // tbi.numer = 1000 million
4052 // tbi.denom = 33 million
4053 // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
4054 // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
4055 // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
4056 // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
4057 // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
4058 //
4059 // Arithmetic notes:
4060 // tbi.denom is at least 1, and not more than 2^32-1.
4061 // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
4062 // tbi.denom is at least 1, and not more than 2^32-1.
4063 // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
4064 // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
4065 // which is unlikely on any current or future Macintosh.
4066 // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
4067 // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
4068 struct mach_timebase_info tbi;
4069 kern_return_t result = mach_timebase_info(&tbi);
4070 if (result == KERN_SUCCESS) clockdivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
4071 return(result);
4072 }
4073
4074 mDNSexport mDNSs32 mDNSPlatformRawTime(void)
4075 {
4076 if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
4077
4078 static uint64_t last_mach_absolute_time = 0;
4079 //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
4080 uint64_t this_mach_absolute_time = mach_absolute_time();
4081 if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
4082 {
4083 LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
4084 LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
4085 // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
4086 last_mach_absolute_time = this_mach_absolute_time;
4087 // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
4088 // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
4089 if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
4090 NotifyOfElusiveBug("mach_absolute_time went backwards!",
4091 "This error occurs from time to time, often on newly released hardware, "
4092 "and usually the exact cause is different in each instance.\r\r"
4093 "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
4094 "and assign it to Radar Component “Kernel” Version “X”.");
4095 }
4096 last_mach_absolute_time = this_mach_absolute_time;
4097
4098 return((mDNSs32)(this_mach_absolute_time / clockdivisor));
4099 }
4100
4101 mDNSexport mDNSs32 mDNSPlatformUTC(void)
4102 {
4103 return time(NULL);
4104 }
4105
4106 // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
4107 mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
4108 mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
4109 mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
4110 mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
4111 mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
4112 mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
4113 mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
4114 #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
4115 mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
4116 #endif
4117 mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }