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